diff options
Diffstat (limited to 'proc/mgt.c')
-rw-r--r-- | proc/mgt.c | 484 |
1 files changed, 267 insertions, 217 deletions
@@ -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++; |