aboutsummaryrefslogtreecommitdiff
path: root/proc/mgt.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc/mgt.c')
-rw-r--r--proc/mgt.c484
1 files changed, 267 insertions, 217 deletions
diff --git a/proc/mgt.c b/proc/mgt.c
index e8af38d4..1180c700 100644
--- a/proc/mgt.c
+++ b/proc/mgt.c
@@ -1,5 +1,5 @@
/* Process management
- Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
@@ -21,6 +21,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <mach.h>
#include <sys/types.h>
+#include <sys/mman.h>
#include <errno.h>
#include <hurd/hurd_types.h>
#include <stdlib.h>
@@ -41,29 +42,34 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Create a new id structure with the given genuine uids and gids. */
static inline struct ids *
-make_ids (uid_t *uids, int nuids, uid_t *gids, int ngids)
+make_ids (const uid_t *uids, size_t nuids)
{
struct ids *i;
- i = malloc (sizeof (struct ids));
+ i = malloc (sizeof (struct ids) + sizeof (uid_t) * nuids);;
+ if (! i)
+ return NULL;
+
i->i_nuids = nuids;
- i->i_ngids = ngids;
- i->i_uids = malloc (sizeof (uid_t) * nuids);
- i->i_gids = malloc (sizeof (uid_t) * ngids);
i->i_refcnt = 1;
- memcpy (i->i_uids, uids, sizeof (uid_t) * nuids);
- memcpy (i->i_gids, gids, sizeof (uid_t) * ngids);
+ memcpy (&i->i_uids, uids, sizeof (uid_t) * nuids);
return i;
}
+static inline void
+ids_ref (struct ids *i)
+{
+ i->i_refcnt ++;
+}
+
/* Free an id structure. */
static inline void
-free_ids (struct ids *i)
+ids_rele (struct ids *i)
{
- free (i->i_uids);
- free (i->i_gids);
- free (i);
+ i->i_refcnt --;
+ if (i->i_refcnt == 0)
+ free (i);
}
/* Tell if process P has uid UID, or has root. */
@@ -77,15 +83,14 @@ check_uid (struct proc *p, uid_t uid)
return 0;
}
-
-/* Implement proc_reathenticate as described in <hurd/proc.defs>. */
+/* Implement proc_reathenticate as described in <hurd/process.defs>. */
kern_return_t
S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
{
error_t err;
uid_t gubuf[50], aubuf[50], ggbuf[50], agbuf[50];
uid_t *gen_uids, *aux_uids, *gen_gids, *aux_gids;
- u_int ngen_uids, naux_uids, ngen_gids, naux_gids;
+ size_t ngen_uids, naux_uids, ngen_gids, naux_gids;
if (!p)
return EOPNOTSUPP;
@@ -95,10 +100,13 @@ S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
gen_gids = ggbuf;
aux_gids = agbuf;
- ngen_uids = naux_uids = 50;
- ngen_gids = naux_gids = 50;
-
+ ngen_uids = sizeof (gubuf) / sizeof (uid_t);
+ naux_uids = sizeof (aubuf) / sizeof (uid_t);
+ ngen_gids = sizeof (ggbuf) / sizeof (uid_t);
+ naux_gids = sizeof (agbuf) / sizeof (uid_t);
+ /* Release the global lock while blocking on the auth server and client. */
+ mutex_unlock (&global_lock);
err = auth_server_authenticate (authserver,
rendport, MACH_MSG_TYPE_COPY_SEND,
MACH_PORT_NULL, MACH_MSG_TYPE_COPY_SEND,
@@ -106,40 +114,48 @@ S_proc_reauthenticate (struct proc *p, mach_port_t rendport)
&aux_uids, &naux_uids,
&gen_gids, &ngen_gids,
&aux_gids, &naux_gids);
+ mutex_lock (&global_lock);
+
if (err)
return err;
- mach_port_deallocate (mach_task_self (), rendport);
- if (!--p->p_id->i_refcnt)
- free_ids (p->p_id);
- p->p_id = make_ids (gen_uids, ngen_uids, gen_gids, ngen_gids);
+ if (p->p_dead)
+ /* The process died while we had the lock released.
+ Its p_id field is no longer valid and we shouldn't touch it. */
+ err = EAGAIN;
+ else
+ {
+ ids_rele (p->p_id);
+ p->p_id = make_ids (gen_uids, ngen_uids);
+ if (! p->p_id)
+ err = ENOMEM;
+ }
if (gen_uids != gubuf)
- vm_deallocate (mach_task_self (), (u_int) gen_uids,
- ngen_uids * sizeof (uid_t));
+ munmap (gen_uids, ngen_uids * sizeof (uid_t));
if (aux_uids != aubuf)
- vm_deallocate (mach_task_self (), (u_int) aux_uids,
- naux_uids * sizeof (uid_t));
+ munmap (aux_uids, naux_uids * sizeof (uid_t));
if (gen_gids != ggbuf)
- vm_deallocate (mach_task_self (), (u_int) gen_gids,
- ngen_gids * sizeof (uid_t));
+ munmap (gen_gids, ngen_gids * sizeof (uid_t));
if (aux_gids != agbuf)
- vm_deallocate (mach_task_self (), (u_int) aux_gids,
- naux_gids * sizeof (uid_t));
+ munmap (aux_gids, naux_gids * sizeof (uid_t));
- return 0;
+ if (!err)
+ mach_port_deallocate (mach_task_self (), rendport);
+ return err;
}
-/* Implement proc_child as described in <hurd/proc.defs>. */
+/* Implement proc_child as described in <hurd/process.defs>. */
kern_return_t
S_proc_child (struct proc *parentp,
task_t childt)
{
- struct proc *childp = task_find (childt);
+ struct proc *childp;
if (!parentp)
return EOPNOTSUPP;
+ childp = task_find (childt);
if (!childp)
return ESRCH;
@@ -160,10 +176,9 @@ S_proc_child (struct proc *parentp,
childp->p_owner = parentp->p_owner;
childp->p_noowner = parentp->p_noowner;
- if (!--childp->p_id->i_refcnt)
- free_ids (childp->p_id);
+ ids_rele (childp->p_id);
+ ids_ref (parentp->p_id);
childp->p_id = parentp->p_id;
- childp->p_id->i_refcnt++;
/* Process hierarchy. Remove from our current location
and place us under our new parent. Sanity check to make sure
@@ -197,17 +212,17 @@ S_proc_child (struct proc *parentp,
return 0;
}
-/* Implement proc_reassign as described in <hurd/proc.defs>. */
+/* Implement proc_reassign as described in <hurd/process.defs>. */
kern_return_t
S_proc_reassign (struct proc *p,
task_t newt)
{
- struct proc *stubp = task_find (newt);
- mach_port_t foo;
+ struct proc *stubp;
if (!p)
return EOPNOTSUPP;
+ stubp = task_find (newt);
if (!stubp)
return ESRCH;
@@ -219,20 +234,12 @@ S_proc_reassign (struct proc *p,
remove_proc_from_hash (p);
task_terminate (p->p_task);
- mach_port_deallocate (mach_task_self (), p->p_task);
+ mach_port_destroy (mach_task_self (), p->p_task);
p->p_task = stubp->p_task;
- /* For security, we need use the request port from STUBP */
+ /* For security, we need to use the request port from STUBP */
ports_transfer_right (p, stubp);
- /* Redirect the task-death notification to the new receive right. */
- mach_port_request_notification (mach_task_self (), p->p_task,
- MACH_NOTIFY_DEAD_NAME, 1,
- p->p_pi.port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- if (foo)
- mach_port_deallocate (mach_task_self (), foo);
-
/* Enqueued messages might refer to the old task port, so
destroy them. */
if (p->p_msgport != MACH_PORT_NULL)
@@ -247,7 +254,7 @@ S_proc_reassign (struct proc *p,
p->p_envp = stubp->p_envp;
/* Destroy stubp */
- stubp->p_task = 0; /* block deallocation */
+ stubp->p_task = MACH_PORT_NULL;/* block deallocation */
process_has_exited (stubp);
stubp->p_waited = 1; /* fake out complete_exit */
complete_exit (stubp);
@@ -257,7 +264,7 @@ S_proc_reassign (struct proc *p,
return 0;
}
-/* Implement proc_setowner as described in <hurd/proc.defs>. */
+/* Implement proc_setowner as described in <hurd/process.defs>. */
kern_return_t
S_proc_setowner (struct proc *p,
uid_t owner,
@@ -280,7 +287,7 @@ S_proc_setowner (struct proc *p,
return 0;
}
-/* Implement proc_getpids as described in <hurd/proc.defs>. */
+/* Implement proc_getpids as described in <hurd/process.defs>. */
kern_return_t
S_proc_getpids (struct proc *p,
pid_t *pid,
@@ -295,7 +302,7 @@ S_proc_getpids (struct proc *p,
return 0;
}
-/* Implement proc_set_arg_locations as described in <hurd/proc.defs>. */
+/* Implement proc_set_arg_locations as described in <hurd/process.defs>. */
kern_return_t
S_proc_set_arg_locations (struct proc *p,
vm_address_t argv,
@@ -308,7 +315,7 @@ S_proc_set_arg_locations (struct proc *p,
return 0;
}
-/* Implement proc_get_arg_locations as described in <hurd/proc.defs>. */
+/* Implement proc_get_arg_locations as described in <hurd/process.defs>. */
kern_return_t
S_proc_get_arg_locations (struct proc *p,
vm_address_t *argv,
@@ -319,13 +326,14 @@ S_proc_get_arg_locations (struct proc *p,
return 0;
}
-/* Implement proc_dostop as described in <hurd/proc.defs>. */
+/* Implement proc_dostop as described in <hurd/process.defs>. */
kern_return_t
S_proc_dostop (struct proc *p,
thread_t contthread)
{
thread_t threadbuf[2], *threads = threadbuf;
- unsigned int nthreads = 2, i;
+ size_t nthreads = sizeof (threadbuf) / sizeof (thread_t);
+ int i;
error_t err;
if (!p)
@@ -336,16 +344,21 @@ S_proc_dostop (struct proc *p,
return err;
err = task_threads (p->p_task, &threads, &nthreads);
if (err)
- return err;
+ {
+ task_resume (p->p_task);
+ return err;
+ }
+ /* We can not compare the thread ports with CONTTHREAD, as CONTTHREAD
+ might be a proxy port (for example in rpctrace). For this reason
+ we suspend all threads and then resume CONTTHREAD. */
for (i = 0; i < nthreads; i++)
{
if (threads[i] != contthread)
- err = thread_suspend (threads[i]);
+ thread_suspend (threads[i]);
mach_port_deallocate (mach_task_self (), threads[i]);
}
if (threads != threadbuf)
- vm_deallocate (mach_task_self (), (vm_address_t) threads,
- nthreads * sizeof (thread_t));
+ munmap (threads, nthreads * sizeof (thread_t));
err = task_resume (p->p_task);
if (err)
return err;
@@ -372,7 +385,7 @@ S_proc_handle_exceptions (struct proc *p,
mach_msg_type_number_t statecnt)
{
struct exc *e;
- error_t err;
+ error_t err;
/* No need to check P here; we don't use it. */
@@ -385,7 +398,7 @@ S_proc_handle_exceptions (struct proc *p,
e->forwardport = forwardport;
e->flavor = flavor;
e->statecnt = statecnt;
- bcopy (new_state, e->thread_state, statecnt * sizeof (natural_t));
+ memcpy (e->thread_state, new_state, statecnt * sizeof (natural_t));
ports_port_deref (e);
return 0;
}
@@ -399,9 +412,9 @@ S_proc_exception_raise (mach_port_t excport,
mach_msg_type_name_t reply_type,
mach_port_t thread,
mach_port_t task,
- int exception,
- int code,
- int subcode)
+ integer_t exception,
+ integer_t code,
+ integer_t subcode)
{
error_t err;
struct proc *p;
@@ -421,8 +434,6 @@ S_proc_exception_raise (mach_port_t excport,
err = proc_exception_raise (e->forwardport,
reply, reply_type, MACH_SEND_NOTIFY,
thread, task, exception, code, subcode);
- mach_port_deallocate (mach_task_self (), thread);
- mach_port_deallocate (mach_task_self (), task);
switch (err)
{
@@ -435,19 +446,21 @@ S_proc_exception_raise (mach_port_t excport,
dequeue that message. */
err = thread_set_state (thread, e->flavor, e->thread_state, e->statecnt);
ports_port_deref (e);
+ mach_port_deallocate (mach_task_self (), thread);
+ mach_port_deallocate (mach_task_self (), task);
return MIG_NO_REPLY;
default:
/* Some unexpected error in forwarding the message. */
/* FALLTHROUGH */
- case MACH_SEND_INVALID_NOTIFY:
- /* The port's queue is full, meaning the thread didn't receive
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ /* The port's queue is full; this means the thread didn't receive
the exception message we forwarded last time it faulted.
Declare that signal thread hopeless and the task crashed. */
/* Translate the exception code into a signal number
- and mark the process has dying that way. */
+ and mark the process as having died that way. */
hsd.exc = exception;
hsd.exc_code = code;
hsd.exc_subcode = subcode;
@@ -456,20 +469,46 @@ S_proc_exception_raise (mach_port_t excport,
p->p_status = W_EXITCODE (0, signo);
p->p_sigcode = hsd.code;
- /* Nuke the task; we will get a notification message and report it
- died with SIGNO. */
+ /* Nuke the task; we will get a notification message and report that
+ it died with SIGNO. */
task_terminate (task);
ports_port_deref (e);
- return 0;
+
+ /* In the MACH_SEND_NOTIFY_IN_PROGRESS case, the kernel did a
+ pseudo-receive of the RPC request message that may have added user
+ refs to these send rights. But we have lost track because the MiG
+ stub did not save the message buffer that was modified by the
+ pseudo-receive.
+
+ Fortunately, we can be sure that we don't need the THREAD send
+ right for anything since this task is now dead; there would be a
+ potential race here with another exception_raise message arriving
+ with the same thread, but we expect that this won't happen since
+ the thread will still be waiting for our reply. XXX We have no
+ secure knowledge that this is really from the kernel, so a
+ malicious user could confuse us and induce a race where we clobber
+ another port put on the THREAD name after the destroy; also, a
+ user just doing thread_set_state et al could arrange that we get a
+ second legitimate exception_raise for the same thread and have the
+ first race mentioned above!
+
+ There are all manner of race problems if we destroy the TASK
+ right. Fortunately, since we've terminated the task we know that
+ we will shortly be getting a dead-name notifiction and that will
+ call mach_port_destroy in TASK when it is safe to do so. */
+
+ mach_port_destroy (mach_task_self (), thread);
+
+ return MIG_NO_REPLY;
}
}
-/* Implement proc_getallpids as described in <hurd/proc.defs>. */
+/* Implement proc_getallpids as described in <hurd/process.defs>. */
kern_return_t
S_proc_getallpids (struct proc *p,
pid_t **pids,
- u_int *pidslen)
+ size_t *pidslen)
{
int nprocs;
pid_t *loc;
@@ -491,8 +530,12 @@ S_proc_getallpids (struct proc *p,
prociterate (count_up, &nprocs);
if (nprocs > *pidslen)
- vm_allocate (mach_task_self (), (vm_address_t *) pids,
- nprocs * sizeof (pid_t), 1);
+ {
+ *pids = mmap (0, nprocs * sizeof (pid_t), PROT_READ|PROT_WRITE,
+ MAP_ANON, 0, 0);
+ if (*pids == MAP_FAILED)
+ return ENOMEM;
+ }
loc = *pids;
prociterate (store_pid, &loc);
@@ -500,141 +543,151 @@ S_proc_getallpids (struct proc *p,
*pidslen = nprocs;
return 0;
}
-
+
/* Create a process for TASK, which is not otherwise known to us.
- The task will be placed as a child of init and in init's pgrp. */
+ The PID/parentage/job-control fields are not yet filled in,
+ and the proc is not entered into any hash table. */
struct proc *
-new_proc (task_t task)
+allocate_proc (task_t task)
{
+ error_t err;
struct proc *p;
- mach_port_t foo;
-
- /* Because these have a reference count of one before starting,
- they can never be freed, so we're safe. */
- static struct login *nulllogin;
- static struct ids nullids = {0, 0, 0, 0, 1};
-
- if (!nulllogin)
- {
- nulllogin = malloc (sizeof (struct login) + 7);
- nulllogin->l_refcnt = 1;
- strcpy (nulllogin->l_name, "<none>");
- }
/* Pid 0 is us; pid 1 is init. We handle those here specially;
all other processes inherit from init here (though proc_child
will move them to their actual parent usually). */
- ports_create_port (proc_class, proc_bucket, sizeof (struct proc), &p);
+ err = ports_create_port (proc_class, proc_bucket, sizeof (struct proc), &p);
+ if (err)
+ return NULL;
- p->p_pid = genpid ();
+ memset (&p->p_pi + 1, 0, sizeof *p - sizeof p->p_pi);
p->p_task = task;
+ p->p_msgport = MACH_PORT_NULL;
- mach_port_request_notification (mach_task_self (), p->p_task,
- MACH_NOTIFY_DEAD_NAME, 1, p->p_pi.port_right,
- MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo);
- if (foo != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), foo);
+ condition_init (&p->p_wakeup);
- switch (p->p_pid)
- {
- case 0:
- p->p_login = malloc (sizeof (struct login) + 5);
- p->p_login->l_refcnt = 1;
- strcpy (p->p_login->l_name, "root");
- break;
+ return p;
+}
- case 1:
- p->p_login = self_proc->p_login;
- p->p_login->l_refcnt++;
- break;
+/* Allocate and initialize the proc structure for init (PID 1),
+ the original parent of all other procs. */
+struct proc *
+create_startup_proc (void)
+{
+ static const uid_t zero;
+ struct proc *p;
+ const char *rootsname = "root";
- default:
- p->p_login = nulllogin;
- p->p_login->l_refcnt++;
- }
+ p = allocate_proc (MACH_PORT_NULL);
+ assert (p);
- p->p_owner = 0;
+ p->p_pid = 1;
- if (p->p_pid == 0)
- {
- uid_t foo = 0;
- p->p_id = make_ids (&foo, 1, &foo, 1);
- p->p_parent = p;
- p->p_sib = 0;
- p->p_prevsib = &p->p_ochild;
- p->p_ochild = p;
- p->p_loginleader = 1;
- p->p_parentset = 1;
- p->p_noowner = 0;
- }
- else if (p->p_pid == 1)
- {
- p->p_id = self_proc->p_id;
- p->p_id->i_refcnt++;
- p->p_parent = self_proc;
-
- p->p_sib = self_proc->p_ochild;
- p->p_prevsib = &self_proc->p_ochild;
- if (p->p_sib)
- p->p_sib->p_prevsib = &p->p_sib;
- self_proc->p_ochild = p;
- p->p_loginleader = 1;
- p->p_ochild = 0;
- p->p_parentset = 1;
- p->p_noowner = 0;
- }
- else
- {
- p->p_id = &nullids;
- p->p_id->i_refcnt++;
-
- /* Our parent is init for now */
- p->p_parent = startup_proc;
-
- p->p_sib = startup_proc->p_ochild;
- p->p_prevsib = &startup_proc->p_ochild;
- if (p->p_sib)
- p->p_sib->p_prevsib = &p->p_sib;
- startup_proc->p_ochild = p;
- p->p_loginleader = 0;
- p->p_ochild = 0;
- p->p_parentset = 0;
- p->p_noowner = 1;
- }
+ p->p_parent = p;
+ p->p_sib = 0;
+ p->p_prevsib = &p->p_ochild;
+ p->p_ochild = p;
+ p->p_parentset = 1;
- if (p->p_pid < 2)
- boot_setsid (p);
- else
- p->p_pgrp = startup_proc->p_pgrp;
+ p->p_deadmsg = 1; /* Force initial "re-"fetch of msgport. */
- p->p_msgport = MACH_PORT_NULL;
+ p->p_noowner = 0;
+ p->p_id = make_ids (&zero, 1);
+ assert (p->p_id);
- condition_init (&p->p_wakeup);
+ p->p_loginleader = 1;
+ p->p_login = malloc (sizeof (struct login) + strlen (rootsname) + 1);
+ assert (p->p_login);
- p->p_argv = p->p_envp = p->p_status = 0;
+ p->p_login->l_refcnt = 1;
+ strcpy (p->p_login->l_name, rootsname);
- p->p_exec = 0;
- p->p_stopped = 0;
- p->p_waited = 0;
- p->p_exiting = 0;
- p->p_waiting = 0;
- p->p_traced = 0;
- p->p_nostopcld = 0;
- p->p_deadmsg = (p->p_pid == 1);
- p->p_checkmsghangs = 0;
- p->p_msgportwait = 0;
- p->p_dead = 0;
-
- if (p->p_pid > 1)
+ boot_setsid (p);
+
+ return p;
+}
+
+/* Request a dead-name notification for P's task port. */
+
+void
+proc_death_notify (struct proc *p)
+{
+ error_t err;
+ mach_port_t old;
+
+ err = mach_port_request_notification (mach_task_self (), p->p_task,
+ MACH_NOTIFY_DEAD_NAME, 1,
+ p->p_pi.port_right,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &old);
+ assert_perror (err);
+
+ if (old != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), old);
+}
+
+/* Complete a new process that has been allocated but not entirely initialized.
+ This gets called for every process except startup_proc (PID 1). */
+void
+complete_proc (struct proc *p, pid_t pid)
+{
+ /* Because these have a reference count of one before starting,
+ they can never be freed, so we're safe. */
+ static struct login *nulllogin;
+ static struct ids nullids = { i_refcnt : 1, i_nuids : 0};
+ const char nullsname [] = "<none>";
+
+ if (!nulllogin)
{
- add_proc_to_hash (p);
- join_pgrp (p);
+ nulllogin = malloc (sizeof (struct login) + sizeof (nullsname) + 1);
+ nulllogin->l_refcnt = 1;
+ strcpy (nulllogin->l_name, nullsname);
}
- return p;
+ p->p_pid = pid;
+
+ ids_ref (&nullids);
+ p->p_id = &nullids;
+
+ p->p_login = nulllogin;
+ p->p_login->l_refcnt++;
+
+ /* Our parent is init for now. */
+ p->p_parent = startup_proc;
+
+ p->p_sib = startup_proc->p_ochild;
+ p->p_prevsib = &startup_proc->p_ochild;
+ if (p->p_sib)
+ p->p_sib->p_prevsib = &p->p_sib;
+ startup_proc->p_ochild = p;
+ p->p_loginleader = 0;
+ p->p_ochild = 0;
+ p->p_parentset = 0;
+
+ p->p_noowner = 1;
+
+ p->p_pgrp = startup_proc->p_pgrp;
+
+ proc_death_notify (p);
+ add_proc_to_hash (p);
+ join_pgrp (p);
}
+
+/* Create a process for TASK, which is not otherwise known to us
+ and initialize it in the usual ways. */
+static struct proc *
+new_proc (task_t task)
+{
+ struct proc *p;
+
+ p = allocate_proc (task);
+ if (p)
+ complete_proc (p, genpid ());
+ return p;
+}
+
/* The task associated with process P has died. Drop most state,
and then record us as dead. Our parent will eventually complete the
deallocation. */
@@ -657,20 +710,19 @@ process_has_exited (struct proc *p)
prociterate ((void (*) (struct proc *, void *))check_message_dying, p);
- /* Nuke external send rights and the (possible) associated reference */
+ /* Nuke external send rights and the (possible) associated reference. */
ports_destroy_right (p);
if (!--p->p_login->l_refcnt)
free (p->p_login);
- if (!--p->p_id->i_refcnt)
- free_ids (p->p_id);
+ ids_rele (p->p_id);
/* Reparent our children to init by attaching the head and tail
- of our list onto init's. */
+ of our list onto init's. */
if (p->p_ochild)
{
- struct proc *tp; /* will point to the last one */
+ struct proc *tp; /* will point to the last one. */
int isdead = 0;
/* first tell them their parent is changing */
@@ -690,7 +742,7 @@ process_has_exited (struct proc *p)
!tp->p_pgrp->pg_orphcnt);
tp->p_parent = startup_proc;
- /* And now nappend the lists. */
+ /* And now append the lists. */
tp->p_sib = startup_proc->p_ochild;
if (tp->p_sib)
tp->p_sib->p_prevsib = &tp->p_sib;
@@ -707,6 +759,9 @@ process_has_exited (struct proc *p)
condition_broadcast (&p->p_wakeup);
p->p_dead = 1;
+
+ /* Cancel any outstanding RPCs done on behalf of the dying process. */
+ ports_interrupt_rpcs (p);
}
void
@@ -717,7 +772,7 @@ complete_exit (struct proc *p)
remove_proc_from_hash (p);
if (p->p_task != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), p->p_task);
+ mach_port_destroy (mach_task_self (), p->p_task);
/* Remove us from our parent's list of children. */
if (p->p_sib)
@@ -740,7 +795,7 @@ struct proc *
add_tasks (task_t task)
{
mach_port_t *psets;
- u_int npsets;
+ size_t npsets;
int i;
struct proc *foundp = 0;
@@ -749,7 +804,7 @@ add_tasks (task_t task)
{
mach_port_t psetpriv;
mach_port_t *tasks;
- u_int ntasks;
+ size_t ntasks;
int j;
if (!foundp)
@@ -759,6 +814,12 @@ add_tasks (task_t task)
for (j = 0; j < ntasks; j++)
{
int set = 0;
+
+ /* The kernel can deliver us an array with null slots in the
+ middle, e.g. if a task died during the call. */
+ if (! MACH_PORT_VALID (tasks[j]))
+ continue;
+
if (!foundp)
{
struct proc *p = task_find_nocreate (tasks[j]);
@@ -773,19 +834,16 @@ add_tasks (task_t task)
if (!set)
mach_port_deallocate (mach_task_self (), tasks[j]);
}
- vm_deallocate (mach_task_self (), (vm_address_t) tasks,
- ntasks * sizeof (task_t));
+ munmap (tasks, ntasks * sizeof (task_t));
mach_port_deallocate (mach_task_self (), psetpriv);
}
mach_port_deallocate (mach_task_self (), psets[i]);
}
- vm_deallocate (mach_task_self (), (vm_address_t) psets,
- npsets * sizeof (mach_port_t));
+ munmap (psets, npsets * sizeof (mach_port_t));
return foundp;
}
-/* Allocate a new pid. The first two times this is called it must return
- 0 and 1 in order; after that it must simply return an unused pid.
+/* Allocate a new unused PID.
(Unused means it is neither the pid nor pgrp of any relevant data.) */
int
genpid ()
@@ -795,24 +853,16 @@ genpid ()
static int nextpid = 0;
static int wrap = WRAP_AROUND;
- int wrapped = 0;
-
- while (!pidfree (nextpid))
+ while (nextpid < wrap && !pidfree (nextpid))
+ ++nextpid;
+ if (nextpid >= wrap)
{
- ++nextpid;
- if (nextpid > wrap)
- {
- if (wrapped)
- {
- wrap *= 2;
- wrapped = 0;
- }
- else
- {
- nextpid = START_OVER;
- wrapped = 1;
- }
- }
+ nextpid = START_OVER;
+ while (!pidfree (nextpid))
+ nextpid++;
+
+ while (nextpid > wrap)
+ wrap *= 2;
}
return nextpid++;