33e16c33bbe00af0a0e0e7560414fe53c6e921de
[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
19 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
20
21 static char waitV;
22
23
24 void
25 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
26 {
27     AFS_STATCNT(osi_InitWaitHandle);
28     achandle->proc = (caddr_t) 0;
29 }
30
31 /* cancel osi_Wait */
32 void
33 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
34 {
35     caddr_t proc;
36
37     AFS_STATCNT(osi_CancelWait);
38     proc = achandle->proc;
39     if (proc == 0)
40         return;
41     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
42     afs_osi_Wakeup(&waitV);
43 }
44
45 /* afs_osi_Wait
46  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
47  * Returns 0 if timeout and EINTR if signalled.
48  */
49 int
50 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
51 {
52     int code;
53     afs_int32 endTime, tid;
54     struct proc *p = current_proc();
55
56     AFS_STATCNT(osi_Wait);
57     endTime = osi_Time() + (ams / 1000);
58     if (ahandle)
59         ahandle->proc = (caddr_t) p;
60     do {
61         AFS_ASSERT_GLOCK();
62         code = 0;
63         code = osi_TimedSleep(&waitV, ams, aintok);
64
65         if (code)
66             break;              /* if something happened, quit now */
67         /* if we we're cancelled, quit now */
68         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
69             /* we've been signalled */
70             break;
71         }
72     } while (osi_Time() < endTime);
73     return code;
74 }
75
76
77
78 typedef struct afs_event {
79     struct afs_event *next;     /* next in hash chain */
80     char *event;                /* lwp event: an address */
81     int refcount;               /* Is it in use? */
82     int seq;                    /* Sequence number: this is incremented
83                                  * by wakeup calls; wait will not return until
84                                  * it changes */
85 #ifdef AFS_DARWIN80_ENV
86    lck_mtx_t *lck;
87    thread_t owner;
88 #endif
89 } afs_event_t;
90
91 #ifdef AFS_DARWIN80_ENV
92 #define EVTLOCK_INIT(e) \
93     do { \
94         (e)->lck = lck_mtx_alloc_init(openafs_lck_grp, 0); \
95         (e)->owner = 0; \
96     } while (0)
97 #define EVTLOCK_LOCK(e) \
98     do { \
99         osi_Assert((e)->owner != current_thread()); \
100         lck_mtx_lock((e)->lck); \
101         osi_Assert((e)->owner == 0); \
102         (e)->owner = current_thread(); \
103     } while (0)
104 #define EVTLOCK_UNLOCK(e) \
105     do { \
106         osi_Assert((e)->owner == current_thread()); \
107         (e)->owner = 0; \
108         lck_mtx_unlock((e)->lck); \
109     } while (0)
110 #define EVTLOCK_DESTROY(e) lck_mtx_free((e)->lck, openafs_lck_grp)
111 #else
112 #define EVTLOCK_INIT(e)
113 #define EVTLOCK_LOCK(e)
114 #define EVTLOCK_UNLOCK(e)
115 #define EVTLOCK_DESTROY(e)
116 #endif
117 #define HASHSIZE 128
118 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
119 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
120 int afs_evhashcnt = 0;
121
122 /* Get and initialize event structure corresponding to lwp event (i.e. address)
123  * */
124 static afs_event_t *
125 afs_getevent(char *event)
126 {
127     afs_event_t *evp, *oevp, *newp = 0;
128     int hashcode;
129
130     AFS_ASSERT_GLOCK();
131     hashcode = afs_evhash(event);
132     evp = afs_evhasht[hashcode];
133     while (evp) {
134         EVTLOCK_LOCK(evp);
135         if (evp->event == event) {
136             evp->refcount++;
137             return evp;
138         }
139         if (evp->refcount == 0)
140             newp = evp;
141         EVTLOCK_UNLOCK(evp);
142         evp = evp->next;
143     }
144     if (!newp) {
145         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
146         afs_evhashcnt++;
147         newp->next = afs_evhasht[hashcode];
148         afs_evhasht[hashcode] = newp;
149         newp->seq = 0;
150         EVTLOCK_INIT(newp);
151     }
152     EVTLOCK_LOCK(newp);
153     newp->event = event;
154     newp->refcount = 1;
155     return newp;
156 }
157
158 /* Release the specified event */
159 #ifdef AFS_DARWIN80_ENV
160 #define relevent(evp) \
161     do { \
162         osi_Assert((evp)->owner == current_thread()); \
163         (evp)->refcount--; \
164         (evp)->owner = 0; \
165         lck_mtx_unlock((evp)->lck); \
166     } while (0)
167 #else
168 #define relevent(evp) ((evp)->refcount--)
169 #endif
170
171
172 void
173 afs_osi_Sleep(void *event)
174 {
175     struct afs_event *evp;
176     int seq;
177
178     evp = afs_getevent(event);
179 #ifdef AFS_DARWIN80_ENV
180      AFS_ASSERT_GLOCK();
181      AFS_GUNLOCK();
182 #endif
183     seq = evp->seq;
184     while (seq == evp->seq) {
185 #ifdef AFS_DARWIN80_ENV
186         evp->owner = 0;
187         msleep(event, evp->lck, PVFS, "afs_osi_Sleep", NULL);
188         evp->owner = current_thread();
189 #else
190         AFS_ASSERT_GLOCK();
191         AFS_GUNLOCK();
192 #ifdef AFS_DARWIN14_ENV
193         /* this is probably safe for all versions, but testing is hard */
194         sleep(event, PVFS);
195 #else
196         assert_wait((event_t) event, 0);
197         thread_block(0);
198 #endif
199         AFS_GLOCK();
200 #endif
201     }
202     relevent(evp);
203 #ifdef AFS_DARWIN80_ENV
204     AFS_GLOCK();
205 #endif
206 }
207
208 void 
209 afs_osi_fullSigMask()
210 {
211 #ifndef AFS_DARWIN80_ENV
212     struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
213        
214     /* Protect original sigmask */
215     if (!user_thread->uu_oldmask) {
216         /* Back up current sigmask */
217         user_thread->uu_oldmask = user_thread->uu_sigmask;
218         /* Mask all signals */
219         user_thread->uu_sigmask = ~(sigset_t)0;
220     }
221 #endif
222 }
223
224 void 
225 afs_osi_fullSigRestore()
226 {
227 #ifndef AFS_DARWIN80_ENV
228     struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
229        
230     /* Protect original sigmask */
231     if (user_thread->uu_oldmask) {
232         /* Restore original sigmask */
233         user_thread->uu_sigmask = user_thread->uu_oldmask;
234         /* Clear the oldmask */
235         user_thread->uu_oldmask = (sigset_t)0;
236     }
237 #endif
238 }
239
240 int
241 afs_osi_SleepSig(void *event)
242 {
243     afs_osi_Sleep(event);
244     return 0;
245 }
246
247 /* osi_TimedSleep
248  * 
249  * Arguments:
250  * event - event to sleep on
251  * ams --- max sleep time in milliseconds
252  * aintok - 1 if should sleep interruptibly
253  *
254  * Returns 0 if timeout and EINTR if signalled.
255  */
256 static int
257 osi_TimedSleep(char *event, afs_int32 ams, int aintok)
258 {
259     int code = 0;
260     struct afs_event *evp;
261     int seq;
262     int prio;
263 #ifdef AFS_DARWIN80_ENV
264     struct timespec ts;
265 #else
266     int ticks;
267 #endif
268
269
270
271     evp = afs_getevent(event);
272     seq = evp->seq;
273     AFS_GUNLOCK();
274 #ifdef AFS_DARWIN80_ENV
275     if (aintok)
276         prio = PCATCH | PPAUSE;
277     else
278         prio = PVFS;
279     ts.tv_sec = ams / 1000;
280     ts.tv_nsec = (ams % 1000) * 1000000;
281     evp->owner = 0;
282     code = msleep(event, evp->lck, prio, "afs_osi_TimedSleep", &ts);
283     evp->owner = current_thread();
284 #else
285     ticks = (ams * afs_hz) / 1000;
286 #ifdef AFS_DARWIN14_ENV
287     /* this is probably safe for all versions, but testing is hard. */
288     /* using tsleep instead of assert_wait/thread_set_timer/thread_block
289      * allows shutdown to work in 1.4 */
290     /* lack of PCATCH does *not* prevent signal delivery, neither does 
291      * a low priority. We would need to deal with ERESTART here if we 
292      * wanted to mess with p->p_sigmask, and messing with p_sigignore is
293      * not the way to go.... (someone correct me if I'm wrong)
294      */
295     if (aintok)
296         prio = PCATCH | PPAUSE;
297     else
298         prio = PVFS;
299     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
300 #else
301     assert_wait((event_t) event, aintok ? THREAD_ABORTSAFE : THREAD_UNINT);
302     thread_set_timer(ticks, NSEC_PER_SEC / hz);
303     thread_block(0);
304     code = 0;
305 #endif
306     AFS_GLOCK();
307 #endif
308     if (seq == evp->seq)
309         code = EINTR;
310
311     relevent(evp);
312 #ifdef AFS_DARWIN80_ENV
313     AFS_GLOCK();
314 #endif
315     return code;
316 }
317
318
319 int
320 afs_osi_Wakeup(void *event)
321 {
322     struct afs_event *evp;
323     int ret = 1;
324
325     evp = afs_getevent(event);
326     if (evp->refcount > 1) {
327         evp->seq++;
328 #ifdef AFS_DARWIN14_ENV
329         /* this is probably safe for all versions, but testing is hard. */
330         wakeup(event);
331 #else
332         thread_wakeup((event_t) event);
333 #endif
334         ret = 0;
335     }
336     relevent(evp);
337     return ret;
338 }
339
340 void
341 shutdown_osisleep(void) {
342     struct afs_event *evp, *nevp, **pevpp;
343     int i;
344     for (i=0; i < HASHSIZE; i++) {
345         evp = afs_evhasht[i];
346         pevpp = &afs_evhasht[i];
347         while (evp) {
348             EVTLOCK_LOCK(evp);
349             nevp = evp->next;
350             if (evp->refcount == 0) {
351                 EVTLOCK_DESTROY(evp);
352                 *pevpp = evp->next;
353                 osi_FreeSmallSpace(evp);
354                 afs_evhashcnt--;
355             } else {
356                 EVTLOCK_UNLOCK(evp);
357                 pevpp = &evp->next;
358             }
359             evp = nevp;
360         }
361     }
362 }
363