@@ -156,8 +156,8 @@ void context_destroy(Context *ctx)
156156 while (signal_message ) {
157157 switch (signal_message -> type ) {
158158 case ProcessInfoRequestSignal : {
159- struct BuiltInAtomRequestSignal * request_signal
160- = CONTAINER_OF (signal_message , struct BuiltInAtomRequestSignal , base );
159+ struct ProcessInfoRequestSignal * request_signal
160+ = CONTAINER_OF (signal_message , struct ProcessInfoRequestSignal , base );
161161 context_process_process_info_request_signal (ctx , request_signal , true);
162162 break ;
163163 }
@@ -312,36 +312,93 @@ void context_process_kill_signal(Context *ctx, struct TermSignal *signal)
312312 context_update_flags (ctx , ~NoFlags , Killed );
313313}
314314
315- void context_process_process_info_request_signal (Context * ctx , struct BuiltInAtomRequestSignal * signal , bool process_table_locked )
315+ void context_process_process_info_request_signal (Context * ctx , struct ProcessInfoRequestSignal * signal , bool process_table_locked )
316316{
317317 Context * target ;
318318 if (process_table_locked ) {
319319 target = globalcontext_get_process_nolock (ctx -> global , signal -> sender_pid );
320320 } else {
321321 target = globalcontext_get_process_lock (ctx -> global , signal -> sender_pid );
322322 }
323- if (LIKELY (target )) {
323+
324+ if (UNLIKELY (!target )) {
325+ return ;
326+ }
327+
328+ if (signal -> mode == PROCESS_INFO_SINGLE ) {
329+ term atom = signal -> atoms [0 ];
324330 size_t term_size ;
325- if (context_get_process_info (ctx , NULL , & term_size , signal -> atom , NULL )) {
326- Heap heap ;
327- if (UNLIKELY (memory_init_heap (& heap , term_size ) != MEMORY_GC_OK )) {
328- mailbox_send_immediate_signal (target , TrapExceptionSignal , OUT_OF_MEMORY_ATOM );
329- } else {
330- term ret ;
331- if (context_get_process_info (ctx , & ret , NULL , signal -> atom , & heap )) {
332- mailbox_send_term_signal (target , TrapAnswerSignal , ret );
333- } else {
334- mailbox_send_immediate_signal (target , TrapExceptionSignal , ret );
335- }
336- memory_destroy_heap (& heap , ctx -> global );
331+ if (!context_get_process_info (ctx , NULL , & term_size , atom , NULL )) {
332+ mailbox_send_immediate_signal (target , TrapExceptionSignal , BADARG_ATOM );
333+ goto done ;
334+ }
335+
336+ Heap heap ;
337+ if (UNLIKELY (memory_init_heap (& heap , term_size ) != MEMORY_GC_OK )) {
338+ mailbox_send_immediate_signal (target , TrapExceptionSignal , OUT_OF_MEMORY_ATOM );
339+ goto done ;
340+ }
341+
342+ term ret ;
343+ if (context_get_process_info (ctx , & ret , NULL , atom , & heap )) {
344+ // return [] when unregistered (BEAM backward compatibility)
345+ if (atom == REGISTERED_NAME_ATOM && term_is_tuple (ret ) && term_is_nil (term_get_tuple_element (ret , 1 ))) {
346+ ret = term_nil ();
337347 }
348+ mailbox_send_term_signal (target , TrapAnswerSignal , ret );
338349 } else {
339- mailbox_send_immediate_signal (target , TrapExceptionSignal , BADARG_ATOM );
350+ mailbox_send_immediate_signal (target , TrapExceptionSignal , ret );
351+ }
352+ memory_destroy_heap (& heap , ctx -> global );
353+ } else {
354+ size_t total_size = 0 ;
355+ for (size_t i = 0 ; i < signal -> len ; i ++ ) {
356+ size_t item_size ;
357+ if (UNLIKELY (!context_get_process_info (ctx , NULL , & item_size , signal -> atoms [i ], NULL ))) {
358+ mailbox_send_immediate_signal (target , TrapExceptionSignal , BADARG_ATOM );
359+ goto done ;
360+ }
361+ total_size += item_size + CONS_SIZE ;
362+ }
363+
364+ if (signal -> len == 0 ) {
365+ mailbox_send_term_signal (target , TrapAnswerSignal , term_nil ());
366+ goto done ;
340367 }
341- if (!process_table_locked ) {
342- globalcontext_get_process_unlock (ctx -> global , target );
368+
369+ Heap heap ;
370+ if (UNLIKELY (memory_init_heap (& heap , total_size ) != MEMORY_GC_OK )) {
371+ mailbox_send_immediate_signal (target , TrapExceptionSignal , OUT_OF_MEMORY_ATOM );
372+ goto done ;
373+ }
374+
375+ // Build list backwards to preserve input order
376+ term result = term_nil ();
377+ bool build_ok = true;
378+ for (ssize_t i = (ssize_t ) signal -> len - 1 ; i >= 0 ; i -- ) {
379+ term item_result ;
380+ if (UNLIKELY (!context_get_process_info (ctx , & item_result , NULL , signal -> atoms [i ], & heap ))) {
381+ mailbox_send_immediate_signal (target , TrapExceptionSignal , item_result );
382+ build_ok = false;
383+ break ;
384+ }
385+
386+ if (signal -> mode == PROCESS_INFO_LIST_OMIT_UNREGISTERED && signal -> atoms [i ] == REGISTERED_NAME_ATOM && term_is_nil (term_get_tuple_element (item_result , 1 ))) {
387+ continue ;
388+ }
389+
390+ result = term_list_prepend (item_result , result , & heap );
343391 }
344- } // else: sender died
392+ if (LIKELY (build_ok )) {
393+ mailbox_send_term_signal (target , TrapAnswerSignal , result );
394+ }
395+ memory_destroy_heap (& heap , ctx -> global );
396+ }
397+
398+ done :
399+ if (!process_table_locked ) {
400+ globalcontext_get_process_unlock (ctx -> global , target );
401+ }
345402}
346403
347404bool context_process_signal_trap_answer (Context * ctx , struct TermSignal * signal )
@@ -525,6 +582,7 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
525582 case MESSAGE_QUEUE_LEN_ATOM :
526583 case REGISTERED_NAME_ATOM :
527584 case MEMORY_ATOM :
585+ case TRAP_EXIT_ATOM :
528586 ret_size = TUPLE_SIZE (2 );
529587 break ;
530588 case LINKS_ATOM : {
@@ -589,12 +647,8 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
589647 // registered_name for process or port..
590648 case REGISTERED_NAME_ATOM : {
591649 term name = globalcontext_get_registered_name_process (ctx -> global , ctx -> process_id );
592- if (term_is_invalid_term ((name ))) {
593- ret = term_nil (); // Set ret to an empty list to match erlang behaviour
594- } else {
595- term_put_tuple_element (ret , 0 , REGISTERED_NAME_ATOM );
596- term_put_tuple_element (ret , 1 , name );
597- }
650+ term_put_tuple_element (ret , 0 , REGISTERED_NAME_ATOM );
651+ term_put_tuple_element (ret , 1 , term_is_invalid_term (name ) ? term_nil () : name );
598652 break ;
599653 }
600654
@@ -630,6 +684,13 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
630684 break ;
631685 }
632686
687+ // true if a process traps exits, otherwise false
688+ case TRAP_EXIT_ATOM : {
689+ term_put_tuple_element (ret , 0 , TRAP_EXIT_ATOM );
690+ term_put_tuple_element (ret , 1 , ctx -> trap_exit ? TRUE_ATOM : FALSE_ATOM );
691+ break ;
692+ }
693+
633694 // pids of linked processes
634695 case LINKS_ATOM : {
635696 term_put_tuple_element (ret , 0 , LINKS_ATOM );
0 commit comments