diff options
Diffstat (limited to 'hurd')
-rw-r--r-- | hurd/Versions | 3 | ||||
-rw-r--r-- | hurd/dtable.c | 103 | ||||
-rw-r--r-- | hurd/hurdfchdir.c | 39 | ||||
-rw-r--r-- | hurd/hurdioctl.c | 66 | ||||
-rw-r--r-- | hurd/hurdsig.c | 55 | ||||
-rw-r--r-- | hurd/msgportdemux.c | 10 | ||||
-rw-r--r-- | hurd/report-wait.c | 2 |
7 files changed, 188 insertions, 90 deletions
diff --git a/hurd/Versions b/hurd/Versions index 5dcdc355d9..a81bc551b2 100644 --- a/hurd/Versions +++ b/hurd/Versions @@ -108,6 +108,9 @@ libc { seteuids; } GLIBC_2.1.3 { + # c* + cthread_fork; cthread_detach; + # d* directory_name_split; diff --git a/hurd/dtable.c b/hurd/dtable.c index 30f6a5ee82..f3eb88fb3a 100644 --- a/hurd/dtable.c +++ b/hurd/dtable.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -107,18 +107,35 @@ text_set_element (_hurd_subinit, init_dtable); static file_t get_dtable_port (int fd) { + struct hurd_fd *d = _hurd_fd_get (fd); file_t dport; - int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (), - (dport = port), - MACH_PORT_RIGHT_SEND, - 1)); - if (err) - { - errno = err; - return MACH_PORT_NULL; - } - else - return dport; + + if (!d) + return __hurd_fail (EBADF), MACH_PORT_NULL; + + HURD_CRITICAL_BEGIN; + + dport = HURD_PORT_USE (&d->port, + ({ + error_t err; + mach_port_t outport; + err = __mach_port_mod_refs (__mach_task_self (), + port, + MACH_PORT_RIGHT_SEND, + 1); + if (err) + { + errno = err; + outport = MACH_PORT_NULL; + } + else + outport = port; + outport; + })); + + HURD_CRITICAL_END; + + return dport; } file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port; @@ -176,32 +193,46 @@ ctty_new_pgrp (void) HURD_CRITICAL_BEGIN; __mutex_lock (&_hurd_dtable_lock); - for (i = 0; i < _hurd_dtablesize; ++i) + if (__USEPORT (CTTYID, port == MACH_PORT_NULL)) { - struct hurd_fd *const d = _hurd_dtable[i]; - struct hurd_userlink ulink, ctty_ulink; - io_t port, ctty; - - if (d == NULL) - /* Nothing to do for an unused descriptor cell. */ - continue; - - port = _hurd_port_get (&d->port, &ulink); - ctty = _hurd_port_get (&d->ctty, &ctty_ulink); - - if (ctty != MACH_PORT_NULL) - { - /* This fd has a ctty-special port. We need a new one, to tell - the io server of our different process group. */ - io_t new; - if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new)) - new = MACH_PORT_NULL; - _hurd_port_set (&d->ctty, new); - } - - _hurd_port_free (&d->port, &ulink, port); - _hurd_port_free (&d->ctty, &ctty_ulink, ctty); + /* We have no controlling terminal. If we haven't had one recently, + but our pgrp is being pointlessly diddled anyway, then we will + have nothing to do in the loop below because no fd will have a + ctty port at all. + + More likely, a setsid call is responsible both for the change + in pgrp and for clearing the cttyid port. In that case, setsid + held the dtable lock while updating the dtable to clear all the + ctty ports, and ergo must have finished doing so before we run here. + So we can be sure, again, that the loop below has no work to do. */ } + else + for (i = 0; i < _hurd_dtablesize; ++i) + { + struct hurd_fd *const d = _hurd_dtable[i]; + struct hurd_userlink ulink, ctty_ulink; + io_t port, ctty; + + if (d == NULL) + /* Nothing to do for an unused descriptor cell. */ + continue; + + port = _hurd_port_get (&d->port, &ulink); + ctty = _hurd_port_get (&d->ctty, &ctty_ulink); + + if (ctty != MACH_PORT_NULL) + { + /* This fd has a ctty-special port. We need a new one, to tell + the io server of our different process group. */ + io_t new; + if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new)) + new = MACH_PORT_NULL; + _hurd_port_set (&d->ctty, new); + } + + _hurd_port_free (&d->port, &ulink, port); + _hurd_port_free (&d->ctty, &ctty_ulink, ctty); + } __mutex_unlock (&_hurd_dtable_lock); HURD_CRITICAL_END; diff --git a/hurd/hurdfchdir.c b/hurd/hurdfchdir.c index efb705393e..4a01f0719c 100644 --- a/hurd/hurdfchdir.c +++ b/hurd/hurdfchdir.c @@ -27,17 +27,30 @@ int _hurd_change_directory_port_from_fd (struct hurd_port *portcell, int fd) { - error_t err; - file_t dir; - - err = HURD_DPORT_USE (fd, - ({ - dir = __file_name_lookup_under (port, ".", 0, 0); - dir == MACH_PORT_NULL ? errno : 0; - })); - - if (! err) - _hurd_port_set (portcell, dir); - - return err ? __hurd_fail (err) : 0; + int ret; + struct hurd_fd *d = _hurd_fd_get (fd); + + if (!d) + return __hurd_fail (EBADF); + + HURD_CRITICAL_BEGIN; + + ret = HURD_PORT_USE (&d->port, + ({ + int ret; + file_t dir = __file_name_lookup_under (port, ".", + 0, 0); + if (dir == MACH_PORT_NULL) + ret = -1; + else + { + _hurd_port_set (portcell, dir); + ret = 0; + } + ret; + })); + + HURD_CRITICAL_END; + + return ret; } diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c index 8482571299..073c15edcc 100644 --- a/hurd/hurdioctl.c +++ b/hurd/hurdioctl.c @@ -1,5 +1,5 @@ /* ioctl commands which must be done in the C library. - Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -132,13 +132,39 @@ _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX); #include <hurd/term.h> #include <hurd/tioctl.h> -static void -rectty_dtable (mach_port_t cttyid) +/* Install a new CTTYID port, atomically updating the dtable appropriately. + This consumes the send right passed in. */ + +void +_hurd_locked_install_cttyid (mach_port_t cttyid) { + mach_port_t old; + struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID]; + struct hurd_userlink ulink; int i; - HURD_CRITICAL_BEGIN; - __mutex_lock (&_hurd_dtable_lock); + /* Install the new cttyid port, and preserve it with a ulink. + We unroll the _hurd_port_set + _hurd_port_get here so that + there is no window where the cell is unlocked and CTTYID could + be changed by another thread. (We also delay the deallocation + of the old port until the end, to minimize the duration of the + critical section.) + + It is important that changing the cttyid port is only ever done by + holding the dtable lock continuously while updating the port cell and + re-ctty'ing the dtable; dtable.c assumes we do this. Otherwise, the + pgrp-change notification code in dtable.c has to worry about racing + against us here in odd situations. The one exception to this is + setsid, which holds the dtable lock while changing the pgrp and + clearing the cttyid port, and then unlocks the dtable lock to allow + + + */ + + __spin_lock (&port->lock); + old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL; + port->port = cttyid; + cttyid = _hurd_port_locked_get (port, &ulink); for (i = 0; i < _hurd_dtablesize; ++i) { @@ -178,6 +204,18 @@ rectty_dtable (mach_port_t cttyid) } __mutex_unlock (&_hurd_dtable_lock); + + if (old != MACH_PORT_NULL) + __mach_port_deallocate (__mach_task_self (), old); + _hurd_port_free (port, &ulink, cttyid); +} + +static void +install_ctty (mach_port_t cttyid) +{ + HURD_CRITICAL_BEGIN; + __mutex_lock (&_hurd_dtable_lock); + _hurd_locked_install_cttyid (cttyid); HURD_CRITICAL_END; } @@ -199,10 +237,7 @@ _hurd_setcttyid (mach_port_t cttyid) } /* Install the port, consuming the reference we just created. */ - _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); - - /* Reset all the ctty ports in all the descriptors. */ - __USEPORT (CTTYID, (rectty_dtable (cttyid), 0)); + install_ctty (cttyid); return 0; } @@ -233,10 +268,7 @@ tiocsctty (int fd, return __hurd_fail (err); /* Make it our own. */ - _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid); - - /* Reset all the ctty ports in all the descriptors. */ - __USEPORT (CTTYID, (rectty_dtable (cttyid), 0)); + install_ctty (cttyid); return 0; } @@ -262,12 +294,8 @@ tiocnotty (int fd, if (err) return __hurd_fail (err); - /* Clear our cttyid port cell. */ - _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL); - - /* Reset all the ctty ports in all the descriptors. */ - - __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0)); + /* Clear our cttyid port. */ + install_ctty (MACH_PORT_NULL); return 0; } diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c index 2c9625b474..47f5fbf0a4 100644 --- a/hurd/hurdsig.c +++ b/hurd/hurdsig.c @@ -1227,28 +1227,47 @@ _hurdsig_init (const int *intarray, size_t intarraysize) /* Start the signal thread listening on the message port. */ - err = __thread_create (__mach_task_self (), &_hurd_msgport_thread); - assert_perror (err); + if (__hurd_threadvar_stack_mask == 0) + { + err = __thread_create (__mach_task_self (), &_hurd_msgport_thread); + assert_perror (err); - stacksize = __vm_page_size * 8; /* Small stack for signal thread. */ - err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread, - _hurd_msgport_receive, - (vm_address_t *) &__hurd_sigthread_stack_base, - &stacksize); - assert_perror (err); + stacksize = ~__hurd_threadvar_stack_mask + 1; + stacksize = __vm_page_size * 8; /* Small stack for signal thread. */ + err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread, + _hurd_msgport_receive, + (vm_address_t *) &__hurd_sigthread_stack_base, + &stacksize); + assert_perror (err); - __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize; - __hurd_sigthread_variables = - malloc (__hurd_threadvar_max * sizeof (unsigned long int)); - if (__hurd_sigthread_variables == NULL) - __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n"); + __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize; + __hurd_sigthread_variables = + malloc (__hurd_threadvar_max * sizeof (unsigned long int)); + if (__hurd_sigthread_variables == NULL) + __libc_fatal ("hurd: Can't allocate threadvars for signal thread\n"); - /* Reinitialize the MiG support routines so they will use a per-thread - variable for the cached reply port. */ - __mig_init ((void *) __hurd_sigthread_stack_base); + /* Reinitialize the MiG support routines so they will use a per-thread + variable for the cached reply port. */ + __mig_init ((void *) __hurd_sigthread_stack_base); - err = __thread_resume (_hurd_msgport_thread); - assert_perror (err); + err = __thread_resume (_hurd_msgport_thread); + assert_perror (err); + } + else + { + /* When cthreads is being used, we need to make the signal thread a + proper cthread. Otherwise it cannot use mutex_lock et al, which + will be the cthreads versions. Various of the message port RPC + handlers need to take locks, so we need to be able to call into + cthreads code and meet its assumptions about how our thread and + its stack are arranged. Since cthreads puts it there anyway, + we'll let the signal thread's per-thread variables be found as for + any normal cthread, and just leave the magic __hurd_sigthread_* + values all zero so they'll be ignored. */ +#pragma weak cthread_fork +#pragma weak cthread_detach + cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0)); + } /* Receive exceptions on the signal port. */ __task_set_special_port (__mach_task_self (), diff --git a/hurd/msgportdemux.c b/hurd/msgportdemux.c index 4250affd0b..7f61758cc3 100644 --- a/hurd/msgportdemux.c +++ b/hurd/msgportdemux.c @@ -1,5 +1,5 @@ /* Demux messages sent on the signal port. - Copyright (C) 1991, 1992, 1994, 1995, 1997 Free Software Foundation, Inc. + Copyright (C) 1991,92,94,95,97,99 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -57,8 +57,12 @@ _hurd_msgport_receive (void) { /* Get our own sigstate cached so we never again have to take a lock to fetch it. There is much code in hurdsig.c that operates with some - sigstate lock held, which will deadlock with _hurd_thread_sigstate. */ - (void) _hurd_self_sigstate (); + sigstate lock held, which will deadlock with _hurd_thread_sigstate. + + Furthermore, in the cthreads case this is the convenient spot + to initialize _hurd_msgport_thread (see hurdsig.c:_hurdsig_init). */ + + _hurd_msgport_thread = _hurd_self_sigstate ()->thread; while (1) (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport); diff --git a/hurd/report-wait.c b/hurd/report-wait.c index 41fdca1619..d0e3d47ad9 100644 --- a/hurd/report-wait.c +++ b/hurd/report-wait.c @@ -112,7 +112,7 @@ _S_msg_report_wait (mach_port_t msgport, thread_t thread, if (thread == _hurd_msgport_thread) /* Cute. */ strcpy (description, "msgport"); - else if (&_hurd_msgport_thread && thread == _hurd_itimer_thread) + else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread) strcpy (description, "itimer"); else { |