]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* Lightweight user references for ports. |
bfff8b1b | 2 | Copyright (C) 1993-2017 Free Software Foundation, Inc. |
c84142e8 UD |
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 | |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
c84142e8 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
c84142e8 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
28f540f4 RM |
18 | |
19 | #ifndef _HURD_PORT_H | |
20 | ||
21 | #define _HURD_PORT_H 1 | |
22 | #include <features.h> | |
23 | ||
24 | #include <mach.h> | |
25 | #include <hurd/userlink.h> | |
26 | #include <spin-lock.h> | |
27 | #include <hurd/signal.h> | |
28 | ||
29 | ||
30 | /* Structure describing a cell containing a port. With the lock held, a | |
31 | user extracts PORT, and attaches his own link (in local storage) to the | |
32 | USERS chain. PORT can then safely be used. When PORT is no longer | |
33 | needed, with the lock held, the user removes his link from the chain. | |
34 | If his link is the last, and PORT has changed since he fetched it, the | |
35 | user deallocates the port he used. See <hurd/userlink.h>. */ | |
36 | ||
37 | struct hurd_port | |
38 | { | |
39 | spin_lock_t lock; /* Locks rest. */ | |
40 | struct hurd_userlink *users; /* Chain of users; see below. */ | |
41 | mach_port_t port; /* Port. */ | |
42 | }; | |
43 | ||
44 | ||
45 | /* Evaluate EXPR with the variable `port' bound to the port in PORTCELL. */ | |
46 | ||
47 | #define HURD_PORT_USE(portcell, expr) \ | |
48 | ({ struct hurd_port *const __p = (portcell); \ | |
49 | struct hurd_userlink __link; \ | |
50 | const mach_port_t port = _hurd_port_get (__p, &__link); \ | |
51 | __typeof(expr) __result = (expr); \ | |
52 | _hurd_port_free (__p, &__link, port); \ | |
53 | __result; }) | |
54 | ||
55 | ||
6f9dc08b | 56 | #ifndef _HURD_PORT_H_EXTERN_INLINE |
b037a293 | 57 | #define _HURD_PORT_H_EXTERN_INLINE __extern_inline |
28f540f4 RM |
58 | #endif |
59 | ||
60 | ||
61 | /* Initialize *PORT to INIT. */ | |
62 | ||
6f9dc08b | 63 | _HURD_PORT_H_EXTERN_INLINE void |
28f540f4 RM |
64 | _hurd_port_init (struct hurd_port *port, mach_port_t init) |
65 | { | |
66 | __spin_lock_init (&port->lock); | |
67 | port->users = NULL; | |
68 | port->port = init; | |
69 | } | |
70 | ||
71 | ||
1474b80f RM |
72 | /* Cleanup function for non-local exits. */ |
73 | extern void _hurd_port_cleanup (void *, jmp_buf, int); | |
74 | ||
28f540f4 RM |
75 | /* Get a reference to *PORT, which is locked. |
76 | Pass return value and LINK to _hurd_port_free when done. */ | |
77 | ||
6f9dc08b | 78 | _HURD_PORT_H_EXTERN_INLINE mach_port_t |
28f540f4 RM |
79 | _hurd_port_locked_get (struct hurd_port *port, |
80 | struct hurd_userlink *link) | |
81 | { | |
82 | mach_port_t result; | |
83 | result = port->port; | |
84 | if (result != MACH_PORT_NULL) | |
1474b80f RM |
85 | { |
86 | link->cleanup = &_hurd_port_cleanup; | |
87 | link->cleanup_data = (void *) result; | |
88 | _hurd_userlink_link (&port->users, link); | |
89 | } | |
28f540f4 RM |
90 | __spin_unlock (&port->lock); |
91 | return result; | |
92 | } | |
93 | ||
94 | /* Same, but locks PORT first. */ | |
95 | ||
6f9dc08b | 96 | _HURD_PORT_H_EXTERN_INLINE mach_port_t |
28f540f4 RM |
97 | _hurd_port_get (struct hurd_port *port, |
98 | struct hurd_userlink *link) | |
99 | { | |
100 | mach_port_t result; | |
101 | HURD_CRITICAL_BEGIN; | |
102 | __spin_lock (&port->lock); | |
103 | result = _hurd_port_locked_get (port, link); | |
104 | HURD_CRITICAL_END; | |
105 | return result; | |
106 | } | |
107 | ||
108 | ||
109 | /* Free a reference gotten with `USED_PORT = _hurd_port_get (PORT, LINK);' */ | |
110 | ||
6f9dc08b | 111 | _HURD_PORT_H_EXTERN_INLINE void |
28f540f4 RM |
112 | _hurd_port_free (struct hurd_port *port, |
113 | struct hurd_userlink *link, | |
114 | mach_port_t used_port) | |
115 | { | |
116 | int dealloc; | |
117 | if (used_port == MACH_PORT_NULL) | |
118 | /* When we fetch an empty port cell with _hurd_port_get, | |
119 | it does not link us on the users chain, since there is | |
120 | no shared resource. */ | |
121 | return; | |
122 | HURD_CRITICAL_BEGIN; | |
123 | __spin_lock (&port->lock); | |
124 | dealloc = _hurd_userlink_unlink (link); | |
125 | __spin_unlock (&port->lock); | |
126 | HURD_CRITICAL_END; | |
127 | if (dealloc) | |
128 | __mach_port_deallocate (__mach_task_self (), used_port); | |
129 | } | |
130 | ||
131 | ||
132 | /* Set *PORT's port to NEWPORT. NEWPORT's reference is consumed by PORT->port. | |
133 | PORT->lock is locked. */ | |
134 | ||
6f9dc08b | 135 | _HURD_PORT_H_EXTERN_INLINE void |
28f540f4 RM |
136 | _hurd_port_locked_set (struct hurd_port *port, mach_port_t newport) |
137 | { | |
138 | mach_port_t old; | |
139 | old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL; | |
140 | port->port = newport; | |
141 | __spin_unlock (&port->lock); | |
142 | if (old != MACH_PORT_NULL) | |
143 | __mach_port_deallocate (__mach_task_self (), old); | |
144 | } | |
145 | ||
146 | /* Same, but locks PORT first. */ | |
147 | ||
6f9dc08b | 148 | _HURD_PORT_H_EXTERN_INLINE void |
28f540f4 RM |
149 | _hurd_port_set (struct hurd_port *port, mach_port_t newport) |
150 | { | |
151 | HURD_CRITICAL_BEGIN; | |
152 | __spin_lock (&port->lock); | |
153 | _hurd_port_locked_set (port, newport); | |
154 | HURD_CRITICAL_END; | |
155 | } | |
156 | ||
157 | ||
158 | #endif /* hurd/port.h */ |