aboutsummaryrefslogtreecommitdiff
path: root/hurd
diff options
context:
space:
mode:
Diffstat (limited to 'hurd')
-rw-r--r--hurd/Makefile2
-rw-r--r--hurd/hurd/port.h11
-rw-r--r--hurd/hurd/signal.h5
-rw-r--r--hurd/hurd/userlink.h99
-rw-r--r--hurd/port-cleanup.c31
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);
+}