/* -*- 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 OSCAR lab, 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 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 General Public License for more details.
You should have received a copy of the GNU 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)) {
struct shim_thread * parent = thread->parent;
assert(parent);
lock(parent->lock);
list_del_init(&thread->siblings);
unlock(parent->lock);
put_thread(parent);
put_thread(thread);
thread->parent = NULL;
}
unlock(thread->lock);
goto found;
}
lock(cur->lock);
if (list_empty(&cur->children) &&
list_empty(&cur->exited_children)) {
unlock(cur->lock);
return -ECHILD;
}
if (!(option & WNOHANG)) {
block:
if (cur->child_exit_event)
while (list_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;
list_for_each_entry(thread, &cur->exited_children, siblings)
if (thread->pgid == -pid)
goto found_child;
if (!(option & WNOHANG))
goto block;
} else {
if (!list_empty(&cur->exited_children)) {
thread = list_first_entry(&cur->exited_children,
struct shim_thread, siblings);
goto found_child;
}
}
unlock(cur->lock);
return 0;
found_child:
list_del_init(&thread->siblings);
put_thread(cur);
thread->parent = NULL;
if (list_empty(&cur->exited_children))
DkEventClear(cur->child_exit_event);
unlock(cur->lock);
found:
if (status)
*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;
}