diff options
Diffstat (limited to 'hurd')
-rw-r--r-- | hurd/Makefile | 2 | ||||
-rw-r--r-- | hurd/hurd/port.h | 11 | ||||
-rw-r--r-- | hurd/hurd/signal.h | 5 | ||||
-rw-r--r-- | hurd/hurd/userlink.h | 99 | ||||
-rw-r--r-- | hurd/port-cleanup.c | 31 |
5 files changed, 117 insertions, 31 deletions
diff --git a/hurd/Makefile b/hurd/Makefile index 386267c..278d8ec 100644 --- a/hurd/Makefile +++ b/hurd/Makefile @@ -49,7 +49,7 @@ routines = hurdinit hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \ fopenport \ vpprintf \ ports-get ports-set hurdports hurdmsg \ - $(sig) $(dtable) hurdinline + $(sig) $(dtable) hurdinline port-cleanup sig = hurdsig hurdfault faultexc siginfo hurd-raise preempt-sig \ trampoline longjmp-ts catch-exc exc2signal hurdkill dtable = dtable port2fd new-fd alloc-fd intern-fd \ diff --git a/hurd/hurd/port.h b/hurd/hurd/port.h index a057503..9de021c 100644 --- a/hurd/hurd/port.h +++ b/hurd/hurd/port.h @@ -1,5 +1,5 @@ /* Lightweight user references for ports. -Copyright (C) 1993, 1994 Free Software Foundation, Inc. +Copyright (C) 1993, 1994, 1995 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 @@ -70,6 +70,9 @@ _hurd_port_init (struct hurd_port *port, mach_port_t init) } +/* Cleanup function for non-local exits. */ +extern void _hurd_port_cleanup (void *, jmp_buf, int); + /* Get a reference to *PORT, which is locked. Pass return value and LINK to _hurd_port_free when done. */ @@ -80,7 +83,11 @@ _hurd_port_locked_get (struct hurd_port *port, mach_port_t result; result = port->port; if (result != MACH_PORT_NULL) - _hurd_userlink_link (&port->users, link); + { + link->cleanup = &_hurd_port_cleanup; + link->cleanup_data = (void *) result; + _hurd_userlink_link (&port->users, link); + } __spin_unlock (&port->lock); return result; } diff --git a/hurd/hurd/signal.h b/hurd/hurd/signal.h index 76007d5..d88d287 100644 --- a/hurd/hurd/signal.h +++ b/hurd/hurd/signal.h @@ -79,6 +79,11 @@ struct hurd_sigstate will be passed to sigreturn after running the handler for a pending signal, instead of examining the thread state. */ struct sigcontext *context; + + /* This is the head of the thread's list of active resources; see + <hurd/userlink.h> for details. This member is only used by the + thread itself, and always inside a critical section. */ + struct hurd_userlink *active_resources; }; /* Linked list of states of all threads whose state has been asked for. */ diff --git a/hurd/hurd/userlink.h b/hurd/hurd/userlink.h index 337d46a..d61e2e2 100644 --- a/hurd/hurd/userlink.h +++ b/hurd/hurd/userlink.h @@ -1,5 +1,5 @@ /* Support for chains recording users of a resource; `struct hurd_userlink'. -Copyright (C) 1994 Free Software Foundation, Inc. +Copyright (C) 1994, 1995 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 @@ -25,19 +25,48 @@ Cambridge, MA 02139, USA. */ #define __need_NULL #include <stddef.h> - -/* This structure is simply a doubly-linked list. Users of a given - resource are recorded by their presence in a list associated with that - resource. A user attaches his own link (in local storage) to a shared - chain at the time he begins using some resource. When finished with - that resource, the user removes his link from the chain. If his link is - the last (there are no other users of the resource), and his chain has - been detached from the shared cell (the resource in the cell has been - replaced), then the user deallocates the resource that he used. */ +#include <hurd/signal.h> +#include <setjmp.h> + + +/* This structure records a link in two doubly-linked lists. + We call these the per-resource user list and the per-thread + active-resource list. + + Users of a given resource are recorded by their presence in a list + associated with that resource. A user attaches his own link (in local + storage on his stack) to a shared chain at the time he begins using some + resource. When finished with that resource, the user removes his link + from the chain. If his link is the last (there are no other users of + the resource), and his chain has been detached from the shared cell (the + resource in the cell has been replaced), then the user deallocates the + resource that he used. + + All uses of shared resources by a single thread are linked together by + its `active-resource' list; the head of this list is stored in the + per-thread sigstate structure. When the thread makes a non-local exit + (i.e. longjmp), it will examine its active-resource list, and each link + residing in a stack frame being jumped out of will be unlinked from both + the resource's user list and the thread's active-resource list, and + deallocate the resource if that was the last user link for that resource. + + NOTE: Access to a thread's active-resource list must always be done + inside a signal-proof critical section; the functions in this file + assume they are called inside a critical section, and do no locking of + their own. Also important: the longjmp cleanup relies on all userlink + structures residing on the stack of the using thread. */ struct hurd_userlink { - struct hurd_userlink *next, **prevp; + struct + { + struct hurd_userlink *next, **prevp; + } resource, thread; + + /* This function is called when a non-local exit + unwinds the frame containing this link. */ + void (*cleanup) (void *cleanup_data, jmp_buf env, int val); + void *cleanup_data; }; @@ -52,32 +81,46 @@ _EXTERN_INLINE void _hurd_userlink_link (struct hurd_userlink **chainp, struct hurd_userlink *link) { - link->next = *chainp; - if (link->next) - link->next->prevp = &link->next; - link->prevp = chainp; + struct hurd_userlink **thread_chainp; + + link->resource.next = *chainp; + if (link->resource.next) + link->resource.next->thread.prevp = &link->resource.next; + link->resource.prevp = chainp; *chainp = link; + + /* Also chain it on the current thread's list of active resources. */ + thread_chainp = &_hurd_self_sigstate ()->active_resources; + link->thread.next = *thread_chainp; + if (link->thread.next) + link->thread.next->thread.prevp = &link->thread.next; + link->thread.prevp = thread_chainp; + *thread_chainp = link; } -/* Detach LINK from its chain. If the return value is nonzero, the caller - should deallocate the resource he started using after attaching LINK to - the chain it's on. If the return value is zero, then someone else is - still using the resource. */ +/* Detach LINK from its chain. Returns nonzero iff this was the + last user of the resource and it should be deallocated. */ _EXTERN_INLINE int _hurd_userlink_unlink (struct hurd_userlink *link) { - /* The caller should deallocate the resource he used if his chain has - been detached from the cell (and thus has a nil `prevp'), and there is - no next link representing another user reference to the same resource. */ - int dealloc = ! link->next && ! link->prevp; + /* We should deallocate the resource used if this chain has been detached + from the cell (and thus has a nil `prevp'), and there is no next link + representing another user reference to the same resource. */ + int dealloc = ! link->resource.next && ! link->resource.prevp; /* Remove our link from the chain of current users. */ - if (link->prevp) - *link->prevp = link->next; - if (link->next) - link->next->prevp = link->prevp; + if (link->resource.prevp) + *link->resource.prevp = link->resource.next; + if (link->resource.next) + link->resource.next->resource.prevp = link->resource.prevp; + + /* Remove our link from the chain of currently active resources + for this thread. */ + *link->thread.prevp = link->thread.next; + if (link->thread.next) + link->thread.next->thread.prevp = link->thread.prevp; return dealloc; } @@ -97,7 +140,7 @@ _hurd_userlink_clear (struct hurd_userlink **chainp) /* Detach the chain of current users from the cell. The last user to remove his link from that chain will deallocate the old resource. */ - (*chainp)->prevp = NULL; + (*chainp)->resource.prevp = NULL; *chainp = NULL; return 0; } diff --git a/hurd/port-cleanup.c b/hurd/port-cleanup.c new file mode 100644 index 0000000..556baaa --- /dev/null +++ b/hurd/port-cleanup.c @@ -0,0 +1,31 @@ +/* Cleanup function for `struct hurd_port' users who longjmp. +Copyright (C) 1995 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 +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <mach.h> +#include <hurd/port.h> + +/* The last user of the send right CLEANUP_DATA is now doing + `longjmp (ENV, VAL)', and this will unwind the frame of + that last user. Deallocate the right he will never get back to using. */ + +void +_hurd_port_cleanup (void *cleanup_data, jmp_buf env, int val) +{ + __mach_port_deallocate (__mach_task_self (), (mach_port_t) cleanup_data); +} |