@@ -280,26 +280,6 @@ static void socket_dtor(ErlNifEnv *caller_env, void *obj)
280
280
#endif
281
281
}
282
282
283
- #if OTP_SOCKET_BSD
284
- static void socket_stop (ErlNifEnv * caller_env , void * obj , ErlNifEvent event , int is_direct_call )
285
- {
286
- UNUSED (caller_env );
287
- UNUSED (event );
288
- UNUSED (is_direct_call );
289
-
290
- struct SocketResource * rsrc_obj = (struct SocketResource * ) obj ;
291
-
292
- if (rsrc_obj -> selecting_process_id != INVALID_PROCESS_ID ) {
293
- enif_demonitor_process (caller_env , rsrc_obj , & rsrc_obj -> selecting_process_monitor );
294
- rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
295
- struct RefcBinary * rsrc_refc = refc_binary_from_data (rsrc_obj );
296
- refc_binary_decrement_refcount (rsrc_refc , caller_env -> global );
297
- }
298
-
299
- TRACE ("socket_stop called on fd=%i\n" , rsrc_obj -> fd );
300
- }
301
- #endif
302
-
303
283
static void socket_down (ErlNifEnv * caller_env , void * obj , ErlNifPid * pid , ErlNifMonitor * mon )
304
284
{
305
285
UNUSED (caller_env );
@@ -314,24 +294,20 @@ static void socket_down(ErlNifEnv *caller_env, void *obj, ErlNifPid *pid, ErlNif
314
294
TRACE ("socket_down called on process_id=%i\n" , (int ) * pid );
315
295
#endif
316
296
317
- struct RefcBinary * rsrc_refc = refc_binary_from_data (rsrc_obj );
318
297
SMP_RWLOCK_WRLOCK (rsrc_obj -> socket_lock );
319
298
320
299
if (rsrc_obj -> selecting_process_id == INVALID_PROCESS_ID ) {
321
300
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
322
301
return ;
323
302
}
303
+ rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
324
304
325
305
#if OTP_SOCKET_BSD
326
- // Monitor fired, so make sure we don't try to demonitor in select_stop
327
- // as it could crash trying to reacquire lock on process table
328
- // enif_select can decrement ref count but it's at least 2 in this case (1 for monitor and 1 for select)
329
- rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
306
+ // enif_select can decrement ref count but it's at least 2 here (1 for monitor and 1 for select)
330
307
enif_select (caller_env , rsrc_obj -> fd , ERL_NIF_SELECT_STOP , rsrc_obj , NULL , term_nil ());
331
308
#elif OTP_SOCKET_LWIP
332
309
// Monitor can be called when we're selecting, accepting or connecting.
333
310
LWIP_BEGIN ();
334
- rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
335
311
if (rsrc_obj -> socket_state & SocketStateTCP ) {
336
312
if (rsrc_obj -> socket_state & SocketStateTCPListening ) {
337
313
(void ) tcp_close (rsrc_obj -> tcp_pcb );
@@ -347,21 +323,13 @@ static void socket_down(ErlNifEnv *caller_env, void *obj, ErlNifPid *pid, ErlNif
347
323
}
348
324
LWIP_END ();
349
325
#endif
350
-
351
326
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
352
-
353
- // We're no longer monitoring so we can decrement ref count
354
- refc_binary_decrement_refcount (rsrc_refc , caller_env -> global );
355
327
}
356
328
357
329
static const ErlNifResourceTypeInit SocketResourceTypeInit = {
358
330
.members = 3 ,
359
331
.dtor = socket_dtor ,
360
- #if OTP_SOCKET_BSD
361
- .stop = socket_stop ,
362
- #else
363
332
.stop = NULL ,
364
- #endif
365
333
.down = socket_down ,
366
334
};
367
335
@@ -734,8 +702,11 @@ static term nif_socket_close(Context *ctx, int argc, term argv[])
734
702
735
703
// So we handle closing a socket while another process is selecting
736
704
if (rsrc_obj -> selecting_process_id != INVALID_PROCESS_ID ) {
737
- // Save process id as socket_stop may be called by enif_select.
738
- int32_t selecting_process_id = rsrc_obj -> selecting_process_id ;
705
+ // Another process is selecting, therefore ref_count >= 3
706
+ // 1. this caller's context heap (parameter to close)
707
+ // 2. select
708
+ // 3. monitor
709
+
739
710
// Stop selecting.
740
711
int stop_res = enif_select (erl_nif_env_from_context (ctx ), rsrc_obj -> fd , ERL_NIF_SELECT_STOP , rsrc_obj , NULL , term_nil ());
741
712
if (UNLIKELY (stop_res < 0 )) {
@@ -749,13 +720,19 @@ static term nif_socket_close(Context *ctx, int argc, term argv[])
749
720
// When using asynchronous API, the selecting process can be the
750
721
// calling process. In this case we don't send any notification.
751
722
//
752
- if (selecting_process_id != ctx -> process_id ) {
723
+ if (rsrc_obj -> selecting_process_id != ctx -> process_id ) {
753
724
// send a {'$socket', Socket, abort, {Ref | undefined, closed}} message to the pid
754
- if (UNLIKELY (send_closed_notification (ctx , argv [0 ], selecting_process_id , rsrc_obj ) < 0 )) {
725
+ if (UNLIKELY (send_closed_notification (ctx , argv [0 ], rsrc_obj -> selecting_process_id , rsrc_obj ) < 0 )) {
755
726
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
756
727
RAISE_ERROR (OUT_OF_MEMORY_ATOM );
757
728
}
758
729
}
730
+
731
+ // Stop monitor
732
+ enif_demonitor_process (erl_nif_env_from_context (ctx ), rsrc_obj , & rsrc_obj -> selecting_process_monitor );
733
+ rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
734
+
735
+ // Now, ref_count >= 1 only.
759
736
}
760
737
761
738
// Eventually close the socket
@@ -1000,16 +977,13 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
1000
977
RAISE_ERROR (BADARG_ATOM );
1001
978
}
1002
979
1003
- struct RefcBinary * rsrc_refc = refc_binary_from_data (rsrc_obj );
1004
980
SMP_RWLOCK_WRLOCK (rsrc_obj -> socket_lock );
1005
981
1006
982
ErlNifEnv * env = erl_nif_env_from_context (ctx );
1007
983
if (rsrc_obj -> selecting_process_id != ctx -> process_id && rsrc_obj -> selecting_process_id != INVALID_PROCESS_ID ) {
1008
984
// demonitor can fail if process is gone.
1009
985
enif_demonitor_process (env , rsrc_obj , & rsrc_obj -> selecting_process_monitor );
1010
986
rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
1011
- // decrement ref count as we are demonitoring
1012
- refc_binary_decrement_refcount (rsrc_refc , ctx -> global );
1013
987
}
1014
988
// Monitor first as select is less likely to fail and it's less expensive to demonitor
1015
989
// if select fails than to stop select if monitor fails
@@ -1018,8 +992,6 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
1018
992
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1019
993
RAISE_ERROR (NOPROC_ATOM );
1020
994
}
1021
- // increment ref count so the resource doesn't go away until monitor is fired
1022
- refc_binary_increment_refcount (rsrc_refc );
1023
995
rsrc_obj -> selecting_process_id = ctx -> process_id ;
1024
996
}
1025
997
@@ -1042,7 +1014,6 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
1042
1014
enif_demonitor_process (env , rsrc_obj , & rsrc_obj -> selecting_process_monitor );
1043
1015
rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
1044
1016
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1045
- refc_binary_decrement_refcount (rsrc_refc , ctx -> global );
1046
1017
RAISE_ERROR (BADARG_ATOM );
1047
1018
}
1048
1019
}
@@ -1087,9 +1058,9 @@ static term nif_socket_select_read(Context *ctx, int argc, term argv[])
1087
1058
break ;
1088
1059
default :
1089
1060
enif_demonitor_process (env , rsrc_obj , & rsrc_obj -> selecting_process_monitor );
1061
+ rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
1090
1062
LWIP_END ();
1091
1063
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1092
- refc_binary_decrement_refcount (rsrc_refc , ctx -> global );
1093
1064
RAISE_ERROR (BADARG_ATOM );
1094
1065
}
1095
1066
LWIP_END ();
@@ -1115,11 +1086,10 @@ static term nif_socket_select_stop(Context *ctx, int argc, term argv[])
1115
1086
if (rsrc_obj -> selecting_process_id != INVALID_PROCESS_ID ) {
1116
1087
enif_demonitor_process (erl_nif_env_from_context (ctx ), rsrc_obj , & rsrc_obj -> selecting_process_monitor );
1117
1088
rsrc_obj -> selecting_process_id = INVALID_PROCESS_ID ;
1118
- struct RefcBinary * rsrc_refc = refc_binary_from_data (rsrc_obj );
1119
- refc_binary_decrement_refcount (rsrc_refc , ctx -> global );
1120
1089
}
1121
1090
#if OTP_SOCKET_BSD
1122
1091
if (UNLIKELY (enif_select (erl_nif_env_from_context (ctx ), rsrc_obj -> fd , ERL_NIF_SELECT_STOP , rsrc_obj , NULL , term_nil ()) < 0 )) {
1092
+ SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1123
1093
RAISE_ERROR (BADARG_ATOM );
1124
1094
}
1125
1095
#elif OTP_SOCKET_LWIP
@@ -1759,8 +1729,10 @@ static term nif_socket_accept(Context *ctx, int argc, term argv[])
1759
1729
int fd = accept (rsrc_obj -> fd , (struct sockaddr * ) & clientaddr , & clientlen );
1760
1730
SMP_RWLOCK_UNLOCK (rsrc_obj -> socket_lock );
1761
1731
if (UNLIKELY (fd == -1 || fd == CLOSED_FD )) {
1762
- AVM_LOGE (TAG , "Unable to accept on socket %i." , rsrc_obj -> fd );
1763
1732
int err = errno ;
1733
+ if (err != EAGAIN ) {
1734
+ AVM_LOGI (TAG , "Unable to accept on socket %i. errno=%i" , rsrc_obj -> fd , (int ) err );
1735
+ }
1764
1736
term reason = (err == ECONNABORTED ) ? CLOSED_ATOM : posix_errno_to_term (err , global );
1765
1737
return make_error_tuple (reason , ctx );
1766
1738
} else {
0 commit comments