70
70
OPERATION_ALIAS_SEND_TT = 34 ,
71
71
};
72
72
73
+ enum
74
+ {
75
+ SPAWN_REPLY_FLAGS_LINK_CREATED = 1 ,
76
+ SPAWN_REPLY_FLAGS_MONITOR_CREATED = 2 ,
77
+ };
78
+
73
79
struct DistributionPacket
74
80
{
75
81
struct ListHead head ;
@@ -129,7 +135,7 @@ static void dist_connection_dtor(ErlNifEnv *caller_env, void *obj)
129
135
130
136
static void dist_enqueue_message (term control_message , term payload , struct DistConnection * connection , GlobalContext * global )
131
137
{
132
- size_t control_message_size = 0 ; // some compilers including esp-idf 5.0.7 is not smart enough
138
+ size_t control_message_size = 0 ; // some compilers including esp-idf 5.0.7 are not smart enough
133
139
enum ExternalTermResult serialize_result = externalterm_compute_external_size (control_message , & control_message_size , global );
134
140
if (LIKELY (serialize_result == EXTERNAL_TERM_OK )) {
135
141
size_t payload_size = 0 ;
@@ -195,10 +201,7 @@ static void dist_connection_down(ErlNifEnv *caller_env, void *obj, ErlNifPid *pi
195
201
196
202
struct DistConnection * conn_obj = (struct DistConnection * ) obj ;
197
203
198
- if (UNLIKELY (enif_compare_monitors (& conn_obj -> connection_process_monitor , mon ) == 0 )) {
199
- struct RefcBinary * rsrc_refc = refc_binary_from_data (obj );
200
- refc_binary_decrement_refcount (rsrc_refc , caller_env -> global );
201
- } else {
204
+ if (enif_compare_monitors (& conn_obj -> connection_process_monitor , mon ) != 0 ) {
202
205
struct ListHead * remote_monitors = synclist_wrlock (& conn_obj -> remote_monitors );
203
206
struct ListHead * item ;
204
207
LIST_FOR_EACH (item , remote_monitors ) {
@@ -280,10 +283,6 @@ static term nif_erlang_setnode_3(Context *ctx, int argc, term argv[])
280
283
list_prepend (dist_connections , & conn_obj -> head );
281
284
synclist_unlock (& ctx -> global -> dist_connections );
282
285
283
- // Increment reference count as the resource should be alive until controller process dies
284
- struct RefcBinary * rsrc_refc = refc_binary_from_data (conn_obj );
285
- refc_binary_increment_refcount (rsrc_refc );
286
-
287
286
if (UNLIKELY (memory_ensure_free_opt (ctx , TERM_BOXED_RESOURCE_SIZE , MEMORY_CAN_SHRINK ) != MEMORY_GC_OK )) {
288
287
RAISE_ERROR (OUT_OF_MEMORY_ATOM );
289
288
}
@@ -339,6 +338,38 @@ static term nif_erlang_dist_ctrl_get_data(Context *ctx, int argc, term argv[])
339
338
return result ;
340
339
}
341
340
341
+ term dist_monitor (struct DistConnection * conn_obj , term from_pid , term target_proc , term monitor_ref , Context * ctx )
342
+ {
343
+ if (term_is_atom (target_proc )) {
344
+ target_proc = globalcontext_get_registered_process (ctx -> global , term_to_atom_index (target_proc ));
345
+ }
346
+ int target_process_id = 0 ;
347
+ if (term_is_local_pid (target_proc )) {
348
+ target_process_id = term_to_local_process_id (target_proc );
349
+ } else {
350
+ RAISE_ERROR (BADARG_ATOM );
351
+ }
352
+ struct RemoteMonitor * monitor = malloc (sizeof (struct RemoteMonitor ));
353
+ monitor -> target_proc = target_proc ;
354
+ monitor -> pid_number = term_get_external_pid_process_id (from_pid );
355
+ monitor -> pid_serial = term_get_external_pid_serial (from_pid );
356
+ monitor -> ref_len = term_get_external_reference_len (monitor_ref );
357
+ memcpy (monitor -> ref_words , term_get_external_reference_words (monitor_ref ), sizeof (uint32_t ) * monitor -> ref_len );
358
+ if (target_process_id ) {
359
+ synclist_append (& conn_obj -> remote_monitors , & monitor -> head );
360
+ ErlNifPid target_process_pid = target_process_id ;
361
+ if (UNLIKELY (enif_monitor_process (erl_nif_env_from_context (ctx ), conn_obj , & target_process_pid , & monitor -> process_monitor ) != 0 )) {
362
+ synclist_remove (& conn_obj -> remote_monitors , & monitor -> head );
363
+ dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
364
+ free (monitor );
365
+ }
366
+ } else {
367
+ dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
368
+ free (monitor );
369
+ }
370
+ return OK_ATOM ;
371
+ }
372
+
342
373
static term nif_erlang_dist_ctrl_put_data (Context * ctx , int argc , term argv [])
343
374
{
344
375
UNUSED (argc );
@@ -390,32 +421,8 @@ static term nif_erlang_dist_ctrl_put_data(Context *ctx, int argc, term argv[])
390
421
term from_pid = term_get_tuple_element (control , 1 );
391
422
term target_proc = term_get_tuple_element (control , 2 );
392
423
term monitor_ref = term_get_tuple_element (control , 3 );
393
- if (term_is_atom (target_proc )) {
394
- target_proc = globalcontext_get_registered_process (ctx -> global , term_to_atom_index (target_proc ));
395
- }
396
- int target_process_id = 0 ;
397
- if (term_is_local_pid (target_proc )) {
398
- target_process_id = term_to_local_process_id (target_proc );
399
- } else {
400
- RAISE_ERROR (BADARG_ATOM );
401
- }
402
- struct RemoteMonitor * monitor = malloc (sizeof (struct RemoteMonitor ));
403
- monitor -> target_proc = target_proc ;
404
- monitor -> pid_number = term_get_external_pid_process_id (from_pid );
405
- monitor -> pid_serial = term_get_external_pid_serial (from_pid );
406
- monitor -> ref_len = term_get_external_reference_len (monitor_ref );
407
- memcpy (monitor -> ref_words , term_get_external_reference_words (monitor_ref ), sizeof (uint32_t ) * monitor -> ref_len );
408
- if (target_process_id ) {
409
- synclist_append (& conn_obj -> remote_monitors , & monitor -> head );
410
- ErlNifPid target_process_pid = target_process_id ;
411
- if (UNLIKELY (enif_monitor_process (erl_nif_env_from_context (ctx ), conn_obj , & target_process_pid , & monitor -> process_monitor ) != 0 )) {
412
- synclist_remove (& conn_obj -> remote_monitors , & monitor -> head );
413
- dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
414
- free (monitor );
415
- }
416
- } else {
417
- dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
418
- free (monitor );
424
+ if (UNLIKELY (term_is_invalid_term (dist_monitor (conn_obj , from_pid , target_proc , monitor_ref , ctx )))) {
425
+ return term_invalid_term ();
419
426
}
420
427
421
428
break ;
@@ -443,6 +450,54 @@ static term nif_erlang_dist_ctrl_put_data(Context *ctx, int argc, term argv[])
443
450
synclist_unlock (& conn_obj -> remote_monitors );
444
451
break ;
445
452
}
453
+ case OPERATION_SPAWN_REQUEST : {
454
+ if (UNLIKELY (arity != 6 )) {
455
+ RAISE_ERROR (BADARG_ATOM );
456
+ }
457
+ term roots [4 ];
458
+ roots [0 ] = argv [0 ];
459
+ roots [1 ] = argv [1 ];
460
+ roots [2 ] = control ;
461
+ roots [3 ] = externalterm_to_term_with_roots (data + 1 + bytes_read , binary_len - 1 - bytes_read , ctx , ExternalTermCopy , & bytes_read , 3 , roots );
462
+ if (UNLIKELY (memory_ensure_free_with_roots (ctx , LIST_SIZE (1 , TUPLE_SIZE (2 ) + TUPLE_SIZE (4 )), 4 , roots , MEMORY_CAN_SHRINK ) != MEMORY_GC_OK )) {
463
+ RAISE_ERROR (OUT_OF_MEMORY_ATOM );
464
+ }
465
+ control = roots [2 ];
466
+ term arglist = roots [3 ];
467
+ term mfa = term_get_tuple_element (control , 4 );
468
+ if (UNLIKELY (!term_is_tuple (mfa ) || term_get_tuple_arity (mfa ) != 3 )) {
469
+ RAISE_ERROR (BADARG_ATOM );
470
+ }
471
+ if (UNLIKELY (!term_is_list (arglist ))) {
472
+ RAISE_ERROR (BADARG_ATOM );
473
+ }
474
+ term reqid = term_get_tuple_element (control , 1 );
475
+ term from = term_get_tuple_element (control , 2 );
476
+ if (UNLIKELY (!term_is_pid (from ))) {
477
+ RAISE_ERROR (BADARG_ATOM );
478
+ }
479
+ // term groupleader = term_get_tuple_element(control, 3);
480
+ // TODO: handle groupleader which is an externalpid
481
+ term options = term_get_tuple_element (control , 5 );
482
+
483
+ term request_tuple = term_alloc_tuple (4 , & ctx -> heap );
484
+ term_put_tuple_element (request_tuple , 0 , roots [0 ]);
485
+ term_put_tuple_element (request_tuple , 1 , reqid );
486
+ term_put_tuple_element (request_tuple , 2 , from );
487
+ term_put_tuple_element (request_tuple , 3 , options );
488
+ term request_opt = term_alloc_tuple (2 , & ctx -> heap );
489
+ term_put_tuple_element (request_opt , 0 , REQUEST_ATOM );
490
+ term_put_tuple_element (request_opt , 1 , request_tuple );
491
+ term spawn_opts = term_list_prepend (request_opt , term_nil (), & ctx -> heap );
492
+
493
+ // reuse roots for args
494
+ roots [0 ] = term_get_tuple_element (mfa , 0 );
495
+ roots [1 ] = term_get_tuple_element (mfa , 1 );
496
+ roots [2 ] = arglist ;
497
+ roots [3 ] = spawn_opts ;
498
+ nif_erlang_spawn_opt (ctx , 4 , roots );
499
+ break ;
500
+ }
446
501
default :
447
502
printf ("Unknown distribution protocol operation id %d\n" , (int ) term_to_int (operation ));
448
503
RAISE_ERROR (BADARG_ATOM );
@@ -468,6 +523,23 @@ void dist_send_message(term external_pid, term payload, Context *ctx)
468
523
synclist_unlock (& ctx -> global -> dist_connections );
469
524
}
470
525
526
+ void dist_spawn_reply (term req_id , term to_pid , bool link , bool monitor , term result , struct DistConnection * connection , GlobalContext * global )
527
+ {
528
+ int flags = (link ? SPAWN_REPLY_FLAGS_LINK_CREATED : 0 )
529
+ | (monitor ? SPAWN_REPLY_FLAGS_MONITOR_CREATED : 0 );
530
+ // allocate tuple
531
+ BEGIN_WITH_STACK_HEAP (TUPLE_SIZE (5 ), heap )
532
+ term control_message = term_alloc_tuple (5 , & heap );
533
+ term_put_tuple_element (control_message , 0 , term_from_int (OPERATION_SPAWN_REPLY ));
534
+ term_put_tuple_element (control_message , 1 , req_id );
535
+ term_put_tuple_element (control_message , 2 , to_pid );
536
+ term_put_tuple_element (control_message , 3 , term_from_int (flags ));
537
+ term_put_tuple_element (control_message , 4 , result );
538
+
539
+ dist_enqueue_message (control_message , term_invalid_term (), connection , global );
540
+ END_WITH_STACK_HEAP (heap , global )
541
+ }
542
+
471
543
const struct Nif setnode_3_nif = {
472
544
.base .type = NIFFunctionType ,
473
545
.nif_ptr = nif_erlang_setnode_3
0 commit comments