@@ -198,6 +198,8 @@ static void process_collect_zombie(struct process *zombie)
198198static void process_make_zombie (struct process * process )
199199{
200200 struct process * child ;
201+ struct process * parent ;
202+ siginfo_t sigchld ;
201203
202204 log_info ("freeing process: %s" , process -> name );
203205
@@ -223,19 +225,53 @@ static void process_make_zombie(struct process *process)
223225 signal_queue_flush (& process -> sig_pending );
224226 address_space_destroy (process -> as );
225227
226- /* Attach all orphans to the init process. */
228+ /*
229+ * Attach all orphans to the init process.
230+ */
227231 FOREACH_LLIST_ENTRY (child , & process -> children , this )
228232 {
229233 locked_scope (& child -> lock ) {
230234 llist_add (& init_process -> children , & child -> this );
235+ child -> parent = init_process ;
231236 }
232237 }
233238
234- spinlock_release (& process -> lock );
239+ /*
240+ * We cannot hold a reference to the process' parents so it might be in
241+ * the process of being made into a zombie itself. Detect this case and
242+ * move ourselves into the init process' children before sending SIGCHLD.
243+ */
244+ parent = process -> parent ;
245+ if (READ_ONCE (parent -> state ) == SCHED_ZOMBIE ) {
246+ llist_add (& init_process -> children , & process -> this );
247+ parent = init_process ;
248+ }
235249
236250 /*
237- * TODO: a SIGCHLD shall be sent to the parent process.
251+ * If the parent process' ignores the SIGCHLD signal the process' lifetime
252+ * must end immediately. This avoids dangling references to uncollectable
253+ * zombie processes.
254+ *
255+ * FIXME: We should delay this a bit to make sure no one's holding
256+ * the lock anymore. This may the source of use after free errors.
257+ * But ... that's for another day, this will work for now.
238258 */
259+ if (parent -> flags & PROC_SA_NOCLDWAIT ) {
260+ process_collect_zombie (process );
261+ return ;
262+ }
263+
264+ /*
265+ * TODO: Use our own signal.h header since newlib defines almost no macro...
266+ * We should be forwarding additional informations, such as the exit
267+ * code and CLD_* values...
268+ */
269+ memset (& sigchld , 0 , sizeof (sigchld ));
270+ sigchld .si_signo = SIGCHLD ;
271+ signal_process (parent , & sigchld );
272+
273+ spinlock_release (& process -> lock );
274+
239275}
240276
241277static struct process * process_get (struct process * process )
@@ -387,6 +423,8 @@ void process_init_kernel_process(void)
387423
388424 thread_set_user_stack (& kernel_process_initial_thread , ustack );
389425
426+ kernel_process .flags = 0 ;
427+
390428 kernel_process .sig_set = NULL ;
391429 signal_queue_init (& kernel_process .sig_pending );
392430 signal_queue_init (& kernel_process_initial_thread .sig_pending );
@@ -698,6 +736,7 @@ thread_fork(struct thread *thread, thread_entry_t entrypoint, void *arg)
698736 PROCESS_NAME_MAX_LEN );
699737 address_space_copy_current (new_process -> as );
700738 new_process -> creds = creds_get (current -> process -> creds );
739+ new_process -> flags = current -> process -> flags & PROC_FLAGS_INHERITED ;
701740 new_process -> sig_set = signal_set_clone (current -> process -> sig_set );
702741 if (new_process -> sig_set == NULL ) {
703742 err = E_NOMEM ;
@@ -719,6 +758,7 @@ thread_fork(struct thread *thread, thread_entry_t entrypoint, void *arg)
719758 goto process_destroy ;
720759 }
721760
761+ new_process -> parent = current -> process ;
722762 locked_scope (& current -> process -> lock )
723763 llist_add (& current -> process -> children , & new_process -> this );
724764
@@ -784,7 +824,7 @@ pid_t sys_getpid(void)
784824}
785825
786826/*
787- * TODO: waitpid(): hande signals
827+ *
788828 */
789829pid_t sys_waitpid (pid_t pid , int * stat_loc , int options )
790830{
0 commit comments