diff options
Diffstat (limited to 'proc')
-rw-r--r-- | proc/ChangeLog | 867 | ||||
-rw-r--r-- | proc/Makefile | 4 | ||||
-rw-r--r-- | proc/cpu-types.c | 38 | ||||
-rw-r--r-- | proc/hash.c | 53 | ||||
-rw-r--r-- | proc/host.c | 371 | ||||
-rw-r--r-- | proc/info.c | 285 | ||||
-rw-r--r-- | proc/main.c | 70 | ||||
-rw-r--r-- | proc/mgt.c | 484 | ||||
-rw-r--r-- | proc/msg.c | 55 | ||||
-rw-r--r-- | proc/notify.c | 12 | ||||
-rw-r--r-- | proc/pgrp.c | 115 | ||||
-rw-r--r-- | proc/primes.c | 135 | ||||
-rw-r--r-- | proc/proc.h | 77 | ||||
-rw-r--r-- | proc/stubs.c | 208 | ||||
-rw-r--r-- | proc/wait.c | 183 |
15 files changed, 1137 insertions, 1820 deletions
diff --git a/proc/ChangeLog b/proc/ChangeLog deleted file mode 100644 index 0b5159c4..00000000 --- a/proc/ChangeLog +++ /dev/null @@ -1,867 +0,0 @@ -Sun Jul 28 22:57:03 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (get_string_array): Correctly adjust NEWSIZE when - reallocating to add very long strings. - -Sat Jul 20 10:08:05 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * msg.c (S_proc_getmsgport): Deal with PID dying while we're waiting. - -Fri Jul 19 18:22:46 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * msg.c (S_proc_setmsgport): Bother to request DEAD_NAME - notification on new message port being installed. - -Thu Jul 18 13:23:51 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * msg.c (S_proc_setmsgport): Use MOVE_SEND, not COPY_SEND, to - return the old message port to the caller. - - * mgt.c (S_proc_handle_exceptions): Release newly created reference - on E when we are done with it. - (S_proc_child): Deallocate our ref on childt once we know we will - return success. - (S_proc_reassign): Likewise for NEWT. - - * main.c (main): Don't wire proc anymore. It's not necessary or - useful. - -Thu Jul 18 04:15:49 1996 Roland McGrath <roland@baalperazim.frob.com> - - * mgt.c (add_tasks): Fix vm_deallocate call to use mach_task_self () - instead of mach_host_self (). - -Tue Jul 16 11:34:34 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (EWOULDBLOCK): Define to work around new libc bug. - -Sun Jul 7 21:04:03 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Don't use unsafe MOVE_SEND in - user-side interruptible RPC. - -Wed Jul 3 14:44:00 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (process_has_exited): When reparenting children to init, - if one of them is dead, alert init. - -Fri Jun 28 11:54:21 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * proc.h (check_owner): Return true any time PROC1 has root. - -Thu May 30 19:11:31 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * pgrp.c (S_proc_getsidport): MAKE_SEND_ONCE -> MAKE_SEND. - -Wed May 29 11:35:37 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Get rid of temp hack for strnlen. - -Fri May 24 15:50:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Set PI->exitstatus and PI->sigcode. - - * mgt.c (process_has_exited): Don't call alert_parent if P->p_task - is null (which happens only if this is the stub process in - proc_reassign). This because the parent is uninvolved in the - death of stubp. - -Wed May 22 17:47:15 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * stubs.c (send_signal): Send sigcode in message. - - * msg.c (S_proc_setmsgport): Add OLDMSGPORT_TYPE param. - -Tue May 14 22:50:49 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * proc.h (check_owner): New inline function. - * info.c (S_proc_pid2task, S_proc_pid2proc): Use check_owner. - -Sun May 12 13:22:04 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (PI_FETCH_THREAD_DETAILS): New macro. - (S_proc_getprocinfo): Only allocate thread detail storage if we're - actually returning thread details (a lone PI_FETCH_THREADS simply - means "number of threads"). React to errors somewhat more gracefully. - - * info.c (S_proc_getprocinfo): Add comment. - -Fri May 10 16:32:17 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_get_tty): New function. - -Fri May 10 09:26:53 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (S_proc_exception_raise): Fetch sigcode from correctly - named member of HSD. - -Thu May 9 19:13:14 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Use new authentication - interface. - - * mgt.c (S_proc_setowner): Expect and interpret new CLEAR parm. - - * info.c (S_proc_getprocinfo): FLAGS is now an in-out parameter. - - * proc.h (struct proc): Add p_sigcode. - * wait.c (S_proc_wait): New parm SIGCODE; return p_sigcode in it. - (S_proc_mark_stop): New parm SIGCODE; record it. - (S_proc_mark_exit): Likewise. - (alert_parent): Set P->p_sigcode if process is dying irregularly. - * mgt.c (S_proc_exception_raise): Set P->p_sigcode; use new - _hurd_exception2signal args. - -Mon May 6 14:23:11 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * proc.h (OUR_VERSION): Upgrade to 0.0. - -Tue Apr 30 16:48:49 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Release GLOBAL_LOCK around time - consuming bits, and more importantly, potential calls to P's - msgport, which can block. - Fix test when appending to WAITS. - -Mon Apr 29 16:58:24 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Install temporary hack so things at - least compile. Turned on thread_waits code. - -Mon Apr 15 13:51:41 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (process_has_exited): Clear p->p_waited. - -Fri Mar 29 09:38:28 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (S_proc_wait): When looking for a specific pid, use - pid_find_allow_zombie, not ordinary pid_find. - - * mgt.c (S_proc_reassign): Use new ports_transfer_right call - instead of claim/install sequence; the latter has leaves the port - out of any hash table for a time, which produces a race with - incoming messages. - -Thu Mar 28 09:21:16 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (S_proc_reassign): Make send once right directly from - value in P->p_pi, don't use ports_get_right. - - * mgt.c (process_has_exited): Inhibit this call from happening - twice. - - * info.c (S_proc_pid2task): Return MACH_PORT_NULL for a zombie. - (S_proc_pid2proc): Likewise. - - * Makefile (mutated_ourmsg_U.h): New target. - * mgt.c: Include mutated_ourmsg_U.h instead of ourmsg_U.h. - * pgrp.c: Likewise. - - * wait.c: Don't include ourmsg_U.h or process_reply_U.h. - * msg.c: Don't include process_reply_U.h. - - * msg.c (S_proc_getmsgport): Allow call to be made for dead - processes; they'll return null. Thank you, Mr. Posix. - * mgt.c (process_has_exited): Null out P->p_msgport and drop - reference. - - * wait.c (S_proc_wait): Return EOPNOTSUPP if RPC destination is - not a valid process. - (S_proc_mark_stop): Likewise. - (S_proc_mark_exit): Likewise. - (S_proc_mark_cont): Likewise. - (S_proc_mark_traced): Likewise. - (S_proc_mod_stopchild): Likewise. - * msg.c (S_proc_setmsgport): Likewise. - (S_proc_getmsgport): Likewise. - * pgrp.c (S_proc_setsid): Likewise. - (S_proc_getsidport): Likewise. - (S_proc_setpgrp): Likewise. - (S_proc_mark_exec): Likewise. - * mgt.c (S_proc_reauthenticate): Likewise. - (S_proc_child): Likewise. - (S_proc_reassign): Likewise. - (S_proc_setowner): Likewise. - (S_proc_getpids): Likewise. - (S_proc_set_arg_locations): Likewise. - (S_proc_dostop): Likewise. - * info.c (S_proc_pid2task): Likewise. - (S_proc_proc2task): Likewise. - (S_proc_pid2proc): Likewise. - (S_proc_make_login_coll): Likewise. - (S_proc_setlogin): Likewise. - (S_proc_getlogin): Likewise. - * host.c (S_proc_sethostid): Likewise. - (S_proc_sethostname): Likewise. - (S_proc_getprivports): Likewise. - (S_proc_setexecdata): Likewise. - - * proc.h (process_drop): New (inline) function. - * hash.c (reqport_find): Only deallocate newly found reference - if process is dead. - * Makefile (MIGSTUBS): Delete process_replyUser.c. - (MIGSFLAGS): Provide new definition. - * msg.c (S_proc_setmsgport): Spawn thread to tickle init instead - of sending reply here. - (tickle_init): New function. - -Mon Mar 25 17:02:04 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * Makefile (proc): Add libshouldbeinlibc.a. - * main.c: Include <wire.h>. - (main): Use wire_task_self instead of doing it ourselves. - -Thu Mar 21 11:59:29 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (S_proc_wait) [child_ready]: Flip test of waited flag. - * mgt.c (new_proc): Oops, reinstall code to request dead name - notification on the task port. - -Wed Mar 20 10:41:01 1996 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * pgrp.c (S_proc_setpgrp): Delete bletcherous hack from July 22, - 1995. - - -- All these changes get rid of zombies and integrate them - into the regular process tables. -- - * proc.h (struct zombie): Delete type. - (zombie_list): Delete variable. - * hash.c (pid_find): Return 0 if process is dead. - (task_find): Likewise. - (task_find_nocreate): Likewise. - (pidfree): Don't call zombie_check_pid. Call - pid_find_allow_zombie instead of pid_find. - (pid_find_allow_zombie): New function. - (prociterate): Don't call FUN for dead processes. - * mgt.c (new_proc): Initialize P->p_dead. - (process_has_exited): Don't call reparent_zombies. Set P->p_dead. - Don't remove from hash tables here, delete ref to task port or - remove from parent's list of children (now in - complete_exit). Don't remove from pgrp here. - (complete_exit): New function. - * wait.c (alert_parent): Don't create zombie. - (reparent_zombies): Delete function. - (S_proc_wait): Don't scan zombie list; check dead children at the - same time as stopped children. When completing wait on a dead - child, call complete_exit after we've finished work. - (zombie_check_pid): Delete function. - * proc.h (complete_exit): Provide prototype. - - -- All these changes make proc multithreaded - and use the ports library in the usual fashion - (well, almost the usual fashion) -- - * Makefile (proc): Mention ../libports/libports.a. - * hash.c (porthash, exchash): Delete variables. - (reqport_find): Use ports library instead of porthash. - (add_proc_to_hash): Don't add to porthash. - (remove_proc_from_hash): Don't remove from porthash. - (exc_find, remove_exc_from_hash): Delete functions. - * mgt.c (new_proc): Allocate new proc structure with - ports_create_port. Don't frob P->p_reqport. - (process_has_exited): Don't frob P->p_reqport, cal - ports_destry_right instead. - * proc.h (proc_bucket, proc_class): New variables. - (request_portset): Delete variable. - * proc.h (struct proc): Delete members `p_reqport' and - p_porthashloc. Add member `p_pi'. - * Makefile (MIGSFLAGS): Delete variable. - * proc.h (global_lock): New variable. - * main.c (global_lock): Provide definition. - (message_demuxer): Lock global_lock around work. - (main): Initialize proc_bucket and proc_class instead of - request_portset. Initialize generic_port through ports - library calls. Fetch startup procserver port through ports - library instead of reading p_reqport. Initialize exc_class. - * mgt.c (S_proc_reauthenticate) Likewise. - - * proc.h: Include <hurd/ports.h> and <cthreads.h>. - * info.c (S_proc_task2proc): Use ports_get_right instead - of p_reqport. - (S_proc_pid2proc): Likewise. - * proc.h (exc_port_class): New variable. - (struct exc): Add member `pi'. Remove member `excport'. - * mgt.c (S_proc_handle_exceptions): Allocate using - ports library. - (S_proc_exception_raise): Use ports library to manage - structure. - (exc_clean): New function. - - -*** - - -- All these changes switch to using condition variables - for wakeup instead of explicit block code -- - * mgt.c (new_proc): Initialize P->p_wakeup. - * wait.c (waiting_parent_cares): Delete function. - * Makefile (MIGSTUBS): Delete interruptServer.o. - * main.c (message_demuxer): Remove call to interrupt_server. - Add call to ports_interrupt_server. - * wait.c: Don't include "interrupt_S.h". - (alent_parent): Unconditionally enqueue zombie. - (S_interrupt_operation): Delete function. - (abort_wait): Delete function. - * msg.c (abort_getmsgport): Delete function. - * wait.c (alert_parent): Use condition_broadcast instead of - continuation stuff. - (reparent_zombies): Likewise. - (S_proc_mark_stop): Likewise. - * msg.c (check_message_return): Likewise. - (check_message_dying): Likewise. - * wait.c (S_proc_wait): Use condition_wait instead of continuation - stuff; never return EBUSY. - * msg.c (S_proc_getmsgport): Likewise. - * proc.h (struct proc): New member `p_wakeup'. Delete member - `p_continuation'. - - - -Mon Feb 12 14:13:55 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Fail reasonably for #ifdef'd-out - thread waits code. - -Fri Feb 9 15:45:07 1996 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Support returning wait strings. - -Fri Feb 9 15:19:14 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * mgt.c (S_proc_exception_raise): Rewritten. - (S_proc_handle_exceptions): Don't set E->replyport. - (S_proc_exception_raise_reply): Function removed. - * main.c (message_demuxer): Don't call proc_excrepl_server. - * proc_excrepl.defs: File removed. - * Makefile (DIST_FILES): Remove proc_excrepl.defs. - (MIGSTUBS): Remove its objects. - * proc_exc.defs: Add msgoption arg. - Use integer_t where appropriate. - * notify.c (do_mach_notify_no_senders): Don't use E->replyport. - * proc.h (struct exc): Removed useless members `replyport', - `replyporttype'. - -Wed Dec 20 17:29:13 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * mgt.c (S_proc_reassign): Have notifications sent to the correct - request port. - Once we've given STUBP's request port to P, don't leave it in - STUBP, so process_has_exited() doesn't dealloc it. - - * pgrp.c (S_proc_getsidport): Add and use new arg sessport_type. - -Wed Dec 20 13:31:01 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (new_proc): Don't set P->p_noowner for processes 0 and 1. - -Wed Dec 20 13:09:04 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * info.c (get_vector): Rewritten without arbitrary limits. - -Tue Dec 19 18:14:30 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * pgrp.c (free_session): Correctly get rid of the receive right - we're holding. - (S_proc_getsidport): Return errors. - -Tue Dec 19 13:58:59 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * info.c (get_string_array): Fix stupid bug in copying to newly - allocated space. - -Tue Dec 19 13:17:46 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Reverse miles' last change. - -Mon Dec 18 19:56:03 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Don't return 0 for the new port. - -Tue Nov 21 13:50:30 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (S_interrupt_operation): Include new seqno parameter. - -Tue Nov 14 13:15:55 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (S_proc_wait): `p->msgportwait' ==> `p->p_msgportwait' - typo fix. - -Thu Nov 9 13:01:28 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * msg.c (S_proc_setmsgport): Only do the RPC reply by hand for - init. Also, return the correct port in that by-hand reply. - - * msg.c (S_proc_getmsgport): Also return EBUSY if P->waiting, - because both share the same memory in the proc structure. - * wait.c (S_proc_wait): Likewise, mutatis mutandis. - -Wed Nov 8 13:10:27 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Don't attempt msg_report_wait if - P->p_msgport is not valid. - - * info.c (S_proc_getprocinfo): Inhibit PI_FETCH_THREAD_WAITS for - now. - -Tue Nov 7 19:49:32 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Calculate the size of the returned - structure correctly. - -Sun Nov 5 02:05:10 1995 Miles Bader <miles@gnu.ai.mit.edu> - - * proc.h: Include <sys/resource.h>. - - * info.c (S_proc_getprocinfo): Add NOISE and NOISE_LEN args. - Fix various typos. Initialize ERR. - -Tue Oct 31 14:19:04 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * wait.c (struct zombie): Deleted; now in proc.h. - (zombie_list): Likewise. - * proc.h (struct zombie): New type. - (zombie_list): New variable. - - * info.c (S_proc_getprocinfo): Implement all the rest of the PI - flags except PI_ZOMBIE. - -Mon Oct 30 16:22:49 1995 Michael I. Bushnell, p/BSG <mib@gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): Support new FETCH flags; support - new msg_report_wait call; improve organization. - - * info.c (S_proc_getprocenv): Removed #ifdef notyet; fixed args to - get_string_array. - -Sat Sep 16 12:57:31 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * ourmsg.defs: New file. - * Makefile (DIST_FILES): Added ourmsg.defs. - (ourmsg_U.h ourmsgUser.c, ourmsg.defs): Targets removed. - -Thu Aug 24 10:38:58 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> - - * Makefile (MIGSTUBS): New variable. - (OBJS): Get the mig stubs from $(MIGSTUBS). - -Wed Aug 23 14:25:30 1995 Miles Bader <miles@churchy.gnu.ai.mit.edu> - - * Makefile (proc): Put all dependencies here. - (HURDLIBS, REMHDRS): Removed. - (OBJS): Calculate the appropiate bits from $(SRCS). - -Sat Jul 22 15:04:52 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * wait.c (zombie_check_pid): Examine Z->pgrp too. - - * pgrp.c (S_proc_setpgrp): Install bletcherous hack. - -Thu Jul 6 15:41:22 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * hash.c: "ihash.h" -> <hurd/ihash.h>. - - * Makefile (ourmsg_U.h ourmsgUser.c): Use local ourmsg.defs - instead of include file directly. - (ourmsg.defs): New target. - - * Makefile: Removed dependencies that are now automatically - generated. - -Tue Jun 27 12:02:47 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * mgt.c (S_proc_dostop): Remove assigments from inside if tests. - -Tue Jun 6 13:24:51 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * Makefile (OBJS): Removed ihash.o and primes.o. - (CPPFLAGS): Deleted addition of -I../lib. - (vpath): Deleted spec. - (REMHDRS): Added ../libihash/ihash.h. - (HURDLIBS): Added libihash. - -Wed Apr 26 14:32:19 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * wait.c (S_proc_wait): Use `waiter_cares', not - `waiting_parent_cares' in zombie check. - -Tue Apr 18 09:30:13 1995 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu> - - * wait.c (reparent_zombies): Send SIGCHLD signal to init. - - * wait.c (S_proc_wait): Don't return ESRCH; return ECHILD. - -Wed Apr 12 14:36:30 1995 Michael I Bushnell <mib@duality.gnu.ai.mit.edu> - - * Makefile (SRCS): Omit primes.c (it's moved to the lib dir). - -Thu Apr 6 14:29:06 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * info.c (S_proc_getprocinfo): New var `tp'. Bother to set - PI->logincollection. - -Wed Apr 5 20:32:02 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * wait.c (waiter_cares, waiting_parent_cares): New functions. - (alert_parent, reparent_zombies, S_proc_wait, S_proc_mark_stop): - Use them. - -Tue Apr 4 14:36:36 1995 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * main.c (main): Wire text and data segment on startup to avoid - failure mode during non-standalone pseudo-crash. - -Tue Mar 14 11:55:00 1995 Miles Bader <miles@geech.gnu.ai.mit.edu> - - * hash.c (addhash, findhash): Moved to ihash.c (which is has a more - generic interface) and renamed ihash_add & ihash_find; all callers - changed. Other changes: struct htable becomes struct ihash, and - all routines that previously deleted things explicitly use - ihash_locp_remove instead. - -Thu Jan 19 02:01:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * pgrp.c (S_proc_setpgrp): Use nowait_msg_proc_newids instead of - nowait_proc_newids. - * mgt.c (S_proc_child): Likewise. - -Tue Jan 17 17:48:32 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * mgt.c (check_uid): Return true if P has root. - - * proc.h (struct proc): Make `argv' and `envp' members - `vm_address_t'. - -Thu Nov 3 12:13:49 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * mgt.c (S_proc_getallpids): Don't dereference PIDS in call - to vm_allocate. - - * info.c (S_proc_getprocinfo): Don't take address of PIARRAY - in call to vm_allocate. Dereference PIARRAY in call to - vm_deallocate. - -Fri Oct 14 04:54:46 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * mgt.c (new_proc): Don't assume MACH_PORT_NULL is zero. - (genpid): Deal with all pids between STAR_OVER and WRAP_AROUND - being used. - -Mon Oct 10 14:23:00 1994 Jim Blandy <jimb@geech.gnu.ai.mit.edu> - - * primes.c (nextprime): Doc fix. - -Mon Oct 10 02:18:02 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * host.c (rebuild_uname): If all the server versions after [0] - (the microkernel) match, merge them all into one "Hurd-VERSION" - element in the uname version string. - -Sun Oct 2 20:36:57 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * host.c (S_proc_sethostname): Don't write off end of - uname_info.nodename. - (rebuild_uname): Rewritten. - (initialize_version_info): Write Mach version info as first - element of server_versions. - (machversion): Variable removed. - -Sat Sep 10 11:37:32 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * mgt.c (make_ids): Copy from UIDS and GIDS into newly allocated - space, not vice versa. - -Wed Aug 31 11:03:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * mgt.c (S_proc_reassign): Rather than getting a new request port, - preserve STUBP's request port. This is more convenient for - users (and equally good security), and it's what the protocol spec - says anyway. - -Tue Aug 30 12:44:37 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * primes.c: Replaced file with new version from Jim Blandy - (jimb@gnu.ai.mit.edu), David Carlton (carlton@math.mit.edu). - - * proc.h (check_dead_execdata_notify): Add prototype. - -Mon Aug 29 12:53:27 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Use new authentication protocol. - -Tue Aug 23 11:41:26 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * pgrp.c (S_proc_setpgrp): If we don't actually change the pgrp, - still send proc_newids; the library depends on always getting it. - -Mon Aug 22 17:09:21 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * wait.c (S_proc_mark_stop): Removed now meaningless assert. - - * info.c (S_proc_getloginpids): Compute size in realloc correctly. - -Mon Aug 22 13:29:21 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * wait.c (S_proc_mod_stopchild): Negate VALUE; sense of - p_nostopcld flag is opposite of flag value described in process.defs. - -Fri Aug 19 10:21:57 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * pgrp.c (S_proc_getpgrppids): Understand PGID of zero as meaning - caller's pgrp. - - * mgt.c (S_proc_child): Check CHILDP->p_msgport against - MACH_PORT_NULL explicitly. - - * pgrp.c (join_pgrp): If pg->pg_orphcnt has significantly changed, - then notify all the processes in the pgrp. - (leave_pgrp): Only send newids message if ip->p_msgport is set. - * mgt.c (S_proc_child): Becase join_pgrp now always sends - newids; don't do it here if we called join_pgrp. - -Fri Aug 19 04:53:04 1994 Roland McGrath <roland@churchy.gnu.ai.mit.edu> - - * pgrp.c (leave_pgrp): Fix swapped args to nowait_proc_newids. - (join_pgrp): Call nowait_proc_newids to notify the process. - -Thu Aug 18 10:40:13 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * mgt.c (S_proc_reauthenticate): Use MACH_MSG_TYPE_MAKE_SEND - to create a send right from P->p_reqport. - - * main.c (main): Removed var `authhandle'. Use global - `authserver' instead. - -Wed Aug 17 14:02:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * host.c (init_stdarrays): Removed function. - (S_proc_execdata_notify): Never call init_stdarrays. - Only call exec_setexecdata if std_port_array is set. - (S_proc_getexecdata): Return error if there is no std_port_array. - -Mon Aug 15 16:12:22 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * host.c (check_dead_execdata_notify): New function. - * notify.c (do_mach_notify_dead_name): For notifications sent - to GENERIC_PORT, call check_dead_execdata_notify. - * main.c (main): Create GENERIC_PORT and put it in - REQUEST_PORTSET. - - * host.c (init_stdarrays): New function. - (S_proc_execdata_notify): Call init_stdarrays the first time. - (S_proc_getexecdata): Likewise. - - * host.c: Include <hurd.h> for various frobs. Include - <unistd.h> for getpid. - -Fri Jul 22 11:01:53 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * Makefile: Rewritten in accord with new scheme. - * wait.c: Include "ourmsg_U.h" instead of "msg.h". - Include "process_reply_U.h" instead of "process_reply.h". - Include "process_S.h" instead of "proc_S.h". - * mgt.c: Include "proc_exc_U.h" instead of "proc_exc.h". - Include "proc_excrepl_U.h" insted of "proc_excrepl.h". - Include "ourmsg_U.h" instead of "msg.h". - Include "process_S.h" instead of "proc_S.h". - * pgrp.c: Include "process_S.h" instead of "proc_S.h". - Include "ourmsg_U.h" instead of "msg.h". - * msg.c: Include "process_reply_U.h" instead of "process_reply.h". - * host.c: Include "process_S.h" instead of "proc_S.h". - * info.c: Likewise. - -Wed Jul 20 16:18:31 1994 Michael I Bushnell <mib@geech.gnu.ai.mit.edu> - - * wait.c (alert_parent): Delete unused variable `err'. - -Tue Jul 19 12:45:43 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * Makefile (proc): Don't use variable $(link) anymore. - -Mon Jul 11 14:32:17 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * pgrp.c (leave_pgrp): When pulling process off of pgrp list, - mutate *both* links. - (free_pgrp): When pulling pgrp off of session list, mutate - *both* links. - -Tue Jul 5 14:23:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * Makefile (TAGSLIBS, TAGSHDRS): New variables. - -Fri Jul 1 10:57:07 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * stubs.c (send_signal): Rewrote to be machine independent - and cleaner. - -Thu Jun 30 14:05:21 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * stubs.c: New file. - * wait.c (alert_parent): Call send_signal instead of nowait_sig_post. - (S_proc_mark_stop): Likewise. - * pgrp.c (leave_pgrp): Likewise. - * proc.h (send_signal): New prototype. - * Makefile (OBJS): Added stubs.o. - (SRCS): Added stubs.c. - (LIBS): New var to get cthreads library. - - * wait.c (alert_parent): Eliminate pointless assert with confusingly - incorrect comment. - - * hash.c (findhash): If we find a slot with ID matching the - one we're looking for, but it has been deleted, then return - 0 rather than HASH_DEL. - - * wait.c (S_proc_wait, reparent_zombies, alert_parent): Use - macros WAIT_ANY and WAIT_MYPGRP instead of magic values -1 - and 0. - - * wait.c (S_proc_wait): Implement correct interpretation of PID - argument: -1 means any child; 0 means child in the same pgrp. - [Incorrect semantics were in loop to search zombies, and loop - looking for stopped children] - (reparent_zombies): Likewise. [Incorrect semantics were in - PID check before returning startup_proc's wait.] - (alert_parent): Likewise. [Incorrect semantics were in - PID check before returning P->p_parent's wait.] - - * wait.c (S_proc_wait): Only return wait on stopped child if - it passes the PID test. - - * pgrp.c (S_proc_setpgrp): Don't do process group change if we are - changing into our own process group. - * mgt.c (S_proc_child): Likewise. - - * pgrp.c (S_proc_setpgrp): When PID is zero, act on calling - process; when PGID is zero, use pid of affected process. - (S_proc_setpgrp): EPERM check should succeed if pgid is the - affected process's *pid*, not pgrp. - -Thu Jun 30 08:40:35 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * mgt.c (S_proc_dostop): Use the proper allocation for task_threads. - Check for errors. Deallocate the send right from CONTTHREAD too. - - * wait.c (alert_parent): Send SIGCHLD to the parent. - -Tue Jun 28 18:12:43 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * primes.c: Include <assert.h>. - (nextprime): Use calloc instead of alloca, bzero. P might be - bigger than will fit on the stack. Assert non-null return - from calloc and realloc. - -Tue Jun 28 13:57:08 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * main.c (main): Set priority of proc server to 2 so that we - get more CPU than ordinary programs. - -Fri Jun 24 17:29:55 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * hash.c (struct htable): New member `locps'. - (addhash): Store LOCP into hash table for use during rehash. - During rehash, then provide correct LOCP parm for old elements. - Allocate and free HT->locps as appropriate. - -Fri Jun 24 04:15:16 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * mgt.c (S_proc_setprocargs): Renamed to S_proc_set_arg_locations. - (S_proc_get_arg_locations): New function. - -Mon Jun 20 15:07:00 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * Makefile (install): Use $(INSTALL_BIN) instead of cp. - -Fri Jun 17 13:00:27 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * mgt.c (S_proc_child): Reverse Roland's change of June 11. - -Sat Jun 11 11:20:16 1994 Roland McGrath (roland@geech.gnu.ai.mit.edu) - - * mgt.c (S_proc_child): Inherit the argv and envp values from the - parent. - -Fri May 27 16:03:53 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * primes.c: Doc fix, with appreciation to Jim Blandy. - -Fri May 13 16:58:13 1994 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) - - * info.c (S_proc_getprocinfo): Only scan through the threads - if task_info succeeds. - - * info.c (S_proc_getprocinfo): Behave properly if one of the - threads has died in between the call to task_threads and the - calls to thread_info (just pretend it never existed). - - * info.c (get_string, get_vector, S_proc_getprocinfo): If the task - has died (there's a race between pending requests and processing - of dead-name notifications) then convert MACH_SEND_INVALID_DEST to - ESRCH. - -Thu May 12 00:59:03 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * main.c (main): Take three args. Store ARGV and ENVP in SELF_PROC. - - * info.c (S_proc_getprocargs): Remove `#ifdef notyet's. - (get_string, get_vector, get_string_array): Functions exposed. - (get_string_array): Set BP before the loop. Use a for loop that - iterates over elts in VECTOR. Fix check of LEN to reallocate buffer. - (S_proc_getprocargs): Cast BUF to vm_address_t * for get_string_array. - (get_vector): Fix pointer arithmetic; break out of loop when done. - Check for error from malloc. - (get_string): Use memchr for scanning. Check for error from - malloc. Pass READLEN correctly to vm_deallocate. - - * msg.c (S_proc_setmsgport): Take new reply port args. - Send reply before trying startup_essential_task. - Include <hurd/startup.h> to declare startup_essential_task. - - * cpu-types.c: New file. - * Makefile (SRCS, OBJS): Add it. - * host.c: Include <stdio.h> for sprintf. - (rebuild_uname): Removed unused variable J. - (S_proc_register_version): Fix arg types. - Use master_host_port, not host_priv. - Remove unused variable J. - (server_versions): Fix syntax errors in struct definition. - (S_proc_uname): Fixed type of first arg. - (rebuild_uname): Fix typo. - (initialize_version_info): Cast args to host_info. - (initialize_version_info): Allocate space for machversion. - -Mon May 9 14:32:37 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * mgt.c (new_proc): Regard init as having a dead message - port initially. - - * msg.c (S_proc_setmsgport): When init chimes in, tell it - we are essential. - - * proc.h (OUR_VERSION, OUR_SERVER_NAME): New macros. - * host.c (uname_info, machversion, server_versions, - nserver_versions, server_version_nalloc): New variables. - (S_proc_register_version, rebuild_uname, initialize_version_info, - S_proc_uname): New functions. - (S_proc_sethostname): Also set uname_info.nodename. - * main.c (main): Call initialize_version_info. - -Fri May 6 13:00:36 1994 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) - - * host.c (S_proc_gethostname): If HOSTNAME is null, return - an empty hostname instead of crashing. - (S_proc_gethostname): Test buffer length properly; allocate - space for the null too. - - * mgt.c (process_has_exited): delete unused variable LAST. - * msg.c (check_message_return): delete unused variables I, - MSGPORTS, and CP. Changed type of second arg to `void *' - so that the function type is appropriate for the first arg - to prociterate. - (check_message_dying): delete unused variable I. - - * wait.c, host.c, info.c, mgt.c, notify.c, pgrp.c: Changed MiG - server stubs' return types from error_t to kern_return_t; the - types are incompatible right now. - -Thu May 5 07:50:24 1994 Roland McGrath (roland@churchy.gnu.ai.mit.edu) - - * Makefile: Change uses of $(headers) to $(includedir). - diff --git a/proc/Makefile b/proc/Makefile index b666c4f7..a1159700 100644 --- a/proc/Makefile +++ b/proc/Makefile @@ -31,9 +31,7 @@ MIGSFLAGS="-DPROCESS_INTRAN=pstruct_t reqport_find (process_t)" \ MIGSTUBS = processServer.o notifyServer.o \ ourmsgUser.o proc_excUser.o proc_excServer.o OBJS = $(SRCS:.c=.o) $(MIGSTUBS) - -proc: $(OBJS) ../libthreads/libthreads.a ../libihash/libihash.a \ - ../libports/libports.a ../libshouldbeinlibc/libshouldbeinlibc.a +HURDLIBS=threads ihash ports shouldbeinlibc include ../Makeconf diff --git a/proc/cpu-types.c b/proc/cpu-types.c index f15387c7..7bcaa928 100644 --- a/proc/cpu-types.c +++ b/proc/cpu-types.c @@ -21,6 +21,18 @@ const char *const mach_cpu_types[] = [CPU_TYPE_SPARC] = "sparc", [CPU_TYPE_I860] = "i860", [CPU_TYPE_ALPHA] = "alpha", +#ifdef CPU_TYPE_I486 + [CPU_TYPE_I486] = "i486", +#endif +#ifdef CPU_TYPE_PENTIUM + [CPU_TYPE_PENTIUM] = "i586", +#endif +#ifdef CPU_TYPE_PENTIUMPRO + [CPU_TYPE_PENTIUMPRO] = "i686", +#endif +#ifdef CPU_TYPE_POWERPC + [CPU_TYPE_POWERPC] = "powerpc", +#endif }; const char *const mach_cpu_subtypes[][32] = @@ -67,14 +79,24 @@ const char *const mach_cpu_subtypes[][32] = [CPU_SUBTYPE_MMAX_XPC] = "MMAX_XPC", [CPU_SUBTYPE_PC532] = "PC532", }, - [CPU_TYPE_I386] = - { - [CPU_SUBTYPE_AT386] = "AT386", - [CPU_SUBTYPE_EXL] = "EXL", - [CPU_SUBTYPE_iPSC386] = "iPSC386", - [CPU_SUBTYPE_SYMMETRY] = "SYMMETRY", - [CPU_SUBTYPE_PS2] = "PS2", - }, +#define Ix86_SUBTYPES \ + { \ + [CPU_SUBTYPE_AT386] = "AT386", \ + [CPU_SUBTYPE_EXL] = "EXL", \ + [CPU_SUBTYPE_iPSC386] = "iPSC386", \ + [CPU_SUBTYPE_SYMMETRY] = "SYMMETRY", \ + [CPU_SUBTYPE_PS2] = "PS2", \ + } + [CPU_TYPE_I386] = Ix86_SUBTYPES, +#ifdef CPU_TYPE_I486 + [CPU_TYPE_I486] = Ix86_SUBTYPES, +#endif +#ifdef CPU_TYPE_PENTIUM + [CPU_TYPE_PENTIUM] = Ix86_SUBTYPES, +#endif +#ifdef CPU_TYPE_PENTIUMPRO + [CPU_TYPE_PENTIUMPRO] = Ix86_SUBTYPES, +#endif [CPU_TYPE_MIPS] = { [CPU_SUBTYPE_MIPS_R2300] = "R2300", diff --git a/proc/hash.c b/proc/hash.c index 85eb7c5d..ed670a16 100644 --- a/proc/hash.c +++ b/proc/hash.c @@ -1,5 +1,5 @@ /* Hash table functions - Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation This file is part of the GNU Hurd. @@ -20,6 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Written by Michael I. Bushnell. */ #include <mach.h> +#include <stddef.h> #include <sys/types.h> #include <hurd/hurd_types.h> #include <string.h> @@ -29,15 +30,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "proc.h" #include <hurd/ihash.h> -static struct ihash pghash, pidhash, taskhash, sidhash; +static struct hurd_ihash pghash + = HURD_IHASH_INITIALIZER (offsetof (struct pgrp, pg_hashloc)); +static struct hurd_ihash pidhash + = HURD_IHASH_INITIALIZER (offsetof (struct proc, p_pidhashloc)); +static struct hurd_ihash taskhash + = HURD_IHASH_INITIALIZER (offsetof (struct proc, p_taskhashloc)); +static struct hurd_ihash sidhash + = HURD_IHASH_INITIALIZER (offsetof (struct session, s_hashloc)); + /* Find the process corresponding to a given pid. */ struct proc * pid_find (pid_t pid) { struct proc *p; - p = ihash_find (&pidhash, pid); - return p->p_dead ? 0 : p; + p = hurd_ihash_find (&pidhash, pid); + return (!p || p->p_dead) ? 0 : p; } /* Find the process corresponding to a given pid. Return it even if @@ -45,7 +54,7 @@ pid_find (pid_t pid) struct proc * pid_find_allow_zombie (pid_t pid) { - return ihash_find (&pidhash, pid); + return hurd_ihash_find (&pidhash, pid); } /* Find the process corresponding to a given task. */ @@ -53,8 +62,8 @@ struct proc * task_find (task_t task) { struct proc *p; - p = ihash_find (&taskhash, task) ? : add_tasks (task); - return p->p_dead ? 0 : p; + p = hurd_ihash_find (&taskhash, task) ? : add_tasks (task); + return (!p || p->p_dead) ? 0 : p; } /* Find the process corresponding to a given task, but @@ -63,8 +72,8 @@ struct proc * task_find_nocreate (task_t task) { struct proc *p; - p = ihash_find (&taskhash, task); - return p->p_dead ? 0 : p; + p = hurd_ihash_find (&taskhash, task); + return (!p || p->p_dead) ? 0 : p; } /* Find the process corresponding to a given request port. */ @@ -75,65 +84,65 @@ reqport_find (mach_port_t reqport) p = ports_lookup_port (proc_bucket, reqport, proc_class); if (p && p->p_dead) ports_port_deref (p); - return p->p_dead ? 0 : p; + return (!p || p->p_dead) ? 0 : p; } /* Find the process group corresponding to a given pgid. */ struct pgrp * pgrp_find (pid_t pgid) { - return ihash_find (&pghash, pgid); + return hurd_ihash_find (&pghash, pgid); } /* Find the session corresponding to a given sid. */ struct session * session_find (pid_t sid) { - return ihash_find (&sidhash, sid); + return hurd_ihash_find (&sidhash, sid); } /* Add a new process to the various hash tables. */ void add_proc_to_hash (struct proc *p) { - ihash_add (&pidhash, p->p_pid, p, &p->p_pidhashloc); - ihash_add (&taskhash, p->p_task, p, &p->p_taskhashloc); + hurd_ihash_add (&pidhash, p->p_pid, p); + hurd_ihash_add (&taskhash, p->p_task, p); } /* Add a new process group to the various hash tables. */ void add_pgrp_to_hash (struct pgrp *pg) { - ihash_add (&pghash, pg->pg_pgid, pg, &pg->pg_hashloc); + hurd_ihash_add (&pghash, pg->pg_pgid, pg); } /* Add a new session to the various hash tables. */ void add_session_to_hash (struct session *s) { - ihash_add (&sidhash, s->s_sid, s, &s->s_hashloc); + hurd_ihash_add (&sidhash, s->s_sid, s); } /* Remove a process group from the various hash tables. */ void remove_pgrp_from_hash (struct pgrp *pg) { - ihash_locp_remove(0, pg->pg_hashloc); + hurd_ihash_locp_remove (&pghash, pg->pg_hashloc); } /* Remove a process from the various hash tables. */ void remove_proc_from_hash (struct proc *p) { - ihash_locp_remove(0, p->p_pidhashloc); - ihash_locp_remove(0, p->p_taskhashloc); + hurd_ihash_locp_remove (&pidhash, p->p_pidhashloc); + hurd_ihash_locp_remove (&taskhash, p->p_taskhashloc); } /* Remove a session from the various hash tables. */ void remove_session_from_hash (struct session *s) { - ihash_locp_remove(0, s->s_hashloc); + hurd_ihash_locp_remove (&sidhash, s->s_hashloc); } /* Call function FUN of two args for each process. FUN's first arg is @@ -141,14 +150,12 @@ remove_session_from_hash (struct session *s) void prociterate (void (*fun) (struct proc *, void *), void *arg) { - error_t thunk(void *value) + HURD_IHASH_ITERATE (&pidhash, value) { struct proc *p = value; if (!p->p_dead) (*fun)(p, arg); - return 0; } - ihash_iterate(&pidhash, thunk); } /* Tell if a pid is available for use */ diff --git a/proc/host.c b/proc/host.c index 3b1e03c8..2b3c4f3c 100644 --- a/proc/host.c +++ b/proc/host.c @@ -1,5 +1,5 @@ /* Proc server host management calls - Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation + Copyright (C) 1992,93,94,96,97,2001,02 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -The GNU Hurd is distributed in the hope that it will be useful, +The GNU Hurd 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. @@ -31,13 +31,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd/exec.h> #include <unistd.h> #include <assert.h> +#include <version.h> +#include <sys/mman.h> #include "proc.h" #include "process_S.h" -static long hostid; -static char *hostname; -static int hostnamelen; static mach_port_t *std_port_array; static int *std_int_array; static int n_std_ports, n_std_ints; @@ -47,93 +46,17 @@ struct server_version { char *name; char *version; - char *release; } *server_versions; int nserver_versions, server_versions_nalloc; -struct execdata_notify +struct execdata_notify { mach_port_t notify_port; struct execdata_notify *next; } *execdata_notifys; -/* Implement proc_sethostid as described in <hurd/proc.defs>. */ -kern_return_t -S_proc_sethostid (struct proc *p, - int newhostid) -{ - if (!p) - return EOPNOTSUPP; - - if (! check_uid (p, 0)) - return EPERM; - - hostid = newhostid; - - return 0; -} - -/* Implement proc_gethostid as described in <hurd/proc.defs>. */ -kern_return_t -S_proc_gethostid (struct proc *p, - int *outhostid) -{ - /* No need to check P here; we don't use it. */ - *outhostid = hostid; - return 0; -} -/* Implement proc_sethostname as described in <hurd/proc.defs>. */ -kern_return_t -S_proc_sethostname (struct proc *p, - char *newhostname, - u_int newhostnamelen) -{ - int len; - if (!p) - return EOPNOTSUPP; - - if (! check_uid (p, 0)) - return EPERM; - - if (hostname) - free (hostname); - - hostname = malloc (newhostnamelen + 1); - hostnamelen = newhostnamelen; - - bcopy (newhostname, hostname, newhostnamelen); - hostname[newhostnamelen] = '\0'; - - len = newhostnamelen + 1; - if (len > sizeof uname_info.nodename) - len = sizeof uname_info.nodename; - bcopy (hostname, uname_info.nodename, len); - uname_info.nodename[sizeof uname_info.nodename - 1] = '\0'; - - return 0; -} - -/* Implement proc_gethostname as described in <hurd/proc.defs>. */ -kern_return_t -S_proc_gethostname (struct proc *p, - char **outhostname, - u_int *outhostnamelen) -{ - /* No need to check P here; we don't use it. */ - - if (*outhostnamelen < hostnamelen + 1) - vm_allocate (mach_task_self (), (vm_address_t *)outhostname, - hostnamelen + 1, 1); - *outhostnamelen = hostnamelen + 1; - if (hostname) - bcopy (hostname, *outhostname, hostnamelen + 1); - else - **outhostname = '\0'; - return 0; -} - -/* Implement proc_getprivports as described in <hurd/proc.defs>. */ +/* Implement proc_getprivports as described in <hurd/process.defs>. */ kern_return_t S_proc_getprivports (struct proc *p, mach_port_t *hostpriv, @@ -141,33 +64,47 @@ S_proc_getprivports (struct proc *p, { if (!p) return EOPNOTSUPP; - + if (! check_uid (p, 0)) return EPERM; - + *hostpriv = master_host_port; *devpriv = master_device_port; return 0; } -/* Implement proc_setexecdata as described in <hurd/proc.defs>. */ +/* Implement proc_setexecdata as described in <hurd/process.defs>. */ kern_return_t S_proc_setexecdata (struct proc *p, mach_port_t *ports, - u_int nports, + size_t nports, int *ints, - u_int nints) + size_t nints) { int i; struct execdata_notify *n; - + mach_port_t *std_port_array_new; + int *std_int_array_new; + if (!p) return EOPNOTSUPP; - + if (!check_uid (p, 0)) return EPERM; - + + /* Allocate memory up front. */ + std_port_array_new = malloc (sizeof (mach_port_t) * nports); + if (! std_port_array_new) + return ENOMEM; + + std_int_array_new = malloc (sizeof (int) * nints); + if (! std_int_array_new) + { + free (std_port_array_new); + return ENOMEM; + } + if (std_port_array) { for (i = 0; i < n_std_ports; i++) @@ -176,75 +113,98 @@ S_proc_setexecdata (struct proc *p, } if (std_int_array) free (std_int_array); - - std_port_array = malloc (sizeof (mach_port_t) * nports); + + std_port_array = std_port_array_new; n_std_ports = nports; - bcopy (ports, std_port_array, sizeof (mach_port_t) * nports); - - std_int_array = malloc (sizeof (int) * nints); + memcpy (std_port_array, ports, sizeof (mach_port_t) * nports); + + std_int_array = std_int_array_new; n_std_ints = nints; - bcopy (ints, std_int_array, sizeof (int) * nints); - + memcpy (std_int_array, ints, sizeof (int) * nints); + for (n = execdata_notifys; n; n = n->next) exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND, n_std_ports, std_int_array, n_std_ints); - + return 0; } -/* Implement proc_getexecdata as described in <hurd/proc.defs>. */ -kern_return_t +/* Implement proc_getexecdata as described in <hurd/process.defs>. */ +kern_return_t S_proc_getexecdata (struct proc *p, mach_port_t **ports, mach_msg_type_name_t *portspoly, - u_int *nports, + size_t *nports, int **ints, - u_int *nints) + size_t *nints) { + int i; + int ports_allocated = 0; /* No need to check P here; we don't use it. */ - /* XXX memory leak here */ - if (!std_port_array) return ENOENT; if (*nports < n_std_ports) - *ports = malloc (n_std_ports * sizeof (mach_port_t)); - bcopy (std_port_array, *ports, n_std_ports * sizeof (mach_port_t)); + { + *ports = mmap (0, round_page (n_std_ports * sizeof (mach_port_t)), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*ports == MAP_FAILED) + return ENOMEM; + ports_allocated = 1; + } + memcpy (*ports, std_port_array, n_std_ports * sizeof (mach_port_t)); *nports = n_std_ports; - + if (*nints < n_std_ints) - *ints = malloc (n_std_ints * sizeof (mach_port_t)); - bcopy (std_int_array, *ints, n_std_ints * sizeof (int)); + { + *ints = mmap (0, round_page (n_std_ints * sizeof (int)), + PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*ints == MAP_FAILED) + { + if (ports_allocated) + munmap (*ports, round_page (n_std_ports * sizeof (mach_port_t))); + return ENOMEM; + } + } + memcpy (*ints, std_int_array, n_std_ints * sizeof (int)); *nints = n_std_ints; + for (i = 0; i < n_std_ports; i++) + mach_port_mod_refs (mach_task_self (), std_port_array[i], MACH_PORT_RIGHT_SEND, 1); + *portspoly = MACH_MSG_TYPE_MOVE_SEND; + return 0; } -/* Implement proc_execdata_notify as described in <hurd/proc.defs>. */ +/* Implement proc_execdata_notify as described in <hurd/process.defs>. */ kern_return_t S_proc_execdata_notify (struct proc *p, mach_port_t notify) { - struct execdata_notify *n = malloc (sizeof (struct execdata_notify)); + struct execdata_notify *n; mach_port_t foo; /* No need to check P here; we don't use it. */ + n = malloc (sizeof (struct execdata_notify)); + if (! n) + return ENOMEM; + n->notify_port = notify; n->next = execdata_notifys; execdata_notifys = n; - mach_port_request_notification (mach_task_self (), notify, + mach_port_request_notification (mach_task_self (), notify, MACH_NOTIFY_DEAD_NAME, 1, generic_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &foo); if (foo) mach_port_deallocate (mach_task_self (), foo); - + if (std_port_array) - exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND, + exec_setexecdata (n->notify_port, std_port_array, MACH_MSG_TYPE_COPY_SEND, n_std_ports, std_int_array, n_std_ints); return 0; } @@ -255,7 +215,7 @@ void check_dead_execdata_notify (mach_port_t port) { struct execdata_notify *en, **prevp; - + for (en = execdata_notifys, prevp = &execdata_notifys; en; en = *prevp) { if (en->notify_port == port) @@ -271,14 +231,17 @@ check_dead_execdata_notify (mach_port_t port) /* Version information handling. - A server registers its name, release, and version with - startup_register_version. The uname version string is composed of all - the server names and versions. The uname release is composed of the - differing server releases in order of decreasing popularity (just one if - they all agree). + A server registers its name and version with + startup_register_version. + + The uname release is the most popular version number. + + The uname version string is composed of all the server names and + versions, omitting special mention of those which match the uname + release, plus the kernel version string. */ + +char *kernel_name, *kernel_version; - The Hurd release comes from <hurd/hurd_types.h> and - is compiled into proc as well as the other servers. */ /* Rebuild the uname version string. */ static void @@ -314,72 +277,58 @@ rebuild_uname (void) *p++ = '/'; } - /* Collect all the differing release strings and count how many + /* Collect all the differing version strings and count how many servers use each. */ - struct release + struct version { - const char *release; + const char *version; unsigned int count; - } releases[nserver_versions]; - int compare_releases (const void *a, const void *b) + } versions[nserver_versions]; + int compare_versions (const void *a, const void *b) { - return (((const struct release *) b)->count - - ((const struct release *) a)->count); + return (((const struct version *) b)->count - + ((const struct version *) a)->count); } - unsigned int nreleases = 0; + unsigned int nversions = 0; for (i = 0; i < nserver_versions; ++i) { - for (j = 0; j < nreleases; ++j) - if (! strcmp (releases[j].release, server_versions[i].release)) + for (j = 0; j < nversions; ++j) + if (! strcmp (versions[j].version, server_versions[i].version)) { - ++releases[j].count; + ++versions[j].count; break; } - if (j == nreleases) + if (j == nversions) { - releases[nreleases].release = server_versions[i].release; - releases[nreleases].count = 1; - ++nreleases; + versions[nversions].version = server_versions[i].version; + versions[nversions].count = 1; + ++nversions; } } - /* Sort the releases in order of decreasing popularity. */ - qsort (releases, nreleases, sizeof (struct release), compare_releases); + /* Sort the versions in order of decreasing popularity. */ + qsort (versions, nversions, sizeof (struct version), compare_versions); /* Now build the uname strings. */ - initstr (uname_info.release); - for (i = 0; i < nreleases; ++i) - addstr (NULL, releases[i].release); + /* release is the most popular version */ + strcpy (uname_info.release, versions[0].version); - if (p > end) -#ifdef notyet - syslog (LOG_EMERG, - "_UTSNAME_LENGTH %u too short; inform bug-glibc@prep.ai.mit.edu\n", - p - end) -#endif - ; - else - p[-1] = '\0'; - end[-1] = '\0'; + initstr (uname_info.version); - for (i = 2; i < nserver_versions; i++) - if (strcmp (server_versions[i].version, server_versions[1].version)) - break; + addstr (kernel_name, kernel_version); - initstr (uname_info.version); + if (versions[0].count > 1) + addstr ("Hurd", versions[0].version); - if (i == nserver_versions) - { - /* All the servers after [0] (the microkernel version) - are the same, so just write one "hurd" version. */ - addstr (server_versions[0].name, server_versions[0].version); - addstr ("Hurd", server_versions[1].version); - } - else + /* Now, for any which differ (if there might be any), write it out + separately. */ + if (versions[0].count != nserver_versions) for (i = 0; i < nserver_versions; i++) - addstr (server_versions[i].name, server_versions[i].version); + if (versions[0].count == 1 + || strcmp (server_versions[i].version, versions[0].version)) + addstr (server_versions[i].name, server_versions[i].version); if (p > end) #ifdef notyet @@ -393,52 +342,58 @@ rebuild_uname (void) end[-1] = '\0'; } - void initialize_version_info (void) { extern const char *const mach_cpu_types[]; extern const char *const mach_cpu_subtypes[][32]; - kernel_version_t kernel_version; + kernel_version_t kv; char *p; struct host_basic_info info; - unsigned int n = sizeof info; + size_t n = sizeof info; error_t err; /* Fill in fixed slots sysname and machine. */ strcpy (uname_info.sysname, "GNU"); - err = host_info (mach_host_self (), HOST_BASIC_INFO, (int *) &info, &n); + err = host_info (mach_host_self (), HOST_BASIC_INFO, + (host_info_t) &info, &n); assert (! err); - snprintf (uname_info.machine, sizeof uname_info.machine, "%s/%s", + snprintf (uname_info.machine, sizeof uname_info.machine, "%s-%s", mach_cpu_types[info.cpu_type], mach_cpu_subtypes[info.cpu_type][info.cpu_subtype]); /* Notice Mach's and our own version and initialize server version - varables. */ + variables. */ server_versions = malloc (sizeof (struct server_version) * 10); + assert (server_versions); server_versions_nalloc = 10; - err = host_kernel_version (mach_host_self (), kernel_version); + err = host_kernel_version (mach_host_self (), kv); assert (! err); - p = index (kernel_version, ':'); + /* Make sure the result is null-terminated, as the kernel doesn't + guarantee it. */ + kv[sizeof (kv) - 1] = '\0'; + p = index (kv, ':'); if (p) *p = '\0'; - p = index (kernel_version, ' '); + p = index (kv, ' '); if (p) *p = '\0'; - server_versions[0].name = strdup (p ? kernel_version : "mach"); - server_versions[0].release = strdup (HURD_RELEASE); - server_versions[0].version = strdup (p ? p + 1 : kernel_version); + kernel_name = strdup (p ? kv : "mach"); + assert (kernel_name); + kernel_version = strdup (p ? p + 1 : kv); + assert (kernel_version); - server_versions[1].name = strdup (OUR_SERVER_NAME); - server_versions[1].release = strdup (HURD_RELEASE); - server_versions[1].version = strdup (OUR_VERSION); + server_versions[0].name = strdup ("proc"); + assert (server_versions[0].name); + server_versions[0].version = strdup (HURD_VERSION); + assert (server_versions[0].version); - nserver_versions = 2; + nserver_versions = 1; rebuild_uname (); - + uname_info.nodename[0] = '\0'; } @@ -455,9 +410,10 @@ kern_return_t S_proc_register_version (pstruct_t server, mach_port_t credential, char *name, - char *release, + char *release, char *version) { + error_t err = 0; int i; /* No need to check SERVER here; we don't use it. */ @@ -465,17 +421,19 @@ S_proc_register_version (pstruct_t server, if (credential != master_host_port) /* Must be privileged to register for uname. */ return EPERM; - + for (i = 0; i < nserver_versions; i++) if (!strcmp (name, server_versions[i].name)) { /* Change this entry. */ free (server_versions[i].version); - free (server_versions[i].release); server_versions[i].version = malloc (strlen (version) + 1); - server_versions[i].release = malloc (strlen (version) + 1); + if (! server_versions[i].version) + { + err = ENOMEM; + goto out; + } strcpy (server_versions[i].version, version); - strcpy (server_versions[i].release, release); break; } if (i == nserver_versions) @@ -483,23 +441,40 @@ S_proc_register_version (pstruct_t server, /* Didn't find it; extend. */ if (nserver_versions == server_versions_nalloc) { + void *new = realloc (server_versions, + sizeof (struct server_version) * + server_versions_nalloc * 2); + if (! new) + { + err = ENOMEM; + goto out; + } + server_versions_nalloc *= 2; - server_versions = realloc (server_versions, - sizeof (struct server_version) * - server_versions_nalloc); + server_versions = new; } server_versions[nserver_versions].name = malloc (strlen (name) + 1); - server_versions[nserver_versions].version = malloc (strlen (version) - + 1); - server_versions[nserver_versions].release = malloc (strlen (release) + if (! server_versions[nserver_versions].name) + { + err = ENOMEM; + goto out; + } + server_versions[nserver_versions].version = malloc (strlen (version) + 1); + if (! server_versions[nserver_versions].version) + { + free (server_versions[nserver_versions].name); + err = ENOMEM; + goto out; + } strcpy (server_versions[nserver_versions].name, name); strcpy (server_versions[nserver_versions].version, version); - strcpy (server_versions[nserver_versions].release, release); nserver_versions++; } - + rebuild_uname (); - mach_port_deallocate (mach_task_self (), credential); - return 0; +out: + if (!err) + mach_port_deallocate (mach_task_self (), credential); + return err; } diff --git a/proc/info.c b/proc/info.c index c44bde6a..f35ad166 100644 --- a/proc/info.c +++ b/proc/info.c @@ -1,5 +1,5 @@ /* Process information queries - Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation + 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 <hurd/hurd_types.h> #include <stdlib.h> #include <errno.h> @@ -32,17 +33,32 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "proc.h" #include "process_S.h" -/* Implement S_proc_pid2task as described in <hurd/proc.defs>. */ + +/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get + its task port &c). If PROC2 has an owner, then PROC1 must have that uid; + otherwise, both must be in the same login collection. */ +static inline int +check_owner (struct proc *proc1, struct proc *proc2) +{ + return + proc2->p_noowner + ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login + : check_uid (proc1, proc2->p_owner); +} + + +/* Implement S_proc_pid2task as described in <hurd/process.defs>. */ kern_return_t S_proc_pid2task (struct proc *callerp, - pid_t pid, - task_t *t) + pid_t pid, + task_t *t) { - struct proc *p = pid_find_allow_zombie (pid); + struct proc *p; if (!callerp) return EOPNOTSUPP; + p = pid_find_allow_zombie (pid); if (!p) return ESRCH; @@ -55,16 +71,17 @@ S_proc_pid2task (struct proc *callerp, if (! check_owner (callerp, p)) return EPERM; + assert (MACH_PORT_VALID (p->p_task)); *t = p->p_task; return 0; } -/* Implement proc_task2pid as described in <hurd/proc.defs>. */ +/* Implement proc_task2pid as described in <hurd/process.defs>. */ kern_return_t S_proc_task2pid (struct proc *callerp, - task_t t, - pid_t *pid) + task_t t, + pid_t *pid) { struct proc *p = task_find (t); @@ -78,11 +95,11 @@ S_proc_task2pid (struct proc *callerp, return 0; } -/* Implement proc_task2proc as described in <hurd/proc.defs>. */ +/* Implement proc_task2proc as described in <hurd/process.defs>. */ kern_return_t S_proc_task2proc (struct proc *callerp, - task_t t, - mach_port_t *outproc) + task_t t, + mach_port_t *outproc) { struct proc *p = task_find (t); @@ -96,10 +113,10 @@ S_proc_task2proc (struct proc *callerp, return 0; } -/* Implement proc_proc2task as described in <hurd/proc.defs>. */ +/* Implement proc_proc2task as described in <hurd/process.defs>. */ kern_return_t S_proc_proc2task (struct proc *p, - task_t *t) + task_t *t) { if (!p) return EOPNOTSUPP; @@ -107,17 +124,18 @@ S_proc_proc2task (struct proc *p, return 0; } -/* Implement proc_pid2proc as described in <hurd/proc.defs>. */ +/* Implement proc_pid2proc as described in <hurd/process.defs>. */ kern_return_t S_proc_pid2proc (struct proc *callerp, - pid_t pid, - mach_port_t *outproc) + pid_t pid, + mach_port_t *outproc) { - struct proc *p = pid_find_allow_zombie (pid); + struct proc *p; if (!callerp) return EOPNOTSUPP; + p = pid_find_allow_zombie (pid); if (!p) return ESRCH; @@ -136,18 +154,18 @@ S_proc_pid2proc (struct proc *callerp, /* Read a string starting at address ADDR in task T; set *STR to point at - newly malloced storage holding it. */ + newly malloced storage holding it, and *LEN to its length with null. */ static error_t get_string (task_t t, vm_address_t addr, - char **str) + char **str, size_t *len) { /* This version assumes that a string is never more than one page in length. */ vm_address_t readaddr; vm_address_t data; - u_int readlen; + size_t readlen; error_t err; char *c; @@ -168,15 +186,15 @@ get_string (task_t t, else { c++; /* Include the null. */ - *str = malloc (c - (char *)(data + (addr - readaddr))); + *len = c - (char *) (data + (addr - readaddr)); + *str = malloc (*len); if (*str == NULL) err = ENOMEM; else - bcopy ((char *)(data + (addr - readaddr)), *str, - c - (char *)(data + (addr - readaddr))); + memcpy (*str, (char *) data + (addr - readaddr), *len); } - vm_deallocate (mach_task_self (), data, readlen); + munmap ((caddr_t) data, readlen); return err; } @@ -210,8 +228,6 @@ get_vector (task_t task, if (err) return err; - /* XXX fault bad here */ - /* Scan for a null. */ for (t = (vm_address_t *) (data + (scanned - readaddr)); t < (vm_address_t *) (data + readlen); @@ -223,15 +239,15 @@ get_vector (task_t task, if (*vec == NULL) err = ENOMEM; else - bcopy ((char *)(data + (addr - readaddr)), *vec, + memcpy (*vec, (char *)(data + (addr - readaddr)), (char *)t - (char *)(data + (addr - readaddr))); break; } /* If we didn't find the null terminator, then we will loop to read an additional page. */ - scanned = data + readlen; - vm_deallocate (mach_task_self (), data, readlen); + scanned = readaddr + readlen; + munmap ((caddr_t) data, readlen); } while (!err && *vec == NULL); return err; @@ -243,7 +259,7 @@ static error_t get_string_array (task_t t, vm_address_t loc, vm_address_t *buf, - u_int *buflen) + size_t *buflen) { char *bp; int *vector, *vp; @@ -258,62 +274,65 @@ get_string_array (task_t t, for (vp = vector; *vp; ++vp) { char *string; - int len; + size_t len; - err = get_string (t, *vp, &string); + err = get_string (t, *vp, &string, &len); if (err) { free (vector); if (*buf != origbuf) - vm_deallocate (mach_task_self (), *buf, *buflen); + munmap ((caddr_t) *buf, *buflen); return err; } - len = strlen (string) + 1; - if (len > *(char **)buf + *buflen - bp) + if (len > (char *) *buf + *buflen - bp) { - vm_address_t newbuf; - vm_size_t prev_len = bp - *(char **)buf; + char *newbuf; + vm_size_t prev_len = bp - (char *) *buf; vm_size_t newsize = *buflen * 2; if (newsize < prev_len + len) - newsize = prev_len + len; + /* Since we will mmap whole pages anyway, + notice how much space we really have. */ + newsize = round_page (prev_len + len); - err = vm_allocate (mach_task_self (), &newbuf, newsize, 1); - if (err) + newbuf = mmap (0, newsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (newbuf == MAP_FAILED) { + err = errno; free (string); free (vector); if (*buf != origbuf) - vm_deallocate (mach_task_self (), *buf, *buflen); + munmap ((caddr_t) *buf, *buflen); return err; } - bcopy (*(char **) buf, (char *) newbuf, prev_len); - bp = (char *)newbuf + prev_len; + memcpy (newbuf, (char *) *buf, prev_len); + bp = newbuf + prev_len; if (*buf != origbuf) - vm_deallocate (mach_task_self (), *buf, *buflen); + munmap ((caddr_t) *buf, *buflen); - *buf = newbuf; + *buf = (vm_address_t) newbuf; *buflen = newsize; } - bcopy (string, bp, len); + memcpy (bp, string, len); bp += len; free (string); } + free (vector); *buflen = bp - (char *) *buf; return 0; } -/* Implement proc_getprocargs as described in <hurd/proc.defs>. */ +/* Implement proc_getprocargs as described in <hurd/process.defs>. */ kern_return_t S_proc_getprocargs (struct proc *callerp, pid_t pid, char **buf, - u_int *buflen) + size_t *buflen) { struct proc *p = pid_find (pid); @@ -325,12 +344,12 @@ S_proc_getprocargs (struct proc *callerp, return get_string_array (p->p_task, p->p_argv, (vm_address_t *) buf, buflen); } -/* Implement proc_getprocenv as described in <hurd/proc.defs>. */ +/* Implement proc_getprocenv as described in <hurd/process.defs>. */ kern_return_t S_proc_getprocenv (struct proc *callerp, pid_t pid, char **buf, - u_int *buflen) + size_t *buflen) { struct proc *p = pid_find (pid); @@ -346,18 +365,18 @@ S_proc_getprocenv (struct proc *callerp, #define PI_FETCH_THREAD_DETAILS \ (PI_FETCH_THREAD_SCHED | PI_FETCH_THREAD_BASIC | PI_FETCH_THREAD_WAITS) -/* Implement proc_getprocinfo as described in <hurd/proc.defs>. */ +/* Implement proc_getprocinfo as described in <hurd/process.defs>. */ kern_return_t S_proc_getprocinfo (struct proc *callerp, pid_t pid, int *flags, int **piarray, - u_int *piarraylen, + size_t *piarraylen, char **waits, mach_msg_type_number_t *waits_len) { struct proc *p = pid_find (pid); struct procinfo *pi; - int nthreads; + size_t nthreads; thread_t *thds; error_t err = 0; size_t structsize; @@ -365,7 +384,7 @@ S_proc_getprocinfo (struct proc *callerp, int pi_alloced = 0, waits_alloced = 0; /* The amount of WAITS we've filled in so far. */ mach_msg_type_number_t waits_used = 0; - u_int tkcount, thcount; + size_t tkcount, thcount; struct proc *tp; task_t task; /* P's task port. */ mach_port_t msgport; /* P's msgport, or MACH_PORT_NULL if none. */ @@ -376,7 +395,9 @@ S_proc_getprocinfo (struct proc *callerp, return ESRCH; task = p->p_task; - msgport = p->p_deadmsg ? MACH_PORT_NULL : p->p_msgport; + + check_msgport_death (p); + msgport = p->p_msgport; if (*flags & PI_FETCH_THREAD_DETAILS) *flags |= PI_FETCH_THREADS; @@ -398,7 +419,18 @@ S_proc_getprocinfo (struct proc *callerp, if (structsize / sizeof (int) > *piarraylen) { - vm_allocate (mach_task_self (), (vm_address_t *)piarray, structsize, 1); + *piarray = mmap (0, structsize, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0); + if (*piarray == MAP_FAILED) + { + err = errno; + if (*flags & PI_FETCH_THREADS) + { + for (i = 0; i < nthreads; i++) + mach_port_deallocate (mach_task_self (), thds[i]); + munmap (thds, nthreads * sizeof (thread_t)); + } + return err; + } pi_alloced = 1; } *piarraylen = structsize / sizeof (int); @@ -424,7 +456,7 @@ S_proc_getprocinfo (struct proc *callerp, assert (tp); pi->logincollection = tp->p_pid; if (p->p_dead || p->p_stopped) - { + { pi->exitstatus = p->p_status; pi->sigcode = p->p_sigcode; } @@ -440,9 +472,37 @@ S_proc_getprocinfo (struct proc *callerp, if (*flags & PI_FETCH_TASKINFO) { tkcount = TASK_BASIC_INFO_COUNT; - err = task_info (task, TASK_BASIC_INFO, (int *)&pi->taskinfo, &tkcount); + err = task_info (task, TASK_BASIC_INFO, + (task_info_t) &pi->taskinfo, &tkcount); if (err == MACH_SEND_INVALID_DEST) err = ESRCH; +#ifdef TASK_SCHED_TIMESHARE_INFO + if (!err) + { + tkcount = TASK_SCHED_TIMESHARE_INFO_COUNT; + err = task_info (task, TASK_SCHED_TIMESHARE_INFO, + (int *)&pi->timeshare_base_info, &tkcount); + if (err == KERN_INVALID_POLICY) + { + pi->timeshare_base_info.base_priority = -1; + err = 0; + } + } +#endif + } + if (*flags & PI_FETCH_TASKEVENTS) + { + tkcount = TASK_EVENTS_INFO_COUNT; + err = task_info (task, TASK_EVENTS_INFO, + (task_info_t) &pi->taskevents, &tkcount); + if (err == MACH_SEND_INVALID_DEST) + err = ESRCH; + if (err) + { + /* Something screwy, give up on this bit of info. */ + *flags &= ~PI_FETCH_TASKEVENTS; + err = 0; + } } for (i = 0; i < nthreads; i++) @@ -453,7 +513,7 @@ S_proc_getprocinfo (struct proc *callerp, { thcount = THREAD_BASIC_INFO_COUNT; err = thread_info (thds[i], THREAD_BASIC_INFO, - (int *)&pi->threadinfos[i].pis_bi, + (thread_info_t) &pi->threadinfos[i].pis_bi, &thcount); if (err == MACH_SEND_INVALID_DEST) { @@ -473,7 +533,7 @@ S_proc_getprocinfo (struct proc *callerp, { thcount = THREAD_SCHED_INFO_COUNT; err = thread_info (thds[i], THREAD_SCHED_INFO, - (int *)&pi->threadinfos[i].pis_si, + (thread_info_t) &pi->threadinfos[i].pis_si, &thcount); if (err == MACH_SEND_INVALID_DEST) { @@ -482,15 +542,15 @@ S_proc_getprocinfo (struct proc *callerp, continue; } if (err) - /* Something screwy, give up o nthis bit of info. */ + /* Something screwy, give up on this bit of info. */ { *flags &= ~PI_FETCH_THREAD_SCHED; err = 0; } } - /* Note that there are thread wait entries only for threads not marked - dead. */ + /* Note that there are thread wait entries only for those threads + not marked dead. */ if (*flags & PI_FETCH_THREAD_WAITS) { @@ -517,18 +577,18 @@ S_proc_getprocinfo (struct proc *callerp, mach_msg_type_number_t new_len = round_page (waits_used + desc_len + 1); - err = vm_allocate (mach_task_self (), - (vm_address_t *)&new_waits, new_len,1); + new_waits = mmap (0, new_len, PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + err = (new_waits == MAP_FAILED) ? errno : 0; if (err) /* Just don't return any more waits information. */ *flags &= ~PI_FETCH_THREAD_WAITS; else { if (waits_used > 0) - bcopy (*waits, new_waits, waits_used); + memcpy (new_waits, *waits, waits_used); if (*waits_len > 0 && waits_alloced) - vm_deallocate (mach_task_self (), - (vm_address_t)*waits, *waits_len); + munmap (*waits, *waits_len); *waits = new_waits; *waits_len = new_len; waits_alloced = 1; @@ -538,7 +598,7 @@ S_proc_getprocinfo (struct proc *callerp, if (waits_used + desc_len + 1 <= *waits_len) /* Append DESC to WAITS. */ { - bcopy (desc, *waits + waits_used, desc_len); + memcpy (*waits + waits_used, desc, desc_len); waits_used += desc_len; (*waits)[waits_used++] = '\0'; } @@ -549,14 +609,11 @@ S_proc_getprocinfo (struct proc *callerp, } if (*flags & PI_FETCH_THREADS) - { - vm_deallocate (mach_task_self (), - (vm_address_t)thds, nthreads * sizeof (thread_t)); - } + munmap (thds, nthreads * sizeof (thread_t)); if (err && pi_alloced) - vm_deallocate (mach_task_self (), (u_int) *piarray, structsize); + munmap (*piarray, structsize); if (err && waits_alloced) - vm_deallocate (mach_task_self (), (vm_address_t)*waits, *waits_len); + munmap (*waits, *waits_len); else *waits_len = waits_used; @@ -602,8 +659,9 @@ kern_return_t S_proc_getloginpids (struct proc *callerp, pid_t id, pid_t **pids, - u_int *npids) + size_t *npids) { + error_t err = 0; struct proc *l = pid_find (id); struct proc *p; struct proc **tail, **new, **parray; @@ -618,6 +676,9 @@ S_proc_getloginpids (struct proc *callerp, /* Simple breadth first search of the children of L. */ parraysize = 50; parray = malloc (sizeof (struct proc *) * parraysize); + if (! parray) + return ENOMEM; + parray[0] = l; for (tail = parray, new = &parray[1]; tail != new; tail++) { @@ -630,6 +691,12 @@ S_proc_getloginpids (struct proc *callerp, struct proc **newparray; newparray = realloc (parray, ((parraysize *= 2) * sizeof (struct proc *))); + if (! newparray) + { + free (parray); + return ENOMEM; + } + tail = newparray + (tail - parray); new = newparray + (new - parray); parray = newparray; @@ -639,19 +706,28 @@ S_proc_getloginpids (struct proc *callerp, } if (*npids < new - parray) - vm_allocate (mach_task_self (), (vm_address_t *) pids, - (new - parray) * sizeof (pid_t), 1); - *npids = new - parray; - for (i = 0; i < *npids; i++) - (*pids)[i] = parray[i]->p_pid; + { + *pids = mmap (0, (new - parray) * sizeof (pid_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (*pids == MAP_FAILED) + err = errno; + } + + if (! err) + { + *npids = new - parray; + for (i = 0; i < *npids; i++) + (*pids)[i] = parray[i]->p_pid; + } + free (parray); - return 0; + return err; } -/* Implement proc_setlogin as described in <hurd/proc.defs>. */ +/* Implement proc_setlogin as described in <hurd/process.defs>. */ kern_return_t S_proc_setlogin (struct proc *p, - char *login) + char *login) { struct login *l; @@ -662,6 +738,9 @@ S_proc_setlogin (struct proc *p, return EPERM; l = malloc (sizeof (struct login) + strlen (login) + 1); + if (! l) + return ENOMEM; + l->l_refcnt = 1; strcpy (l->l_name, login); if (!--p->p_login->l_refcnt) @@ -670,10 +749,10 @@ S_proc_setlogin (struct proc *p, return 0; } -/* Implement proc_getlogin as described in <hurd/proc.defs>. */ +/* Implement proc_getlogin as described in <hurd/process.defs>. */ kern_return_t S_proc_getlogin (struct proc *p, - char *login) + char *login) { if (!p) return EOPNOTSUPP; @@ -681,10 +760,42 @@ S_proc_getlogin (struct proc *p, return 0; } -/* Implement proc_get_tty as described in <hurd/proc.defs>. */ +/* Implement proc_get_tty as described in <hurd/process.defs>. */ kern_return_t S_proc_get_tty (struct proc *p, pid_t pid, mach_port_t *tty, mach_msg_type_name_t *tty_type) { return EOPNOTSUPP; /* XXX */ } + +/* Implement proc_getnports as described in <hurd/process.defs>. */ +kern_return_t +S_proc_getnports (struct proc *callerp, + pid_t pid, + mach_msg_type_number_t *nports) +{ + struct proc *p = pid_find (pid); + mach_port_array_t names; + mach_msg_type_number_t ncount; + mach_port_type_array_t types; + mach_msg_type_number_t tcount; + error_t err = 0; + + /* No need to check CALLERP here; we don't use it. */ + + if (!p) + return ESRCH; + + err = mach_port_names (p->p_task, &names, &ncount, &types, &tcount); + if (err == KERN_INVALID_TASK) + err = ESRCH; + + if (!err) { + *nports = ncount; + + munmap (names, ncount * sizeof (mach_port_t)); + munmap (types, tcount * sizeof (mach_port_type_t)); + } + + return err; +} diff --git a/proc/main.c b/proc/main.c index 1292cea0..f2cdfdf5 100644 --- a/proc/main.c +++ b/proc/main.c @@ -1,5 +1,5 @@ /* Initialization of the proc server - Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1993,94,95,96,97,99,2000,01 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -23,11 +23,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <hurd/hurd_types.h> #include <hurd.h> #include <hurd/startup.h> +#include <device/device.h> #include <assert.h> -#include <wire.h> +#include <argp.h> +#include <error.h> +#include <version.h> #include "proc.h" +const char *argp_program_version = STANDARD_HURD_VERSION (proc); + int message_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) @@ -56,64 +61,79 @@ main (int argc, char **argv, char **envp) mach_port_t pset, psetcntl; void *genport; process_t startup_port; - volatile int hold = 0; - - while (hold); - + struct argp argp = { 0, 0, 0, "Hurd process server" }; + + argp_parse (&argp, argc, argv, 0, 0, 0); initialize_version_info (); - task_get_bootstrap_port (mach_task_self (), &boot); + err = task_get_bootstrap_port (mach_task_self (), &boot); + assert_perror (err); + if (boot == MACH_PORT_NULL) + error (2, 0, "proc server can only be run by init during boot"); proc_bucket = ports_create_bucket (); proc_class = ports_create_class (0, 0); generic_port_class = ports_create_class (0, 0); exc_class = ports_create_class (exc_clean, 0); - ports_create_port (generic_port_class, proc_bucket, + ports_create_port (generic_port_class, proc_bucket, sizeof (struct port_info), &genport); generic_port = ports_get_right (genport); - /* new_proc depends on these assignments which must occur in this order. */ - self_proc = new_proc (mach_task_self ()); /* proc 0 is the procserver */ - startup_proc = new_proc (MACH_PORT_NULL); /* proc 1 is init */ + /* Create the initial proc object for init (PID 1). */ + startup_proc = create_startup_proc (); + + /* Create our own proc object (we are PID 0). */ + self_proc = allocate_proc (mach_task_self ()); + assert (self_proc); + + complete_proc (self_proc, 0); - startup_port = ports_get_right (startup_proc); - mach_port_insert_right (mach_task_self (), startup_port, - startup_port, MACH_MSG_TYPE_MAKE_SEND); + startup_port = ports_get_send_right (startup_proc); err = startup_procinit (boot, startup_port, &startup_proc->p_task, &authserver, &master_host_port, &master_device_port); - assert (!err); + assert_perror (err); mach_port_deallocate (mach_task_self (), startup_port); mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1); _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver); mach_port_deallocate (mach_task_self (), boot); - add_proc_to_hash (self_proc); - add_proc_to_hash (startup_proc); + proc_death_notify (startup_proc); + add_proc_to_hash (startup_proc); /* Now that we have the task port. */ /* Set our own argv and envp locations. */ - self_proc->p_argv = (int) argv; - self_proc->p_envp = (int) envp; + self_proc->p_argv = (vm_address_t) argv; + self_proc->p_envp = (vm_address_t) envp; /* Give ourselves good scheduling performance, because we are so important. */ err = thread_get_assignment (mach_thread_self (), &pset); - assert (!err); + assert_perror (err); err = host_processor_set_priv (master_host_port, pset, &psetcntl); - assert (!err); + assert_perror (err); thread_max_priority (mach_thread_self (), psetcntl, 0); - assert (!err); + assert_perror (err); err = task_priority (mach_task_self (), 2, 1); - assert (!err); + assert_perror (err); mach_port_deallocate (mach_task_self (), pset); mach_port_deallocate (mach_task_self (), psetcntl); -/* wire_task_self (); */ + { + /* Get our stderr set up to print on the console, in case we have + to panic or something. */ + mach_port_t cons; + error_t err; + err = device_open (master_device_port, D_READ|D_WRITE, "console", &cons); + assert_perror (err); + stdin = mach_open_devstream (cons, "r"); + stdout = stderr = mach_open_devstream (cons, "w"); + mach_port_deallocate (mach_task_self (), cons); + } while (1) ports_manage_port_operations_multithread (proc_bucket, message_demuxer, - 0, 0, 0, 0); + 0, 0, 0); } @@ -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++; @@ -1,5 +1,5 @@ /* Message port manipulations - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994, 1995, 1996, 1999, 2001 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -50,7 +50,6 @@ S_proc_setmsgport (struct proc *p, mach_port_t *oldmsgport, mach_msg_type_name_t *oldmsgport_type) { - mach_port_t foo; if (!p) return EOPNOTSUPP; @@ -63,12 +62,6 @@ S_proc_setmsgport (struct proc *p, prociterate (check_message_return, p); p->p_checkmsghangs = 0; - mach_port_request_notification (mach_task_self (), msgport, - 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); - if (p == startup_proc) /* Init is single threaded, so we can't delay our reply for the essential task RPC; spawn a thread to do it. */ @@ -89,6 +82,32 @@ check_message_dying (struct proc *p, struct proc *dyingp) } } +/* Check if the message port of process P has died. Return nonzero if + this has indeed happened. */ +int +check_msgport_death (struct proc *p) +{ + /* Only check if the message port passed away, if we know that it + was ever alive. */ + if (p->p_msgport != MACH_PORT_NULL) + { + mach_port_type_t type; + error_t err; + + err = mach_port_type (mach_task_self (), p->p_msgport, &type); + if (err || (type & MACH_PORT_TYPE_DEAD_NAME)) + { + /* The port appears to be dead; throw it away. */ + mach_port_deallocate (mach_task_self (), p->p_msgport); + p->p_msgport = MACH_PORT_NULL; + p->p_deadmsg = 1; + return 1; + } + } + + return 0; +} + error_t S_proc_getmsgport (struct proc *callerp, mach_port_t reply_port, @@ -97,11 +116,14 @@ S_proc_getmsgport (struct proc *callerp, mach_port_t *msgport) { int cancel; - struct proc *p = pid_find_allow_zombie (pid); + struct proc *p; if (!callerp) return EOPNOTSUPP; - + + p = pid_find_allow_zombie (pid); + +restart: while (p && p->p_deadmsg && !p->p_dead) { callerp->p_msgportwait = 1; @@ -119,15 +141,10 @@ S_proc_getmsgport (struct proc *callerp, if (!p) return ESRCH; + if (check_msgport_death (p)) + goto restart; + *msgport = p->p_msgport; - return 0; -} -void -message_port_dead (struct proc *p) -{ - mach_port_deallocate (mach_task_self (), p->p_msgport); - p->p_msgport = MACH_PORT_NULL; - p->p_deadmsg = 1; + return 0; } - diff --git a/proc/notify.c b/proc/notify.c index 9d48d945..5a112b07 100644 --- a/proc/notify.c +++ b/proc/notify.c @@ -1,5 +1,5 @@ /* Handle notifications - Copyright (C) 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1996, 1999 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -44,6 +44,7 @@ do_mach_notify_dead_name (mach_port_t notify, if (notify == generic_port) { check_dead_execdata_notify (deadport); + mach_port_deallocate (mach_task_self (), deadport); return 0; } @@ -52,16 +53,11 @@ do_mach_notify_dead_name (mach_port_t notify, if (!p) return EOPNOTSUPP; - if (p->p_msgport == deadport) - { - message_port_dead (p); - ports_port_deref (p); - return 0; - } - else if (p->p_task == deadport) + if (p->p_task == deadport) { process_has_exited (p); ports_port_deref (p); + mach_port_deallocate (mach_task_self (), deadport); return 0; } else diff --git a/proc/pgrp.c b/proc/pgrp.c index 224f7e52..2d6ca93a 100644 --- a/proc/pgrp.c +++ b/proc/pgrp.c @@ -1,5 +1,5 @@ -/* Session and process group manipulation - Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +/* Session and process group manipulation + Copyright (C) 1992,93,94,95,96,99,2001,02 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -8,7 +8,7 @@ it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. -The GNU Hurd is distributed in the hope that it will be useful, +The GNU Hurd 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. @@ -25,6 +25,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <sys/errno.h> #include <stdlib.h> #include <signal.h> +#include <assert.h> #include "proc.h" #include "process_S.h" @@ -37,19 +38,22 @@ new_pgrp (pid_t pgid, struct session *sess) { struct pgrp *pg; - + pg = malloc (sizeof (struct pgrp)); + if (! pg) + return NULL; + pg->pg_plist = 0; pg->pg_pgid = pgid; pg->pg_orphcnt = 0; - + pg->pg_session = sess; pg->pg_next = sess->s_pgrps; if (pg->pg_next) pg->pg_next->pg_prevp = &pg->pg_next; sess->s_pgrps = pg; pg->pg_prevp = &sess->s_pgrps; - + add_pgrp_to_hash (pg); return pg; } @@ -59,14 +63,17 @@ static inline struct session * new_session (struct proc *p) { struct session *sess; - + sess = malloc (sizeof (struct session)); + if (! sess) + return NULL; + sess->s_sid = p->p_pid; sess->s_pgrps = 0; sess->s_sessionid = MACH_PORT_NULL; add_session_to_hash (sess); - + return sess; } @@ -93,21 +100,21 @@ free_pgrp (struct pgrp *pg) remove_pgrp_from_hash (pg); free (pg); } - -/* Implement proc_setsid as described in <hurd/proc.defs>. */ + +/* Implement proc_setsid as described in <hurd/process.defs>. */ kern_return_t S_proc_setsid (struct proc *p) { struct session *sess; - + if (!p) return EOPNOTSUPP; - + if (p->p_pgrp->pg_pgid == p->p_pid || pgrp_find (p->p_pid)) return EPERM; - + leave_pgrp (p); - + sess = new_session (p); p->p_pgrp= new_pgrp (p->p_pid, sess); join_pgrp (p); @@ -120,14 +127,15 @@ void boot_setsid (struct proc *p) { struct session *sess; - + sess = new_session (p); p->p_pgrp = new_pgrp (p->p_pid, sess); + assert (p->p_pgrp); join_pgrp (p); return; } -/* Implement proc_getsid as described in <hurd/proc.defs>. */ +/* Implement proc_getsid as described in <hurd/process.defs>. */ kern_return_t S_proc_getsid (struct proc *callerp, pid_t pid, @@ -143,12 +151,12 @@ S_proc_getsid (struct proc *callerp, return 0; } -/* Implement proc_getsessionpids as described in <hurd/proc.defs>. */ +/* Implement proc_getsessionpids as described in <hurd/process.defs>. */ kern_return_t S_proc_getsessionpids (struct proc *callerp, pid_t sid, pid_t **pids, - u_int *npidsp) + size_t *npidsp) { int count; struct pgrp *pg; @@ -156,13 +164,13 @@ S_proc_getsessionpids (struct proc *callerp, struct session *s; pid_t *pp = *pids; u_int npids = *npidsp; - + /* No need to check CALLERP; we don't use it. */ s = session_find (sid); if (!s) return ESRCH; - + count = 0; for (pg = s->s_pgrps; pg; pg = pg->pg_next) for (p = pg->pg_plist; p; p = p->p_gnext) @@ -170,12 +178,15 @@ S_proc_getsessionpids (struct proc *callerp, if (++count <= npids) *pp++ = p->p_pid; } - + if (count > npids) /* They didn't all fit */ { - vm_allocate (mach_task_self (), (vm_address_t *)pids, - count * sizeof (pid_t), 1); + *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (*pids == MAP_FAILED) + return errno; + pp = *pids; for (pg = s->s_pgrps; pg; pg = pg->pg_next) for (p = pg->pg_plist; p; p = p->p_gnext) @@ -192,14 +203,14 @@ kern_return_t S_proc_getsessionpgids (struct proc *callerp, pid_t sid, pid_t **pgids, - u_int *npgidsp) + size_t *npgidsp) { int count; struct pgrp *pg; struct session *s; pid_t *pp = *pgids; int npgids = *npgidsp; - + /* No need to check CALLERP; we don't use it. */ s = session_find (sid); @@ -210,12 +221,15 @@ S_proc_getsessionpgids (struct proc *callerp, for (pg = s->s_pgrps; pg; pg = pg->pg_next) if (++count <= npgids) *pp++ = pg->pg_pgid; - + if (count > npgids) /* They didn't all fit. */ { - vm_allocate (mach_task_self (), (vm_address_t *)pgids, - count * sizeof (pid_t), 1); + *pgids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (*pgids == MAP_FAILED) + return errno; + pp = *pgids; for (pg = s->s_pgrps; pg; pg = pg->pg_next) *pp++ = pg->pg_pgid; @@ -230,14 +244,14 @@ kern_return_t S_proc_getpgrppids (struct proc *callerp, pid_t pgid, pid_t **pids, - u_int *npidsp) + size_t *npidsp) { struct proc *p; struct pgrp *pg; pid_t *pp = *pids; unsigned int npids = *npidsp, count; - + /* No need to check CALLERP; we don't use it. */ if (pgid == 0) @@ -253,12 +267,15 @@ S_proc_getpgrppids (struct proc *callerp, for (p = pg->pg_plist; p; p = p->p_gnext) if (++count <= npids) *pp++ = p->p_pid; - + if (count > npids) /* They didn't all fit. */ { - vm_allocate (mach_task_self (), (vm_address_t *)pids, - count * sizeof (pid_t), 1); + *pids = mmap (0, count * sizeof (pid_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + if (*pids == MAP_FAILED) + return errno; + pp = *pids; for (p = pg->pg_plist; p; p = p->p_gnext) *pp++ = p->p_pid; @@ -268,13 +285,13 @@ S_proc_getpgrppids (struct proc *callerp, return 0; } -/* Implement proc_getsidport as described in <hurd/proc.defs>. */ +/* Implement proc_getsidport as described in <hurd/process.defs>. */ kern_return_t S_proc_getsidport (struct proc *p, mach_port_t *sessport, mach_msg_type_name_t *sessport_type) { error_t err = 0; - + if (!p) return EOPNOTSUPP; @@ -291,7 +308,7 @@ S_proc_getsidport (struct proc *p, return err; } -/* Implement proc_setpgrp as described in <hurd/proc.defs>. */ +/* Implement proc_setpgrp as described in <hurd/process.defs>. */ kern_return_t S_proc_setpgrp (struct proc *callerp, pid_t pid, @@ -299,7 +316,7 @@ S_proc_setpgrp (struct proc *callerp, { struct proc *p; struct pgrp *pg; - + if (!callerp) return EOPNOTSUPP; @@ -307,10 +324,10 @@ S_proc_setpgrp (struct proc *callerp, if (!p || (p != callerp && p->p_parent != callerp)) return ESRCH; - + if (p->p_parent == callerp && p->p_exec) return EACCES; - + if (!pgid) pgid = p->p_pid; pg = pgrp_find (pgid); @@ -320,7 +337,7 @@ S_proc_setpgrp (struct proc *callerp, || ((pgid != p->p_pid && (!pg || pg->pg_session != callerp->p_pgrp->pg_session)))) return EPERM; - + if (p->p_pgrp != pg) { leave_pgrp (p); @@ -330,11 +347,11 @@ S_proc_setpgrp (struct proc *callerp, else nowait_msg_proc_newids (p->p_msgport, p->p_task, p->p_parent->p_pid, pg->pg_pgid, !pg->pg_orphcnt); - + return 0; } -/* Implement proc_getpgrp as described in <hurd/proc.defs>. */ +/* Implement proc_getpgrp as described in <hurd/process.defs>. */ kern_return_t S_proc_getpgrp (struct proc *callerp, pid_t pid, @@ -343,17 +360,17 @@ S_proc_getpgrp (struct proc *callerp, struct proc *p = pid_find (pid); /* No need to check CALLERP; we don't use it. */ - + if (!p) return ESRCH; - + if (p->p_pgrp) *pgid = p->p_pgrp->pg_pgid; - + return 0; } -/* Implement proc_mark_exec as described in <hurd/proc.defs>. */ +/* Implement proc_mark_exec as described in <hurd/process.defs>. */ kern_return_t S_proc_mark_exec (struct proc *p) { @@ -375,7 +392,7 @@ leave_pgrp (struct proc *p) *p->p_gprevp = p->p_gnext; if (p->p_gnext) p->p_gnext->p_gprevp = p->p_gprevp; - + /* If we were the last member of our pgrp, free it */ if (!pg->pg_plist) free_pgrp (pg); @@ -387,7 +404,7 @@ leave_pgrp (struct proc *p) an orphaned process group -- do the orphaning gook */ struct proc *ip; int dosignal = 0; - + for (ip = pg->pg_plist; ip; ip = ip->p_gnext) { if (ip->p_stopped) @@ -418,7 +435,7 @@ join_pgrp (struct proc *p) if (pg->pg_plist) pg->pg_plist->p_gprevp = &p->p_gnext; pg->pg_plist = p; - + origorphcnt = !!pg->pg_orphcnt; if (p->p_parent->p_pgrp != pg && p->p_parent->p_pgrp->pg_session == pg->pg_session) diff --git a/proc/primes.c b/proc/primes.c deleted file mode 100644 index d0fc4d0c..00000000 --- a/proc/primes.c +++ /dev/null @@ -1,135 +0,0 @@ -/* Prime number generation - Copyright (C) 1994 Free Software Foundation - - This program 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 2, or (at - your option) any later version. - - This program 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - -#include <stdlib.h> -#include <limits.h> -#include <string.h> -#include <assert.h> - -#define BITS_PER_UNSIGNED (8 * sizeof (unsigned)) -#define SQRT_INT_MAX (1 << (BITS_PER_UNSIGNED / 2)) - -/* Return the next prime greater than or equal to N. */ -int -nextprime (unsigned n) -{ - /* Among other things, We guarantee that, for all i (0 <= i < primes_len), - primes[i] is a prime, - next_multiple[i] is a multiple of primes[i], - next_multiple[i] > primes[primes_len - 1], - next_multiple[i] is not a multiple of two unless primes[i] == 2, and - next_multiple[i] is the smallest such value. */ - static unsigned *primes, *next_multiple; - static int primes_len; - static int primes_size; - static unsigned next_sieve; /* always even */ - unsigned max_prime; - - if (! primes) - { - primes_size = 128; - primes = (unsigned *) malloc (primes_size * sizeof (*primes)); - next_multiple = (unsigned *) malloc (primes_size - * sizeof (*next_multiple)); - - primes[0] = 2; next_multiple[0] = 6; - primes[1] = 3; next_multiple[1] = 9; - primes[2] = 5; next_multiple[2] = 15; - primes_len = 3; - - next_sieve = primes[primes_len - 1] + 1; - } - - if (n <= primes[0]) - return primes[0]; - - while (n > (max_prime = primes[primes_len - 1])) - { - /* primes doesn't contain any prime large enough. Sieve from - max_prime + 1 to 2 * max_prime, looking for more primes. */ - unsigned start = next_sieve; - unsigned end = start + max_prime + 1; - char *sieve = (char *) alloca ((end - start) * sizeof (*sieve)); - int i; - - assert (sieve); - - bzero (sieve, (end - start) * sizeof (*sieve)); - - /* Make the sieve indexed by prime number, rather than - distance-from-start-to-the-prime-number. When we're done, - sieve[P] will be zero iff P is prime. - - ANSI C doesn't define what this means. Fuck them. */ - sieve -= start; - - /* Set sieve[i] for all composites i, start <= i < end. - Ignore multiples of 2. */ - for (i = 1; i < primes_len; i++) - { - unsigned twice_prime = 2 * primes[i]; - unsigned multiple; - - for (multiple = next_multiple[i]; - multiple < end; - multiple += twice_prime) - sieve[multiple] = 1; - next_multiple[i] = multiple; - } - - for (i = start + 1; i < end; i += 2) - if (! sieve[i]) - { - if (primes_len >= primes_size) - { - primes_size *= 2; - primes = (int *) realloc (primes, - primes_size * sizeof (*primes)); - next_multiple - = (int *) realloc (next_multiple, - primes_size * sizeof (*next_multiple)); - } - primes[primes_len] = i; - if (i >= SQRT_INT_MAX) - next_multiple[primes_len] = INT_MAX; - else - next_multiple[primes_len] = i * i; - primes_len++; - } - - next_sieve = end; - } - - /* Now we have at least one prime >= n. Find the smallest such. */ - { - int bottom = 0; - int top = primes_len; - - while (bottom < top) - { - int mid = (bottom + top) / 2; - - if (primes[mid] < n) - bottom = mid + 1; - else - top = mid; - } - - return primes[top]; - } -} - diff --git a/proc/proc.h b/proc/proc.h index 30886487..7943e0be 100644 --- a/proc/proc.h +++ b/proc/proc.h @@ -1,5 +1,5 @@ /* Process server definitions - Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + Copyright (C) 1992,93,94,95,96,99,2000,01 Free Software Foundation, Inc. This file is part of the GNU Hurd. @@ -23,7 +23,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #define PROC_H_INCLUDED #include <sys/resource.h> +#include <sys/mman.h> #include <hurd/ports.h> +#include <hurd/ihash.h> #include <cthreads.h> struct proc @@ -34,8 +36,8 @@ struct proc struct proc *p_gnext, **p_gprevp; /* process group */ /* Hash table pointers that point here */ - void **p_pidhashloc; /* by pid */ - void **p_taskhashloc; /* by task port */ + hurd_ihash_locp_t p_pidhashloc; /* by pid */ + hurd_ihash_locp_t p_taskhashloc; /* by task port */ /* Identification of this process */ task_t p_task; @@ -64,28 +66,31 @@ struct proc vm_address_t p_argv, p_envp; int p_status; /* to return via wait */ int p_sigcode; - - int p_exec:1; /* has called proc_mark_exec */ - int p_stopped:1; /* has called proc_mark_stop */ - int p_waited:1; /* stop has been reported to parent */ - int p_exiting:1; /* has called proc_mark_exit */ - int p_waiting:1; /* blocked in wait */ - int p_traced:1; /* has called proc_mark_traced */ - int p_nostopcld:1; /* has called proc_mark_nostopchild */ - int p_parentset:1; /* has had a parent set with proc_child */ - int p_deadmsg:1; /* hang on requests for a message port */ - int p_checkmsghangs:1; /* someone is currently hanging on us */ - int p_msgportwait:1; /* blocked in getmsgport */ - int p_noowner:1; /* has no owner known */ - int p_loginleader:1; /* leader of login collection */ - int p_dead:1; /* process is dead */ + struct rusage p_rusage; /* my usage if I'm dead, to return via wait */ + + struct rusage p_child_rusage; /* accumulates p_rusage of all dead children */ + + unsigned int p_exec:1; /* has called proc_mark_exec */ + unsigned int p_stopped:1; /* has called proc_mark_stop */ + unsigned int p_waited:1; /* stop has been reported to parent */ + unsigned int p_exiting:1; /* has called proc_mark_exit */ + unsigned int p_waiting:1; /* blocked in wait */ + unsigned int p_traced:1; /* has called proc_mark_traced */ + unsigned int p_nostopcld:1; /* has called proc_mark_nostopchild */ + unsigned int p_parentset:1; /* has had a parent set with proc_child */ + unsigned int p_deadmsg:1; /* hang on requests for a message port */ + unsigned int p_checkmsghangs:1; /* someone is currently hanging on us */ + unsigned int p_msgportwait:1; /* blocked in getmsgport */ + unsigned int p_noowner:1; /* has no owner known */ + unsigned int p_loginleader:1; /* leader of login collection */ + unsigned int p_dead:1; /* process is dead */ }; typedef struct proc *pstruct_t; struct pgrp { - void **pg_hashloc; + hurd_ihash_locp_t pg_hashloc; struct proc *pg_plist; /* member processes */ struct pgrp *pg_next, **pg_prevp; /* list of pgrps in session */ pid_t pg_pgid; @@ -95,7 +100,7 @@ struct pgrp struct session { - void **s_hashloc; + hurd_ihash_locp_t s_hashloc; pid_t s_sid; struct pgrp *s_pgrps; /* list of member pgrps */ mach_port_t s_sessionid; /* receive right */ @@ -109,10 +114,9 @@ struct login struct ids { - int i_nuids, i_ngids; - uid_t *i_uids; - gid_t *i_gids; int i_refcnt; + int i_nuids; + uid_t i_uids[0]; }; /* Structure for an exception port we are listening on. */ @@ -143,11 +147,7 @@ mach_port_t generic_port; /* messages not related to a specific proc */ struct mutex global_lock; -/* Our name for version system */ -#define OUR_SERVER_NAME "proc" -#define OUR_VERSION "0.0" - -extern inline void +static inline void __attribute__ ((unused)) process_drop (struct proc *p) { if (p) @@ -156,7 +156,6 @@ process_drop (struct proc *p) /* Forward declarations */ void complete_wait (struct proc *, int); -int nextprime (int); int check_uid (struct proc *, uid_t); void addalltasks (void); void prociterate (void (*)(struct proc *, void *), void *); @@ -169,7 +168,7 @@ int genpid (); void abort_getmsgport (struct proc *); int zombie_check_pid (pid_t); void check_message_dying (struct proc *, struct proc *); -void message_port_dead (struct proc *); +int check_msgport_death (struct proc *); void check_dead_execdata_notify (mach_port_t); void add_proc_to_hash (struct proc *); @@ -194,7 +193,10 @@ void exc_clean (void *); struct proc *add_tasks (task_t); int pidfree (pid_t); -struct proc *new_proc (task_t); +struct proc *create_startup_proc (void); +struct proc *allocate_proc (task_t); +void proc_death_notify (struct proc *); +void complete_proc (struct proc *, pid_t); void leave_pgrp (struct proc *); void join_pgrp (struct proc *); @@ -208,17 +210,6 @@ void complete_exit (struct proc *); void initialize_version_info (void); void send_signal (mach_port_t, int, mach_port_t); - -/* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get - its task port &c). If PROC2 has an owner, then PROC1 must have that uid; - otherwise, both must be in the same login collection. */ -extern inline int -check_owner (struct proc *proc1, struct proc *proc2) -{ - return - proc2->p_noowner - ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login - : check_uid (proc1, proc2->p_owner); -} + #endif diff --git a/proc/stubs.c b/proc/stubs.c index d43f2ea5..de3a9b11 100644 --- a/proc/stubs.c +++ b/proc/stubs.c @@ -1,5 +1,5 @@ /* By-hand stubs for some RPC calls - Copyright (C) 1994, 1996 Free Software Foundation + Copyright (C) 1994,96,99,2000 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -20,28 +20,55 @@ #include <hurd/hurd_types.h> #include <mach/message.h> #include <string.h> +#include <assert.h> #include "proc.h" /* From hurd/msg.defs: */ #define RPCID_SIG_POST 23000 -struct msg_spec + +struct msg_sig_post_request { - int len; - void *contents; + mach_msg_header_t head; + mach_msg_type_t signaltype; + int signal; + mach_msg_type_t sigcode_type; + natural_t sigcode; + mach_msg_type_t refporttype; + mach_port_t refport; }; -/* Send the Mach message indicated by msg_spec; call cthread_exit +/* Send the Mach message indicated by msg_spec. call cthread_exit when it has been delivered. */ -static void -blocking_message_send (struct msg_spec *message) +static any_t +blocking_message_send (any_t arg) { - cthread_wire (); - mach_msg ((mach_msg_header_t *)message->contents, MACH_SEND_MSG, - message->len, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - cthread_exit (0); + struct msg_sig_post_request *const req = arg; + error_t err; + + err = mach_msg (&req->head, MACH_SEND_MSG, sizeof *req, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + switch (err) + { + /* These are the codes that mean a pseudo-receive modified + the message buffer and we might need to clean up the send rights. + None of them should be possible in our usage. */ + case MACH_SEND_TIMED_OUT: + case MACH_SEND_INTERRUPTED: + case MACH_SEND_INVALID_NOTIFY: + case MACH_SEND_NO_NOTIFY: + case MACH_SEND_NOTIFY_IN_PROGRESS: + assert_perror (err); + break; + + default: /* Other errors are safe to ignore. */ + break; + } + + + return 0; } /* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't @@ -53,84 +80,89 @@ send_signal (mach_port_t msgport, { error_t err; - static struct + /* This message buffer might be modified by mach_msg in some error cases, + so we cannot safely use a shared static buffer. */ + struct msg_sig_post_request message = + { { - mach_msg_header_t head; - mach_msg_type_t signaltype; - int signal; - mach_msg_type_t sigcode_type; - natural_t sigcode; - mach_msg_type_t refporttype; - mach_port_t refport; - } - message = + /* Message header: */ + (MACH_MSGH_BITS_COMPLEX + | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ + sizeof message, /* msgh_size */ + msgport, /* msgh_remote_port */ + MACH_PORT_NULL, /* msgh_local_port */ + 0, /* msgh_seqno */ + RPCID_SIG_POST, /* msgh_id */ + }, { - { - /* Message header: */ - (MACH_MSGH_BITS_COMPLEX - | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, - MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */ - sizeof message, /* msgh_size */ - 0, /* msgh_remote_port */ - MACH_PORT_NULL, /* msgh_local_port */ - 0, /* msgh_seqno */ - RPCID_SIG_POST, /* msgh_id */ - }, - { - /* Type descriptor for signo */ - MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ - 32, /* msgt_size */ - 1, /* msgt_number */ - 1, /* msgt_inline */ - 0, /* msgt_longform */ - 0, /* msgt_deallocate */ - 0, /* msgt_unused */ - }, - /* Signal number */ - 0, - /* Type descriptor for sigcode */ - { - MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ - 32, /* msgt_size */ - 1, /* msgt_number */ - 1, /* msgt_inline */ - 0, /* msgt_longform */ - 0, /* msgt_deallocate */ - 0, /* msgt_unused */ - }, - /* Sigcode */ - 0, - { - /* Type descriptor for refport */ - MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ - 32, /* msgt_size */ - 1, /* msgt_number */ - 1, /* msgt_unline */ - 0, /* msgt_longform */ - 0, /* msgt_deallocate */ - 0, /* msgt_unused */ - }, - /* Reference port */ - MACH_PORT_NULL, - }; - - message.head.msgh_remote_port = msgport; - message.signal = signal; - message.refport = refport; - - err = mach_msg((mach_msg_header_t *)&message, - MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, - MACH_PORT_NULL, 0, MACH_PORT_NULL); - - if (err == MACH_SEND_TIMEOUT) + /* Type descriptor for signo */ + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Signal number */ + signal, + /* Type descriptor for sigcode */ + { + MACH_MSG_TYPE_INTEGER_32, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + /* Sigcode */ + 0, { - struct msg_spec *msg_spec = malloc (sizeof (struct msg_spec)); - - msg_spec->len = sizeof message; - msg_spec->contents = malloc (sizeof message); - bcopy (&message, msg_spec->contents, sizeof message); - - cthread_detach (cthread_fork ((cthread_fn_t) blocking_message_send, - msg_spec)); + /* Type descriptor for refport */ + MACH_MSG_TYPE_COPY_SEND, /* msgt_name */ + 32, /* msgt_size */ + 1, /* msgt_number */ + 1, /* msgt_inline */ + 0, /* msgt_longform */ + 0, /* msgt_deallocate */ + 0, /* msgt_unused */ + }, + refport + }; + + err = mach_msg ((mach_msg_header_t *)&message, + MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0, + MACH_PORT_NULL, 0, MACH_PORT_NULL); + switch (err) + { + case MACH_SEND_TIMED_OUT: + /* The send could not complete immediately, and we do not want to + block. We'll fork off another thread to do the blocking send. + The message buffer was modified by a pseudo-receive operation, so + we need to copy its modified contents into a malloc'd buffer. */ + { + struct msg_sig_post_request *copy = malloc (sizeof *copy); + if (copy) + { + memcpy (copy, &message, sizeof message); + cthread_detach (cthread_fork (blocking_message_send, copy)); + } + break; + } + + /* These are the other codes that mean a pseudo-receive modified + the message buffer and we might need to clean up the send rights. + None of them should be possible in our usage. */ + case MACH_SEND_INTERRUPTED: + case MACH_SEND_INVALID_NOTIFY: + case MACH_SEND_NO_NOTIFY: + case MACH_SEND_NOTIFY_IN_PROGRESS: + assert_perror (err); + break; + + default: /* Other errors are safe to ignore. */ + break; } } diff --git a/proc/wait.c b/proc/wait.c index 60ec58ff..6fc94e83 100644 --- a/proc/wait.c +++ b/proc/wait.c @@ -1,5 +1,5 @@ /* Implementation of wait - Copyright (C) 1994, 1995, 1996 Free Software Foundation + Copyright (C) 1994, 1995, 1996, 2001 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -19,6 +19,8 @@ #include <sys/types.h> #include <hurd/hurd_types.h> #include <sys/resource.h> +#include <sys/time.h> +#include <mach/task_info.h> #include "proc.h" @@ -32,7 +34,95 @@ #include "process_S.h" #include <mach/mig_errors.h> -#define EWOULDBLOCK EAGAIN /* XXX */ +static inline void +rusage_add (struct rusage *acc, const struct rusage *b) +{ + timeradd (&acc->ru_utime, &b->ru_utime, &acc->ru_utime); + timeradd (&acc->ru_stime, &b->ru_stime, &acc->ru_stime); + + /* Check <bits/resource.h> definition of `struct rusage' + to make sure this gets all the fields. */ + acc->ru_maxrss += b->ru_maxrss; + acc->ru_ixrss += b->ru_ixrss; + acc->ru_idrss += b->ru_idrss; + acc->ru_isrss += b->ru_isrss; + acc->ru_minflt += b->ru_minflt; + acc->ru_majflt += b->ru_majflt; + acc->ru_nswap += b->ru_nswap; + acc->ru_inblock += b->ru_inblock; + acc->ru_oublock += b->ru_oublock; + acc->ru_msgsnd += b->ru_msgsnd; + acc->ru_msgrcv += b->ru_msgrcv; + acc->ru_nsignals += b->ru_nsignals; + acc->ru_nvcsw += b->ru_nvcsw; + acc->ru_nivcsw += b->ru_nivcsw; +} + +/* XXX This is real half-assed. + + We want to collect usage statistics from dead processes to return to its + parent for its proc_wait calls and its aggregate child statistics. + + The microkernel provides no access to this information once the task is + terminated. So the best we can do is take a sample at some time while + the task is still alive but not too long before it dies. Our results + are always inaccurate, because they don't account for the final part of + the task's lifetime. But perhaps it's better than nothing at all. + + The obvious place to take this sample is in proc_mark_exit, which in + normal circumstances a task is calling immediately before terminating + itself. So in the best of cases, our data omits only the interval in + which our RPC returns to the task and it calls task_terminate. We could + take samples in other places just to have something rather than nothing + if the task dies unexpectedly (e.g. SIGKILL); but it may not be worthwhile + since the end result is never going to be accurate anyway. + + The only way to get correct results is by adding some microkernel + feature to report the task statistics data post-mortem. */ + +void +sample_rusage (struct proc *p) +{ + struct task_basic_info bi; + struct task_events_info ei; + struct task_thread_times_info tti; + mach_msg_type_number_t count; + error_t err; + + count = TASK_BASIC_INFO_COUNT; + err = task_info (p->p_task, TASK_BASIC_INFO, + (task_info_t) &bi, &count); + if (err) + memset (&bi, 0, sizeof bi); + + count = TASK_EVENTS_INFO_COUNT; + err = task_info (p->p_task, TASK_EVENTS_INFO, + (task_info_t) &ei, &count); + if (err) + memset (&ei, 0, sizeof ei); + + count = TASK_THREAD_TIMES_INFO_COUNT; + err = task_info (p->p_task, TASK_THREAD_TIMES_INFO, + (task_info_t) &tti, &count); + if (err) + memset (&tti, 0, sizeof tti); + + time_value_add (&bi.user_time, &tti.user_time); + time_value_add (&bi.system_time, &tti.system_time); + + memset (&p->p_rusage, 0, sizeof (struct rusage)); + + p->p_rusage.ru_utime.tv_sec = bi.user_time.seconds; + p->p_rusage.ru_utime.tv_usec = bi.user_time.microseconds; + p->p_rusage.ru_stime.tv_sec = bi.system_time.seconds; + p->p_rusage.ru_stime.tv_usec = bi.system_time.microseconds; + + /* These statistics map only approximately. */ + p->p_rusage.ru_majflt = ei.pageins; + p->p_rusage.ru_minflt = ei.faults - ei.pageins; + p->p_rusage.ru_msgsnd = ei.messages_sent; /* Mach IPC, not SysV IPC */ + p->p_rusage.ru_msgrcv = ei.messages_received; /* ditto */ +} /* Return nonzero if a `waitpid' on WAIT_PID by a process in MYPGRP cares about the death of PID/PGRP. */ @@ -46,11 +136,14 @@ waiter_cares (pid_t wait_pid, pid_t mypgrp, (wait_pid == WAIT_MYPGRP && pgrp == mypgrp)); } -/* A process is dying. Send SIGCHLD to the parent. Wake the parent -if it is waiting for us to exit. */ +/* A process is dying. Send SIGCHLD to the parent. + Wake the parent if it is waiting for us to exit. */ void alert_parent (struct proc *p) { + /* We accumulate the aggregate usage stats of all our dead children. */ + rusage_add (&p->p_parent->p_child_rusage, &p->p_rusage); + send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task); if (!p->p_exiting) @@ -78,73 +171,59 @@ S_proc_wait (struct proc *p, pid_t *pid_status) { int cancel; - - int child_ready (struct proc *child) + + int reap (struct proc *child) { - if (child->p_waited) + if (child->p_waited + || (!child->p_dead + && (!child->p_stopped + || !(child->p_traced || (options & WUNTRACED))))) return 0; + child->p_waited = 1; + *status = child->p_status; + *sigcode = child->p_sigcode; + *ru = child->p_rusage; /* all zeros if !p_dead */ + *pid_status = child->p_pid; if (child->p_dead) - return 1; - if (!child->p_stopped) - return 0; - if (child->p_traced || (options & WUNTRACED)) - return 1; - return 0; + complete_exit (child); + return 1; } if (!p) return EOPNOTSUPP; - + start_over: /* See if we can satisfy the request with a stopped child; also check for invalid arguments here. */ - if (!p->p_ochild) + if (!p->p_ochild) return ECHILD; - + if (pid > 0) { struct proc *child = pid_find_allow_zombie (pid); if (!child || child->p_parent != p) return ECHILD; - if (child_ready (child)) - { - child->p_waited = 1; - *status = child->p_status; - *sigcode = child->p_sigcode; - if (child->p_dead) - complete_exit (child); - bzero (ru, sizeof (struct rusage)); - *pid_status = pid; - return 0; - } + if (reap (child)) + return 0; } else { struct proc *child; int had_a_match = pid == 0; - + for (child = p->p_ochild; child; child = child->p_sib) if (waiter_cares (pid, p->p_pgrp->pg_pgid, child->p_pid, child->p_pgrp->pg_pgid)) { + if (reap (child)) + return 0; had_a_match = 1; - if (child_ready (child)) - { - child->p_waited = 1; - *status = child->p_status; - *sigcode = child->p_sigcode; - *pid_status = child->p_pid; - if (child->p_dead) - complete_exit (child); - bzero (ru, sizeof (struct rusage)); - return 0; - } } if (!had_a_match) return ECHILD; } - + if (options & WNOHANG) return EWOULDBLOCK; @@ -157,7 +236,7 @@ S_proc_wait (struct proc *p, goto start_over; } -/* Implement proc_mark_stop as described in <hurd/proc.defs>. */ +/* Implement proc_mark_stop as described in <hurd/process.defs>. */ kern_return_t S_proc_mark_stop (struct proc *p, int signo, @@ -170,20 +249,20 @@ S_proc_mark_stop (struct proc *p, p->p_status = W_STOPCODE (signo); p->p_sigcode = sigcode; p->p_waited = 0; - + if (p->p_parent->p_waiting) { condition_broadcast (&p->p_parent->p_wakeup); p->p_parent->p_waiting = 0; } - + if (!p->p_parent->p_nostopcld) send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task); return 0; } -/* Implement proc_mark_exit as described in <hurd/proc.defs>. */ +/* Implement proc_mark_exit as described in <hurd/process.defs>. */ kern_return_t S_proc_mark_exit (struct proc *p, int status, @@ -191,17 +270,22 @@ S_proc_mark_exit (struct proc *p, { if (!p) return EOPNOTSUPP; - + if (WIFSTOPPED (status)) return EINVAL; - + + sample_rusage (p); /* See comments above sample_rusage. */ + + if (p->p_exiting) + return EBUSY; + p->p_exiting = 1; p->p_status = status; p->p_sigcode = sigcode; return 0; } -/* Implement proc_mark_cont as described in <hurd/proc.defs>. */ +/* Implement proc_mark_cont as described in <hurd/process.defs>. */ kern_return_t S_proc_mark_cont (struct proc *p) { @@ -211,7 +295,7 @@ S_proc_mark_cont (struct proc *p) return 0; } -/* Implement proc_mark_traced as described in <hurd/proc.defs>. */ +/* Implement proc_mark_traced as described in <hurd/process.defs>. */ kern_return_t S_proc_mark_traced (struct proc *p) { @@ -221,7 +305,7 @@ S_proc_mark_traced (struct proc *p) return 0; } -/* Implement proc_mark_nostopchild as described in <hurd/proc.defs>. */ +/* Implement proc_mark_nostopchild as described in <hurd/process.defs>. */ kern_return_t S_proc_mod_stopchild (struct proc *p, int value) @@ -232,4 +316,3 @@ S_proc_mod_stopchild (struct proc *p, p->p_nostopcld = ! value; return 0; } - |