/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
/* 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_CATAGORY(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;
INC_PROFILE_OCCURENCE(syscall_use_ipc);
if (pid > 0) {
if (!(thread = lookup_thread(pid)))
return -ECHILD;
if (!(option & WNOHANG)) {
block_pid:
DkObjectsWaitAny(1, &thread->exit_event,
NO_TIMEOUT);
}
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);
DkObjectsWaitAny(1, &cur->child_exit_event, NO_TIMEOUT);
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 == -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;
}