/* -*- 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_exit.c
*
* Implementation of system call "exit" and "exit_group".
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void release_robust_list (struct robust_list_head * head);
void release_clear_child_id (int * clear_child_tid);
int thread_exit(struct shim_thread * self, bool send_ipc)
{
lock(self->lock);
if (!self->is_alive) {
out:
unlock(self->lock);
return 0;
}
int exit_code = self->exit_code;
self->is_alive = false;
if (IS_INTERNAL(self))
goto out;
struct shim_handle_map * handle_map = self->handle_map;
self->handle_map = NULL;
struct shim_handle * exec = self->exec;
self->exec = NULL;
struct shim_thread * parent = self->parent;
if (parent) {
assert(parent != self);
assert(parent->child_exit_event);
debug("thread exits, notifying thread %d\n", parent->tid);
lock(parent->lock);
list_del_init(&self->siblings);
list_add_tail(&self->siblings, &parent->exited_children);
if (!self->in_vm) {
debug("deliver SIGCHLD (thread = %d, exitval = %d)\n",
self->tid, exit_code);
siginfo_t info;
memset(&info, 0, sizeof(siginfo_t));
info.si_signo = SIGCHLD;
info.si_pid = self->tid;
info.si_uid = self->uid;
info.si_status = (exit_code & 0xff) << 8;
append_signal(parent, SIGCHLD, &info);
}
unlock(parent->lock);
DkEventSet(parent->child_exit_event);
}
struct robust_list_head * robust_list = (void *) self->robust_list;
self->robust_list = NULL;
unlock(self->lock);
if (handle_map)
put_handle_map(handle_map);
if (exec)
put_handle(exec);
if (robust_list)
release_robust_list(robust_list);
if (self->clear_child_tid)
release_clear_child_id (self->clear_child_tid);
DkEventSet(self->exit_event);
if (self->in_vm && send_ipc)
ipc_cld_exit_send(self->tid, exit_code);
return 0;
}
int try_process_exit (int error_code)
{
struct shim_thread * cur_thread = get_cur_thread();
thread_exit(cur_thread, true);
if (check_last_thread(cur_thread))
return 0;
terminate_async_helper();
if (!exit_with_ipc_helper(true))
shim_clean();
return 0;
}
int shim_do_exit_group (int error_code)
{
INC_PROFILE_OCCURENCE(syscall_use_ipc);
struct shim_thread * cur_thread = get_cur_thread();
assert(!IS_INTERNAL(cur_thread));
if (debug_handle)
sysparser_printf("---- shim_exit_group (returning %d)\n", error_code);
if (cur_thread->dummy) {
thread_exit(cur_thread, true);
switch_dummy_thread(cur_thread);
}
debug("now kill other threads in the process\n");
do_kill_proc(cur_thread->tgid, cur_thread->tgid, SIGKILL, false);
debug("now exit the process\n");
try_process_exit(error_code);
#ifdef PROFILE
if (ENTER_TIME)
SAVE_PROFILE_INTERVAL_SINCE(syscall_exit_group, ENTER_TIME);
#endif
DkThreadExit();
return 0;
}
int shim_do_exit (int error_code)
{
INC_PROFILE_OCCURENCE(syscall_use_ipc);
struct shim_thread * cur_thread = get_cur_thread();
assert(!IS_INTERNAL(cur_thread));
if (debug_handle)
sysparser_printf("---- shim_exit (returning %d)\n", error_code);
if (cur_thread->dummy) {
thread_exit(cur_thread, true);
switch_dummy_thread(cur_thread);
}
try_process_exit(error_code);
#ifdef PROFILE
if (ENTER_TIME)
SAVE_PROFILE_INTERVAL_SINCE(syscall_exit, ENTER_TIME);
#endif
DkThreadExit();
return 0;
}