7070 OPERATION_ALIAS_SEND_TT = 34 ,
7171};
7272
73+ enum
74+ {
75+ SPAWN_REPLY_FLAGS_LINK_CREATED = 1 ,
76+ SPAWN_REPLY_FLAGS_MONITOR_CREATED = 2 ,
77+ };
78+
7379struct DistributionPacket
7480{
7581 struct ListHead head ;
@@ -339,6 +345,37 @@ static term nif_erlang_dist_ctrl_get_data(Context *ctx, int argc, term argv[])
339345 return result ;
340346}
341347
348+ term dist_monitor (struct DistConnection * conn_obj , term from_pid , term target_proc , term monitor_ref , Context * ctx )
349+ {
350+ int target_process_id = 0 ;
351+ if (term_is_local_pid (target_proc )) {
352+ target_process_id = term_to_local_process_id (target_proc );
353+ } else if (term_is_atom (target_proc )) {
354+ target_process_id = globalcontext_get_registered_process (ctx -> global , term_to_atom_index (target_proc ));
355+ } else {
356+ RAISE_ERROR (BADARG_ATOM );
357+ }
358+ struct RemoteMonitor * monitor = malloc (sizeof (struct RemoteMonitor ));
359+ monitor -> target_proc = target_proc ;
360+ monitor -> pid_number = term_get_external_pid_process_id (from_pid );
361+ monitor -> pid_serial = term_get_external_pid_serial (from_pid );
362+ monitor -> ref_len = term_get_external_reference_len (monitor_ref );
363+ memcpy (monitor -> ref_words , term_get_external_reference_words (monitor_ref ), sizeof (uint32_t ) * monitor -> ref_len );
364+ if (target_process_id ) {
365+ synclist_append (& conn_obj -> remote_monitors , & monitor -> head );
366+ ErlNifPid target_process_pid = target_process_id ;
367+ if (UNLIKELY (enif_monitor_process (erl_nif_env_from_context (ctx ), conn_obj , & target_process_pid , & monitor -> process_monitor ) != 0 )) {
368+ synclist_remove (& conn_obj -> remote_monitors , & monitor -> head );
369+ dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
370+ free (monitor );
371+ }
372+ } else {
373+ dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
374+ free (monitor );
375+ }
376+ return OK_ATOM ;
377+ }
378+
342379static term nif_erlang_dist_ctrl_put_data (Context * ctx , int argc , term argv [])
343380{
344381 UNUSED (argc );
@@ -390,32 +427,7 @@ static term nif_erlang_dist_ctrl_put_data(Context *ctx, int argc, term argv[])
390427 term from_pid = term_get_tuple_element (control , 1 );
391428 term target_proc = term_get_tuple_element (control , 2 );
392429 term monitor_ref = term_get_tuple_element (control , 3 );
393- int target_process_id = 0 ;
394- if (term_is_local_pid (target_proc )) {
395- target_process_id = term_to_local_process_id (target_proc );
396- } else if (term_is_atom (target_proc )) {
397- target_process_id = globalcontext_get_registered_process (ctx -> global , term_to_atom_index (target_proc ));
398- } else {
399- RAISE_ERROR (BADARG_ATOM );
400- }
401- struct RemoteMonitor * monitor = malloc (sizeof (struct RemoteMonitor ));
402- monitor -> target_proc = target_proc ;
403- monitor -> pid_number = term_get_external_pid_process_id (from_pid );
404- monitor -> pid_serial = term_get_external_pid_serial (from_pid );
405- monitor -> ref_len = term_get_external_reference_len (monitor_ref );
406- memcpy (monitor -> ref_words , term_get_external_reference_words (monitor_ref ), sizeof (uint32_t ) * monitor -> ref_len );
407- if (target_process_id ) {
408- synclist_append (& conn_obj -> remote_monitors , & monitor -> head );
409- ErlNifPid target_process_pid = target_process_id ;
410- if (UNLIKELY (enif_monitor_process (erl_nif_env_from_context (ctx ), conn_obj , & target_process_pid , & monitor -> process_monitor ) != 0 )) {
411- synclist_remove (& conn_obj -> remote_monitors , & monitor -> head );
412- dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
413- free (monitor );
414- }
415- } else {
416- dist_enqueue_monitor_exit_message (monitor , NOPROC_ATOM , conn_obj , ctx -> global );
417- free (monitor );
418- }
430+ dist_monitor (conn_obj , from_pid , target_proc , monitor_ref , ctx );
419431
420432 break ;
421433 }
@@ -442,6 +454,53 @@ static term nif_erlang_dist_ctrl_put_data(Context *ctx, int argc, term argv[])
442454 synclist_unlock (& conn_obj -> remote_monitors );
443455 break ;
444456 }
457+ case OPERATION_SPAWN_REQUEST : {
458+ if (UNLIKELY (arity != 6 )) {
459+ RAISE_ERROR (BADARG_ATOM );
460+ }
461+ term roots [4 ];
462+ roots [0 ] = argv [0 ];
463+ roots [1 ] = argv [1 ];
464+ roots [2 ] = control ;
465+ roots [3 ] = externalterm_to_term_with_roots (data + 1 + bytes_read , binary_len - 1 - bytes_read , ctx , ExternalTermCopy , & bytes_read , 3 , roots );
466+ 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 )) {
467+ RAISE_ERROR (OUT_OF_MEMORY_ATOM );
468+ }
469+ control = roots [2 ];
470+ term arglist = roots [3 ];
471+ term mfa = term_get_tuple_element (control , 4 );
472+ if (UNLIKELY (!term_is_tuple (mfa ) || term_get_tuple_arity (mfa ) != 3 )) {
473+ RAISE_ERROR (BADARG_ATOM );
474+ }
475+ if (UNLIKELY (!term_is_list (arglist ))) {
476+ RAISE_ERROR (BADARG_ATOM );
477+ }
478+ term reqid = term_get_tuple_element (control , 1 );
479+ term from = term_get_tuple_element (control , 2 );
480+ if (UNLIKELY (!term_is_pid (from ))) {
481+ RAISE_ERROR (BADARG_ATOM );
482+ }
483+ // term groupleader = term_get_tuple_element(control, 3);
484+ term options = term_get_tuple_element (control , 5 );
485+
486+ term request_tuple = term_alloc_tuple (4 , & ctx -> heap );
487+ term_put_tuple_element (request_tuple , 0 , roots [0 ]);
488+ term_put_tuple_element (request_tuple , 1 , reqid );
489+ term_put_tuple_element (request_tuple , 2 , from );
490+ term_put_tuple_element (request_tuple , 3 , options );
491+ term request_opt = term_alloc_tuple (2 , & ctx -> heap );
492+ term_put_tuple_element (request_opt , 0 , REQUEST_ATOM );
493+ term_put_tuple_element (request_opt , 1 , request_tuple );
494+ term spawn_opts = term_list_prepend (request_opt , term_nil (), & ctx -> heap );
495+
496+ // reuse roots for args
497+ roots [0 ] = term_get_tuple_element (mfa , 0 );
498+ roots [1 ] = term_get_tuple_element (mfa , 1 );
499+ roots [2 ] = arglist ;
500+ roots [3 ] = spawn_opts ;
501+ nif_erlang_spawn_opt (ctx , 4 , roots );
502+ break ;
503+ }
445504 default :
446505 printf ("Unknown distribution protocol operation id %d\n" , (int ) term_to_int (operation ));
447506 RAISE_ERROR (BADARG_ATOM );
@@ -467,6 +526,23 @@ void dist_send_message(term external_pid, term payload, Context *ctx)
467526 synclist_unlock (& ctx -> global -> dist_connections );
468527}
469528
529+ void dist_spawn_reply (term req_id , term to_pid , bool link , bool monitor , term result , struct DistConnection * connection , GlobalContext * global )
530+ {
531+ int flags = (link ? SPAWN_REPLY_FLAGS_LINK_CREATED : 0 )
532+ | (monitor ? SPAWN_REPLY_FLAGS_MONITOR_CREATED : 0 );
533+ // allocate tuple
534+ BEGIN_WITH_STACK_HEAP (TUPLE_SIZE (5 ), heap )
535+ term control_message = term_alloc_tuple (5 , & heap );
536+ term_put_tuple_element (control_message , 0 , term_from_int (OPERATION_SPAWN_REPLY ));
537+ term_put_tuple_element (control_message , 1 , req_id );
538+ term_put_tuple_element (control_message , 2 , to_pid );
539+ term_put_tuple_element (control_message , 3 , term_from_int (flags ));
540+ term_put_tuple_element (control_message , 4 , result );
541+
542+ dist_enqueue_message (control_message , term_invalid_term (), connection , global );
543+ END_WITH_STACK_HEAP (heap , global )
544+ }
545+
470546const struct Nif setnode_3_nif = {
471547 .base .type = NIFFunctionType ,
472548 .nif_ptr = nif_erlang_setnode_3
0 commit comments