* hurd.h, hurd/hurd/fd.h, hurd/hurd/port.h, hurd/hurd/signal.h,
[platform/upstream/glibc.git] / hurd / hurd / userlink.h
1 /* Support for chains recording users of a resource; `struct hurd_userlink'.
2    Copyright (C) 1994, 1995, 1997, 1999 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #ifndef _HURD_USERLINK_H
21
22 #define _HURD_USERLINK_H        1
23 #include <features.h>
24
25 #define __need_NULL
26 #include <stddef.h>
27
28 #include <hurd/signal.h>
29 #include <setjmp.h>
30
31
32 /* This structure records a link in two doubly-linked lists.
33    We call these the per-resource user list and the per-thread
34    active-resource list.
35
36    Users of a given resource are recorded by their presence in a list
37    associated with that resource.  A user attaches his own link (in local
38    storage on his stack) to a shared chain at the time he begins using some
39    resource.  When finished with that resource, the user removes his link
40    from the chain.  If his link is the last (there are no other users of
41    the resource), and his chain has been detached from the shared cell (the
42    resource in the cell has been replaced), then the user deallocates the
43    resource that he used.
44
45    All uses of shared resources by a single thread are linked together by
46    its `active-resource' list; the head of this list is stored in the
47    per-thread sigstate structure.  When the thread makes a non-local exit
48    (i.e. longjmp), it will examine its active-resource list, and each link
49    residing in a stack frame being jumped out of will be unlinked from both
50    the resource's user list and the thread's active-resource list, and
51    deallocate the resource if that was the last user link for that resource.
52
53    NOTE: Access to a thread's active-resource list must always be done
54    inside a signal-proof critical section; the functions in this file
55    assume they are called inside a critical section, and do no locking of
56    their own.  Also important: the longjmp cleanup relies on all userlink
57    structures residing on the stack of the using thread.  */
58
59 struct hurd_userlink
60   {
61     struct
62       {
63         struct hurd_userlink *next, **prevp;
64       } resource, thread;
65
66     /* This function is called when a non-local exit
67        unwinds the frame containing this link.  */
68     void (*cleanup) (void *cleanup_data, jmp_buf env, int val);
69     void *cleanup_data;
70   };
71
72
73 #ifndef _HURD_USERLINK_H_EXTERN_INLINE
74 #define _HURD_USERLINK_H_EXTERN_INLINE extern __inline
75 #endif
76
77
78 /* Attach LINK to the chain of users at *CHAINP.  */
79
80 _HURD_USERLINK_H_EXTERN_INLINE void
81 _hurd_userlink_link (struct hurd_userlink **chainp,
82                      struct hurd_userlink *link)
83 {
84   struct hurd_userlink **thread_chainp;
85
86   link->resource.next = *chainp;
87   if (link->resource.next)
88     link->resource.next->resource.prevp = &link->resource.next;
89   link->resource.prevp = chainp;
90   *chainp = link;
91
92   /* Also chain it on the current thread's list of active resources.  */
93   thread_chainp = &_hurd_self_sigstate ()->active_resources;
94   link->thread.next = *thread_chainp;
95   if (link->thread.next)
96     link->thread.next->thread.prevp = &link->thread.next;
97   link->thread.prevp = thread_chainp;
98   *thread_chainp = link;
99 }
100
101
102 /* Detach LINK from its chain.  Returns nonzero iff this was the
103    last user of the resource and it should be deallocated.  */
104
105 _HURD_USERLINK_H_EXTERN_INLINE int
106 _hurd_userlink_unlink (struct hurd_userlink *link)
107 {
108   /* We should deallocate the resource used if this chain has been detached
109      from the cell (and thus has a nil `prevp'), and there is no next link
110      representing another user reference to the same resource. */
111   int dealloc = ! link->resource.next && ! link->resource.prevp;
112
113   /* Remove our link from the chain of current users.  */
114   if (link->resource.prevp)
115     *link->resource.prevp = link->resource.next;
116   if (link->resource.next)
117     link->resource.next->resource.prevp = link->resource.prevp;
118
119   /* Remove our link from the chain of currently active resources
120      for this thread.  */
121   *link->thread.prevp = link->thread.next;
122   if (link->thread.next)
123     link->thread.next->thread.prevp = link->thread.prevp;
124
125   return dealloc;
126 }
127
128
129 /* Clear all users from *CHAINP.  Call this when the resource *CHAINP
130    protects is changing.  If the return value is nonzero, no users are on
131    the chain and the caller should deallocate the resource.  If the return
132    value is zero, someone is still using the resource and they will
133    deallocate it when they are finished.  */
134
135 _HURD_USERLINK_H_EXTERN_INLINE int
136 _hurd_userlink_clear (struct hurd_userlink **chainp)
137 {
138   if (*chainp == NULL)
139     return 1;
140
141   /* Detach the chain of current users from the cell.  The last user to
142      remove his link from that chain will deallocate the old resource.  */
143   (*chainp)->resource.prevp = NULL;
144   *chainp = NULL;
145   return 0;
146 }
147
148 #endif  /* hurd/userlink.h */