version 1.1.1.1, 2008/06/03 10:38:51 |
version 1.1.1.1.2.1, 2008/08/13 17:12:45 |
|
|
/* |
/* |
* Copyright (c) 2005-2007, Kohsuke Ohtani |
* Copyright (c) 2005-2008, Kohsuke Ohtani |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
/* |
/* |
* Process server: |
* Process server: |
* |
* |
* A process server is responsible to handle process ID, group ID, |
* A process server is responsible to handle process ID, group |
* signal and fork()/exec() state. Since Prex microkernel does not |
* ID, signal and fork()/exec() state. Since Prex microkernel |
* have the concept about process or process group, the process |
* does not have the concept about process or process group, the |
* server will map each Prex task to POSIX process. |
* process server will map each Prex task to POSIX process. |
* |
* |
* Prex does not support uid (user ID) and gid (group ID) because |
* Prex does not support uid (user ID) and gid (group ID) because |
* it runs only in a single user mode. The value of uid and gid is |
* it runs only in a single user mode. The value of uid and gid is |
|
|
* library stubs, and it is out of scope in this server. |
* library stubs, and it is out of scope in this server. |
* |
* |
* Important Notice: |
* Important Notice: |
* This server is made as a single thread program to reduce many locks |
* This server is made as a single thread program to reduce many |
* and to keep the code clean. So, we should not block in the kernel |
* locks and to keep the code clean. So, we should not block in |
* for any service. If some service must wait an event, it should wait |
* the kernel for any service. If some service must wait an |
* within the library stub in the client application. |
* event, it should wait within the library stub in the client |
|
* application. |
*/ |
*/ |
|
|
#include <prex/prex.h> |
#include <prex/prex.h> |
|
|
#include "proc.h" |
#include "proc.h" |
|
|
/* forward declarations */ |
/* forward declarations */ |
static int proc_version(struct msg *msg); |
static int proc_debug(struct msg *); |
static int proc_debug(struct msg *msg); |
static int proc_shutdown(struct msg *); |
static int proc_shutdown(struct msg *msg); |
static int proc_exec(struct msg *); |
static int proc_exec(struct msg *msg); |
static int proc_pstat(struct msg *); |
static int proc_pstat(struct msg *msg); |
static int proc_register(struct msg *); |
static int proc_register(struct msg *msg); |
static int proc_setinit(struct msg *); |
static int proc_setinit(struct msg *msg); |
|
|
|
/* |
/* |
* Message mapping |
* Message mapping |
|
|
}; |
}; |
|
|
static const struct msg_map procmsg_map[] = { |
static const struct msg_map procmsg_map[] = { |
{STD_VERSION, proc_version}, |
|
{STD_DEBUG, proc_debug}, |
{STD_DEBUG, proc_debug}, |
{STD_SHUTDOWN, proc_shutdown}, |
{STD_SHUTDOWN, proc_shutdown}, |
{PS_GETPID, proc_getpid}, |
{PS_GETPID, proc_getpid}, |
{PS_GETPPID, proc_getppid}, |
{PS_GETPPID, proc_getppid}, |
{PS_GETPGID, proc_getpgid}, |
{PS_GETPGID, proc_getpgid}, |
{PS_SETPGID, proc_setpgid}, |
{PS_SETPGID, proc_setpgid}, |
|
{PS_GETSID, proc_getsid}, |
|
{PS_SETSID, proc_setsid}, |
{PS_FORK, proc_fork}, |
{PS_FORK, proc_fork}, |
{PS_EXIT, proc_exit}, |
{PS_EXIT, proc_exit}, |
{PS_STOP, proc_stop}, |
{PS_STOP, proc_stop}, |
|
|
{PS_PSTAT, proc_pstat}, |
{PS_PSTAT, proc_pstat}, |
{PS_REGISTER, proc_register}, |
{PS_REGISTER, proc_register}, |
{PS_SETINIT, proc_setinit}, |
{PS_SETINIT, proc_setinit}, |
{0, 0}, |
{0, NULL}, |
}; |
}; |
|
|
static struct proc proc0; /* process data of this server (pid=0) */ |
static struct proc proc0; /* process data of this server (pid=0) */ |
static struct pgrp pgrp0; /* process group for process server */ |
static struct pgrp pgrp0; /* process group for first process */ |
|
static struct session session0; /* session for first process */ |
|
|
struct proc initproc; /* process slot for init process (pid=1) */ |
struct proc initproc; /* process slot for init process (pid=1) */ |
struct proc *curproc; /* current (caller) process */ |
struct proc *curproc; /* current (caller) process */ |
struct list allproc; /* list of all processes */ |
struct list allproc; /* list of all processes */ |
|
|
|
/* |
|
* Create a new process. |
|
*/ |
static void |
static void |
newproc(struct proc *p, pid_t pid, task_t task) |
newproc(struct proc *p, pid_t pid, task_t task) |
{ |
{ |
|
|
p->parent = &proc0; |
p->p_parent = &proc0; |
p->pgrp = &pgrp0; |
p->p_pgrp = &pgrp0; |
p->stat = SRUN; |
p->p_stat = SRUN; |
p->exit_code = 0; |
p->p_exitcode = 0; |
p->wait_vfork = 0; |
p->p_vforked = 0; |
p->pid = pid; |
p->p_pid = pid; |
p->task = task; |
p->p_task = task; |
list_init(&p->children); |
list_init(&p->p_children); |
list_insert(&allproc, &p->link); |
list_insert(&allproc, &p->p_link); |
proc_add(p); |
proc_add(p); |
list_insert(&proc0.children, &p->sibling); |
list_insert(&proc0.p_children, &p->p_sibling); |
list_insert(&pgrp0.members, &p->pgrp_link); |
list_insert(&pgrp0.pg_members, &p->p_pgrp_link); |
} |
} |
|
|
/* |
/* |
* exec() - Update pid to track the mapping with task id. |
* exec() - Update pid to track the mapping with task id. |
* |
* The almost all work is done by a exec server for exec() |
* The almost all work is done by a exec server for exec() emulation. |
* emulation. So, there is not so many jobs here... |
* So, there is not so many jobs here... |
|
*/ |
*/ |
static int |
static int |
proc_exec(struct msg *msg) |
proc_exec(struct msg *msg) |
{ |
{ |
task_t org_task, new_task; |
task_t orgtask, newtask; |
struct proc *p, *parent; |
struct proc *p, *parent; |
|
|
dprintf("proc_exec: proc=%x\n", curproc); |
DPRINTF(("proc_exec: pid=%x\n", curproc->p_pid)); |
org_task = msg->data[0]; |
|
new_task = msg->data[1]; |
orgtask = (task_t)msg->data[0]; |
if ((p = task_to_proc(org_task)) == NULL) |
newtask = (task_t)msg->data[1]; |
|
if ((p = task_to_proc(orgtask)) == NULL) |
return EINVAL; |
return EINVAL; |
|
|
proc_remove(p); |
proc_remove(p); |
p->task = new_task; |
p->p_task = newtask; |
proc_add(p); |
proc_add(p); |
p->stack_base = (void *)msg->data[2]; |
p->p_stackbase = (void *)msg->data[2]; |
|
|
parent = p->parent; |
parent = p->p_parent; |
if (parent != NULL && parent->wait_vfork) |
if (parent != NULL && parent->p_vforked) |
vfork_end(parent); |
vfork_end(parent); |
return 0; |
return 0; |
} |
} |
|
|
task_t task; |
task_t task; |
struct proc *p; |
struct proc *p; |
|
|
dprintf("proc_pstat: task=%x\n", msg->data[0]); |
DPRINTF(("proc_pstat: task=%x\n", msg->data[0])); |
task = msg->data[0]; |
|
|
task = (task_t)msg->data[0]; |
if ((p = task_to_proc(task)) == NULL) |
if ((p = task_to_proc(task)) == NULL) |
return EINVAL; |
return EINVAL; |
|
|
msg->data[0] = (int)p->pid; |
msg->data[0] = (int)p->p_pid; |
msg->data[2] = (int)p->stat; |
msg->data[2] = (int)p->p_stat; |
if (p->parent == NULL) |
if (p->p_parent == NULL) |
msg->data[1] = (int)0; |
msg->data[1] = (int)0; |
else |
else |
msg->data[1] = (int)p->parent->pid; |
msg->data[1] = (int)p->p_parent->p_pid; |
return 0; |
return 0; |
} |
} |
|
|
|
|
struct proc *p; |
struct proc *p; |
|
|
p = &initproc; |
p = &initproc; |
if (p->stat == SRUN) |
if (p->p_stat == SRUN) |
return EPERM; |
return EPERM; |
|
|
newproc(p, 1, msg->hdr.task); |
newproc(p, 1, msg->hdr.task); |
|
|
if ((p = malloc(sizeof(struct proc))) == NULL) |
if ((p = malloc(sizeof(struct proc))) == NULL) |
return ENOMEM; |
return ENOMEM; |
|
|
if ((pid = pid_assign()) == 0) |
if ((pid = pid_assign()) == 0) { |
|
free(p); |
return EAGAIN; /* Too many processes */ |
return EAGAIN; /* Too many processes */ |
|
} |
newproc(p, pid, msg->hdr.task); |
newproc(p, pid, msg->hdr.task); |
return 0; |
return 0; |
} |
} |
|
|
static int |
static int |
proc_version(struct msg *msg) |
|
{ |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
proc_shutdown(struct msg *msg) |
proc_shutdown(struct msg *msg) |
{ |
{ |
|
|
|
|
#ifdef DEBUG_PROC |
#ifdef DEBUG_PROC |
struct proc *p; |
struct proc *p; |
list_t n; |
list_t n; |
char stat[][5] = { "RUN ", "ZOMB", "STOP" }; |
char stat[][5] = { " ", "RUN ", "ZOMB", "STOP" }; |
|
|
printf("<Process Server>\n"); |
dprintf("<Process Server>\n"); |
printf("Dump process\n"); |
dprintf("Dump process\n"); |
printf(" pid ppid stat task\n"); |
dprintf(" pid ppid pgid sid stat task\n"); |
printf(" ------ ------ ---- --------\n"); |
dprintf(" ------ ------ ------ ------ ---- --------\n"); |
|
|
for (n = list_first(&allproc); n != &allproc; |
for (n = list_first(&allproc); n != &allproc; |
n = list_next(n)) { |
n = list_next(n)) { |
p = list_entry(n, struct proc, link); |
p = list_entry(n, struct proc, p_link); |
printf(" %6d %6d %s %08x\n", |
dprintf(" %6d %6d %6d %6d %s %08x\n", p->p_pid, |
p->pid, p->parent->pid, stat[p->stat], p->task); |
p->p_parent->p_pid, p->p_pgrp->pg_pgid, |
|
p->p_pgrp->pg_session->s_leader->p_pid, |
|
stat[p->p_stat], p->p_task); |
} |
} |
printf("\n"); |
dprintf("\n"); |
#endif |
#endif |
return 0; |
return 0; |
} |
} |
|
|
{ |
{ |
struct proc *p; |
struct proc *p; |
|
|
|
p = &proc0; |
|
curproc = p; |
|
|
tty_init(); |
tty_init(); |
table_init(); |
table_init(); |
|
list_init(&allproc); |
|
|
/* |
/* |
* Setup a process for ourselves. |
* Create process 0 (the process server) |
* pid=0 is always reserved by process server. |
|
*/ |
*/ |
p = &proc0; |
pgrp0.pg_pgid = 0; |
p->parent = 0; |
list_init(&pgrp0.pg_members); |
p->pgrp = &pgrp0; |
|
p->stat = SRUN; |
|
p->exit_code = 0; |
|
p->wait_vfork = 0; |
|
p->pid = 0; |
|
p->task = task_self(); |
|
list_init(&p->children); |
|
list_init(&allproc); |
|
list_init(&pgrp0.members); |
|
proc_add(p); |
|
pgrp_add(&pgrp0); |
pgrp_add(&pgrp0); |
list_insert(&pgrp0.members, &p->pgrp_link); |
|
|
pgrp0.pg_session = &session0; |
|
session0.s_refcnt = 1; |
|
session0.s_leader = p; |
|
session0.s_ttyhold = 0; |
|
|
|
p->p_pgrp = &pgrp0; |
|
p->p_parent = 0; |
|
p->p_stat = SRUN; |
|
p->p_exitcode = 0; |
|
p->p_vforked = 0; |
|
p->p_pid = 0; |
|
p->p_task = task_self(); |
|
list_init(&p->p_children); |
|
proc_add(p); |
|
list_insert(&pgrp0.pg_members, &p->p_pgrp_link); |
|
|
|
DPRINTF(("proc0=%x init=%x\n", &proc0, &initproc)); |
} |
} |
|
|
/* |
/* |
|
|
curproc = task_to_proc(msg.hdr.task); |
curproc = task_to_proc(msg.hdr.task); |
|
|
/* Update the capability of caller task. */ |
/* Update the capability of caller task. */ |
if (curproc && task_getcap(msg.hdr.task, |
if (curproc && |
&curproc->cap)) |
task_getcap(msg.hdr.task, &curproc->p_cap)) |
break; |
break; |
|
|
err = map->func(&msg); |
err = (*map->func)(&msg); |
break; |
break; |
} |
} |
map++; |
map++; |
|
|
msg_reply(obj, &msg, sizeof(msg)); |
msg_reply(obj, &msg, sizeof(msg)); |
#ifdef DEBUG_PROC |
#ifdef DEBUG_PROC |
if (err) |
if (err) |
dprintf("msg code=%x error=%d\n", map->code, err); |
DPRINTF(("proc: msg code=%x error=%d\n", map->code, |
|
err)); |
#endif |
#endif |
} |
} |
return 0; |
return 0; |