/* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * shim_wait.c * * Implementation of system call "wait4". */ #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_PROFILE_CATEGORY(wait, ); DEFINE_PROFILE_INTERVAL(child_exit_notification, wait); pid_t shim_do_wait4(pid_t pid, int* status, int option, struct __kernel_rusage* ru) { struct shim_thread* cur = get_cur_thread(); struct shim_thread* thread = NULL; int ret = 0; __UNUSED(ru); INC_PROFILE_OCCURENCE(syscall_use_ipc); if (pid > 0) { if (!(thread = lookup_thread(pid))) return -ECHILD; if (!(option & WNOHANG)) { block_pid: object_wait_with_retry(thread->exit_event); } lock(&thread->lock); if (thread->is_alive) { unlock(&thread->lock); if (!(option & WNOHANG)) goto block_pid; put_thread(thread); return 0; } if (!LIST_EMPTY(thread, siblings)) { debug("reaping thread %p\n", thread); struct shim_thread* parent = thread->parent; assert(parent); lock(&parent->lock); /* DEP 5/15/17: These threads are exited */ assert(!thread->is_alive); LISTP_DEL_INIT(thread, &thread->parent->exited_children, siblings); unlock(&parent->lock); put_thread(parent); put_thread(thread); thread->parent = NULL; } unlock(&thread->lock); goto found; } lock(&cur->lock); if (LISTP_EMPTY(&cur->children) && LISTP_EMPTY(&cur->exited_children)) { unlock(&cur->lock); return -ECHILD; } if (!(option & WNOHANG)) { block: if (cur->child_exit_event) while (LISTP_EMPTY(&cur->exited_children)) { unlock(&cur->lock); object_wait_with_retry(cur->child_exit_event); lock(&cur->lock); } } if (pid == 0 || pid < -1) { if (pid == 0) pid = -cur->pgid; LISTP_FOR_EACH_ENTRY(thread, &cur->exited_children, siblings) { if (thread->pgid == (IDTYPE)-pid) goto found_child; } if (!(option & WNOHANG)) goto block; } else { if (!LISTP_EMPTY(&cur->exited_children)) { thread = LISTP_FIRST_ENTRY(&cur->exited_children, struct shim_thread, siblings); goto found_child; } } unlock(&cur->lock); return 0; found_child: LISTP_DEL_INIT(thread, &cur->exited_children, siblings); put_thread(cur); thread->parent = NULL; if (LISTP_EMPTY(&cur->exited_children)) DkEventClear(cur->child_exit_event); unlock(&cur->lock); found: if (status) { /* Bits 0--7 are for the signal, if any. * Bits 8--15 are for the exit code */ *status = thread->term_signal; *status |= ((thread->exit_code & 0xff) << 8); } ret = thread->tid; SAVE_PROFILE_INTERVAL_SINCE(child_exit_notification, thread->exit_time); del_thread(thread); put_thread(thread); return ret; }