Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / afs / DARWIN / osi_sleep.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include "afs/param.h"
12
13
14 #include "afs/sysincludes.h" /* Standard vendor system headers */
15 #include "afsincludes.h" /* Afs-based standard headers */
16 #include "afs/afs_stats.h" /* afs statistics */
17
18 static char waitV;
19
20 void
21 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
22 {
23 AFS_STATCNT(osi_InitWaitHandle);
24 achandle->proc = (caddr_t) 0;
25 }
26
27 /* cancel osi_Wait */
28 void
29 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
30 {
31 caddr_t proc;
32
33 AFS_STATCNT(osi_CancelWait);
34 proc = achandle->proc;
35 if (proc == 0)
36 return;
37 achandle->proc = (caddr_t) 0; /* so dude can figure out he was signalled */
38 afs_osi_Wakeup(&waitV);
39 }
40
41 /* afs_osi_Wait
42 * Waits for data on ahandle, or ams ms later. ahandle may be null.
43 * Returns 0 if timeout and EINTR if signalled.
44 */
45 int
46 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
47 {
48 int code;
49 afs_int32 endTime, tid;
50 struct proc *p = current_proc();
51
52 AFS_STATCNT(osi_Wait);
53 endTime = osi_Time() + (ams / 1000);
54 if (ahandle)
55 ahandle->proc = (caddr_t) p;
56 do {
57 AFS_ASSERT_GLOCK();
58 code = 0;
59 code = afs_osi_TimedSleep(&waitV, ams, aintok);
60
61 if (code)
62 break; /* if something happened, quit now */
63 /* if we we're cancelled, quit now */
64 if (ahandle && (ahandle->proc == (caddr_t) 0)) {
65 /* we've been signalled */
66 break;
67 }
68 } while (osi_Time() < endTime);
69 return code;
70 }
71
72
73
74 #ifdef AFS_DARWIN80_ENV
75 #define EVTLOCK_INIT(e) \
76 do { \
77 (e)->lck = lck_mtx_alloc_init(openafs_lck_grp, 0); \
78 (e)->owner = 0; \
79 } while (0)
80 #define EVTLOCK_LOCK(e) \
81 do { \
82 osi_Assert((e)->owner != current_thread()); \
83 lck_mtx_lock((e)->lck); \
84 osi_Assert((e)->owner == 0); \
85 (e)->owner = current_thread(); \
86 } while (0)
87 #define EVTLOCK_UNLOCK(e) \
88 do { \
89 osi_Assert((e)->owner == current_thread()); \
90 (e)->owner = 0; \
91 lck_mtx_unlock((e)->lck); \
92 } while (0)
93 #define EVTLOCK_DESTROY(e) lck_mtx_free((e)->lck, openafs_lck_grp)
94 #else
95 #define EVTLOCK_INIT(e)
96 #define EVTLOCK_LOCK(e)
97 #define EVTLOCK_UNLOCK(e)
98 #define EVTLOCK_DESTROY(e)
99 #endif
100 afs_event_t *afs_evhasht[AFS_EVHASHSIZE]; /* Hash table for events */
101 #define afs_evhash(event) (afs_uint32) ((((long)event)>>2) & (AFS_EVHASHSIZE-1))
102 int afs_evhashcnt = 0;
103
104 /* Get and initialize event structure corresponding to lwp event (i.e. address)
105 * */
106 static afs_event_t *
107 afs_getevent(char *event)
108 {
109 afs_event_t *evp, *oevp, *newp = 0;
110 int hashcode;
111
112 AFS_ASSERT_GLOCK();
113 hashcode = afs_evhash(event);
114 evp = afs_evhasht[hashcode];
115 while (evp) {
116 EVTLOCK_LOCK(evp);
117 if (evp->event == event) {
118 evp->refcount++;
119 return evp;
120 }
121 if (evp->refcount == 0)
122 newp = evp;
123 EVTLOCK_UNLOCK(evp);
124 evp = evp->next;
125 }
126 if (!newp) {
127 newp = osi_AllocSmallSpace(sizeof(afs_event_t));
128 afs_evhashcnt++;
129 newp->next = afs_evhasht[hashcode];
130 afs_evhasht[hashcode] = newp;
131 newp->seq = 0;
132 EVTLOCK_INIT(newp);
133 }
134 EVTLOCK_LOCK(newp);
135 newp->event = event;
136 newp->refcount = 1;
137 return newp;
138 }
139
140 /* Release the specified event */
141 #ifdef AFS_DARWIN80_ENV
142 #define relevent(evp) \
143 do { \
144 osi_Assert((evp)->owner == current_thread()); \
145 (evp)->refcount--; \
146 (evp)->owner = 0; \
147 lck_mtx_unlock((evp)->lck); \
148 } while (0)
149 #else
150 #define relevent(evp) ((evp)->refcount--)
151 #endif
152
153
154 void
155 afs_osi_Sleep(void *event)
156 {
157 struct afs_event *evp;
158 int seq;
159
160 evp = afs_getevent(event);
161 #ifdef AFS_DARWIN80_ENV
162 AFS_ASSERT_GLOCK();
163 AFS_GUNLOCK();
164 #endif
165 seq = evp->seq;
166 while (seq == evp->seq) {
167 #ifdef AFS_DARWIN80_ENV
168 evp->owner = 0;
169 msleep(event, evp->lck, PVFS, "afs_osi_Sleep", NULL);
170 evp->owner = current_thread();
171 #else
172 AFS_ASSERT_GLOCK();
173 AFS_GUNLOCK();
174 /* this is probably safe for all versions, but testing is hard */
175 sleep(event, PVFS);
176 AFS_GLOCK();
177 #endif
178 }
179 relevent(evp);
180 #ifdef AFS_DARWIN80_ENV
181 AFS_GLOCK();
182 #endif
183 }
184
185 void
186 afs_osi_fullSigMask()
187 {
188 #ifndef AFS_DARWIN80_ENV
189 struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
190
191 /* Protect original sigmask */
192 if (!user_thread->uu_oldmask) {
193 /* Back up current sigmask */
194 user_thread->uu_oldmask = user_thread->uu_sigmask;
195 /* Mask all signals */
196 user_thread->uu_sigmask = ~(sigset_t)0;
197 }
198 #endif
199 }
200
201 void
202 afs_osi_fullSigRestore()
203 {
204 #ifndef AFS_DARWIN80_ENV
205 struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
206
207 /* Protect original sigmask */
208 if (user_thread->uu_oldmask) {
209 /* Restore original sigmask */
210 user_thread->uu_sigmask = user_thread->uu_oldmask;
211 /* Clear the oldmask */
212 user_thread->uu_oldmask = (sigset_t)0;
213 }
214 #endif
215 }
216
217 int
218 afs_osi_SleepSig(void *event)
219 {
220 afs_osi_Sleep(event);
221 return 0;
222 }
223
224 /* afs_osi_TimedSleep
225 *
226 * Arguments:
227 * event - event to sleep on
228 * ams --- max sleep time in milliseconds
229 * aintok - 1 if should sleep interruptibly
230 *
231 * Returns 0 if timeout and EINTR if signalled.
232 */
233 int
234 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
235 {
236 int code = 0;
237 struct afs_event *evp;
238 int seq;
239 int prio;
240 #ifdef AFS_DARWIN80_ENV
241 struct timespec ts;
242 #else
243 int ticks;
244 #endif
245
246
247
248 evp = afs_getevent(event);
249 seq = evp->seq;
250 AFS_GUNLOCK();
251 #ifdef AFS_DARWIN80_ENV
252 if (aintok)
253 prio = PCATCH | PPAUSE;
254 else
255 prio = PVFS;
256 ts.tv_sec = ams / 1000;
257 ts.tv_nsec = (ams % 1000) * 1000000;
258 evp->owner = 0;
259 code = msleep(event, evp->lck, prio, "afs_osi_TimedSleep", &ts);
260 evp->owner = current_thread();
261 #else
262 ticks = (ams * afs_hz) / 1000;
263 /* this is probably safe for all versions, but testing is hard. */
264 /* using tsleep instead of assert_wait/thread_set_timer/thread_block
265 * allows shutdown to work in 1.4 */
266 /* lack of PCATCH does *not* prevent signal delivery, neither does
267 * a low priority. We would need to deal with ERESTART here if we
268 * wanted to mess with p->p_sigmask, and messing with p_sigignore is
269 * not the way to go.... (someone correct me if I'm wrong)
270 */
271 if (aintok)
272 prio = PCATCH | PPAUSE;
273 else
274 prio = PVFS;
275 code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
276 AFS_GLOCK();
277 #endif
278 if (seq == evp->seq)
279 code = EINTR;
280
281 relevent(evp);
282 #ifdef AFS_DARWIN80_ENV
283 AFS_GLOCK();
284 #endif
285 return code;
286 }
287
288
289 int
290 afs_osi_Wakeup(void *event)
291 {
292 struct afs_event *evp;
293 int ret = 1;
294
295 evp = afs_getevent(event);
296 if (evp->refcount > 1) {
297 evp->seq++;
298 /* this is probably safe for all versions, but testing is hard. */
299 wakeup(event);
300 ret = 0;
301 }
302 relevent(evp);
303 return ret;
304 }
305
306 void
307 shutdown_osisleep(void) {
308 struct afs_event *evp, *nevp, **pevpp;
309 int i;
310 for (i=0; i < AFS_EVHASHSIZE; i++) {
311 evp = afs_evhasht[i];
312 pevpp = &afs_evhasht[i];
313 while (evp) {
314 EVTLOCK_LOCK(evp);
315 nevp = evp->next;
316 if (evp->refcount == 0) {
317 EVTLOCK_DESTROY(evp);
318 *pevpp = evp->next;
319 osi_FreeSmallSpace(evp);
320 afs_evhashcnt--;
321 } else {
322 afs_warn("nonzero refcount in shutdown_osisleep()\n");
323 EVTLOCK_UNLOCK(evp);
324 pevpp = &evp->next;
325 }
326 evp = nevp;
327 }
328 }
329 }
330