#include "make_status.h"
#include "status.h"
#include "signal.h"
#include "sched.h"
#include "proc.h"
#include "alloc_proc.h"
#include "idle.h"
#include "proc_struct.h"
#include <fd.h>
#include <node.h>
#include <vm.h>
#include <string_table.h>
#include <paging.h>
#include <asm.h>
#include <errno.h>
#include <consts.h>
#include <enums.h>
#include <stddef.h>
static int is_orphaned(const struct proc_struct *proc)
{
return is_orphan(proc) || proc->parent->group == proc->group;
}
int is_orphaned_proc_group(const struct proc_group_struct *proc_group)
{
struct proc_struct *proc;
for (proc = proc_group->first_proc; proc; proc = proc->group_next) {
if (proc->state == PS_ZOMBIE)
continue;
if (!is_orphaned(proc))
return 0;
}
return 1;
}
static int become_orphaned_proc_group(const struct proc_struct *proc)
{
struct proc_struct *p;
if (is_orphaned(proc))
return 0;
for (p = proc->group->first_proc; p; p = p->group_next) {
if (p == proc)
continue;
if (p->state == PS_ZOMBIE)
continue;
if (!is_orphaned(p))
return 0;
}
return 1;
}
static int has_stopped_member(const struct proc_group_struct *proc_group)
{
struct proc_struct *proc;
for (proc = proc_group->first_proc; proc; proc = proc->group_next)
if (proc->state == PS_STOPPED)
return 1;
return 0;
}
static void close_file_descrs(struct file_descr_struct *file_descr_table[])
{
struct file_descr_struct **file_descr;
for (file_descr = file_descr_table; file_descr < file_descr_table + OPEN_MAX; file_descr++)
if (*file_descr)
fd_close(*file_descr);
}
static void hangup_newly_orphaned_process_group(const struct proc_struct *proc)
{
if (!become_orphaned_proc_group(proc))
return;
if (has_stopped_member(proc->group)) {
signal_group(proc->group, SIGHUP);
signal_group(proc->group, SIGCONT);
}
}
static void __attribute__ ((noreturn)) terminate(int status)
{
struct proc_struct *child;
cli();
sched_remove(current);
close_file_descrs(current->file_descr_table);
vm_free(¤t->vm);
node_release(current->wd);
string_table_destroy(¤t->cmdline);
current->state = PS_ZOMBIE;
hangup_newly_orphaned_process_group(current);
for (child = current->first_child; child; child = child->next_sibling)
hangup_newly_orphaned_process_group(child);
proc_tree_dishinerit_children(current);
set_status(status);
schedule();
while (1)
hlt();
}
void __attribute__ ((noreturn)) exit(int code)
{
terminate(make_status(0, code, 0));
}
void __attribute__ ((noreturn)) abort(int sig)
{
terminate(make_status(sig, 0, 0));
}
static void destroy_proc(struct proc_struct *proc)
{
proc_group_remove(proc);
proc_tree_remove(proc);
proc_list_remove(proc);
proc_table_remove(proc);
}
static void discard_proc(struct proc_struct *proc)
{
destroy_proc(proc);
free_proc(proc);
}
static int reap(struct proc_struct *child, int *status, int options)
{
int pid;
if (!report_status(child, status))
return 0;
pid = child->id;
switch (child->state) {
case PS_STOPPED:
if (!(options & WUNTRACED))
return 0;
break;
case PS_ZOMBIE:
discard_proc(child);
break;
default:
return 0;
}
return pid;
}
static int reap_any(struct proc_struct *child, struct proc_group_struct *proc_group, int *status, int options)
{
int pid;
int child_exists;
if (child)
return reap(child, status, options);
child_exists = 0;
for (child = current->first_child; child; child = child->next_sibling) {
if (proc_group && child->group != proc_group)
continue;
child_exists = 1;
if ((pid = reap(child, status, options)))
return pid;
}
return child_exists ? 0 : -ECHILD;
}
static int do_wait(struct proc_struct *child, struct proc_group_struct *proc_group, int *status, int options)
{
int retval;
int intr;
disable_intr(intr);
while (!(retval = reap_any(child, proc_group, status, options))) {
if (options & WNOHANG) {
retval = 0;
goto restore;
}
if (!wait_child_status()) {
retval = -ERESTARTSYS;
goto restore;
}
}
restore:
restore_intr(intr);
return retval;
}
int wait(struct proc_struct *child, int *status, int options)
{
return do_wait(child, NULL, status, options);
}
int wait_group_any(struct proc_group_struct *proc_group, int *status, int options)
{
return do_wait(NULL, proc_group, status, options);
}
int wait_any(int *status, int options)
{
return do_wait(NULL, NULL, status, options);
}
void reap_orphan_zombies()
{
int intr;
struct proc_struct *orphan, *next;
disable_intr(intr);
if (idle->first_child) {
for (orphan = idle->first_child; orphan; orphan = next) {
next = orphan->next_sibling;
if (orphan->state == PS_ZOMBIE)
discard_proc(orphan);
}
if (!idle->first_child)
check_paging_empty();
}
restore_intr(intr);
}