kill macos prior to panther
[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 typedef struct afs_event {
75     struct afs_event *next;     /* next in hash chain */
76     char *event;                /* lwp event: an address */
77     int refcount;               /* Is it in use? */
78     int seq;                    /* Sequence number: this is incremented
79                                  * by wakeup calls; wait will not return until
80                                  * it changes */
81 #ifdef AFS_DARWIN80_ENV
82    lck_mtx_t *lck;
83    thread_t owner;
84 #endif
85 } afs_event_t;
86
87 #ifdef AFS_DARWIN80_ENV
88 #define EVTLOCK_INIT(e) \
89     do { \
90         (e)->lck = lck_mtx_alloc_init(openafs_lck_grp, 0); \
91         (e)->owner = 0; \
92     } while (0)
93 #define EVTLOCK_LOCK(e) \
94     do { \
95         osi_Assert((e)->owner != current_thread()); \
96         lck_mtx_lock((e)->lck); \
97         osi_Assert((e)->owner == 0); \
98         (e)->owner = current_thread(); \
99     } while (0)
100 #define EVTLOCK_UNLOCK(e) \
101     do { \
102         osi_Assert((e)->owner == current_thread()); \
103         (e)->owner = 0; \
104         lck_mtx_unlock((e)->lck); \
105     } while (0)
106 #define EVTLOCK_DESTROY(e) lck_mtx_free((e)->lck, openafs_lck_grp)
107 #else
108 #define EVTLOCK_INIT(e)
109 #define EVTLOCK_LOCK(e)
110 #define EVTLOCK_UNLOCK(e)
111 #define EVTLOCK_DESTROY(e)
112 #endif
113 #define HASHSIZE 128
114 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
115 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
116 int afs_evhashcnt = 0;
117
118 /* Get and initialize event structure corresponding to lwp event (i.e. address)
119  * */
120 static afs_event_t *
121 afs_getevent(char *event)
122 {
123     afs_event_t *evp, *oevp, *newp = 0;
124     int hashcode;
125
126     AFS_ASSERT_GLOCK();
127     hashcode = afs_evhash(event);
128     evp = afs_evhasht[hashcode];
129     while (evp) {
130         EVTLOCK_LOCK(evp);
131         if (evp->event == event) {
132             evp->refcount++;
133             return evp;
134         }
135         if (evp->refcount == 0)
136             newp = evp;
137         EVTLOCK_UNLOCK(evp);
138         evp = evp->next;
139     }
140     if (!newp) {
141         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
142         afs_evhashcnt++;
143         newp->next = afs_evhasht[hashcode];
144         afs_evhasht[hashcode] = newp;
145         newp->seq = 0;
146         EVTLOCK_INIT(newp);
147     }
148     EVTLOCK_LOCK(newp);
149     newp->event = event;
150     newp->refcount = 1;
151     return newp;
152 }
153
154 /* Release the specified event */
155 #ifdef AFS_DARWIN80_ENV
156 #define relevent(evp) \
157     do { \
158         osi_Assert((evp)->owner == current_thread()); \
159         (evp)->refcount--; \
160         (evp)->owner = 0; \
161         lck_mtx_unlock((evp)->lck); \
162     } while (0)
163 #else
164 #define relevent(evp) ((evp)->refcount--)
165 #endif
166
167
168 void
169 afs_osi_Sleep(void *event)
170 {
171     struct afs_event *evp;
172     int seq;
173
174     evp = afs_getevent(event);
175 #ifdef AFS_DARWIN80_ENV
176      AFS_ASSERT_GLOCK();
177      AFS_GUNLOCK();
178 #endif
179     seq = evp->seq;
180     while (seq == evp->seq) {
181 #ifdef AFS_DARWIN80_ENV
182         evp->owner = 0;
183         msleep(event, evp->lck, PVFS, "afs_osi_Sleep", NULL);
184         evp->owner = current_thread();
185 #else
186         AFS_ASSERT_GLOCK();
187         AFS_GUNLOCK();
188         /* this is probably safe for all versions, but testing is hard */
189         sleep(event, PVFS);
190         AFS_GLOCK();
191 #endif
192     }
193     relevent(evp);
194 #ifdef AFS_DARWIN80_ENV
195     AFS_GLOCK();
196 #endif
197 }
198
199 void 
200 afs_osi_fullSigMask()
201 {
202 #ifndef AFS_DARWIN80_ENV
203     struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
204        
205     /* Protect original sigmask */
206     if (!user_thread->uu_oldmask) {
207         /* Back up current sigmask */
208         user_thread->uu_oldmask = user_thread->uu_sigmask;
209         /* Mask all signals */
210         user_thread->uu_sigmask = ~(sigset_t)0;
211     }
212 #endif
213 }
214
215 void 
216 afs_osi_fullSigRestore()
217 {
218 #ifndef AFS_DARWIN80_ENV
219     struct uthread *user_thread = (struct uthread *)get_bsdthread_info(current_act());
220        
221     /* Protect original sigmask */
222     if (user_thread->uu_oldmask) {
223         /* Restore original sigmask */
224         user_thread->uu_sigmask = user_thread->uu_oldmask;
225         /* Clear the oldmask */
226         user_thread->uu_oldmask = (sigset_t)0;
227     }
228 #endif
229 }
230
231 int
232 afs_osi_SleepSig(void *event)
233 {
234     afs_osi_Sleep(event);
235     return 0;
236 }
237
238 /* afs_osi_TimedSleep
239  * 
240  * Arguments:
241  * event - event to sleep on
242  * ams --- max sleep time in milliseconds
243  * aintok - 1 if should sleep interruptibly
244  *
245  * Returns 0 if timeout and EINTR if signalled.
246  */
247 int
248 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
249 {
250     int code = 0;
251     struct afs_event *evp;
252     int seq;
253     int prio;
254 #ifdef AFS_DARWIN80_ENV
255     struct timespec ts;
256 #else
257     int ticks;
258 #endif
259
260
261
262     evp = afs_getevent(event);
263     seq = evp->seq;
264     AFS_GUNLOCK();
265 #ifdef AFS_DARWIN80_ENV
266     if (aintok)
267         prio = PCATCH | PPAUSE;
268     else
269         prio = PVFS;
270     ts.tv_sec = ams / 1000;
271     ts.tv_nsec = (ams % 1000) * 1000000;
272     evp->owner = 0;
273     code = msleep(event, evp->lck, prio, "afs_osi_TimedSleep", &ts);
274     evp->owner = current_thread();
275 #else
276     ticks = (ams * afs_hz) / 1000;
277     /* this is probably safe for all versions, but testing is hard. */
278     /* using tsleep instead of assert_wait/thread_set_timer/thread_block
279      * allows shutdown to work in 1.4 */
280     /* lack of PCATCH does *not* prevent signal delivery, neither does 
281      * a low priority. We would need to deal with ERESTART here if we 
282      * wanted to mess with p->p_sigmask, and messing with p_sigignore is
283      * not the way to go.... (someone correct me if I'm wrong)
284      */
285     if (aintok)
286         prio = PCATCH | PPAUSE;
287     else
288         prio = PVFS;
289     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
290     AFS_GLOCK();
291 #endif
292     if (seq == evp->seq)
293         code = EINTR;
294
295     relevent(evp);
296 #ifdef AFS_DARWIN80_ENV
297     AFS_GLOCK();
298 #endif
299     return code;
300 }
301
302
303 int
304 afs_osi_Wakeup(void *event)
305 {
306     struct afs_event *evp;
307     int ret = 1;
308
309     evp = afs_getevent(event);
310     if (evp->refcount > 1) {
311         evp->seq++;
312         /* this is probably safe for all versions, but testing is hard. */
313         wakeup(event);
314         ret = 0;
315     }
316     relevent(evp);
317     return ret;
318 }
319
320 void
321 shutdown_osisleep(void) {
322     struct afs_event *evp, *nevp, **pevpp;
323     int i;
324     for (i=0; i < HASHSIZE; i++) {
325         evp = afs_evhasht[i];
326         pevpp = &afs_evhasht[i];
327         while (evp) {
328             EVTLOCK_LOCK(evp);
329             nevp = evp->next;
330             if (evp->refcount == 0) {
331                 EVTLOCK_DESTROY(evp);
332                 *pevpp = evp->next;
333                 osi_FreeSmallSpace(evp);
334                 afs_evhashcnt--;
335             } else {
336                 EVTLOCK_UNLOCK(evp);
337                 pevpp = &evp->next;
338             }
339             evp = nevp;
340         }
341     }
342 }
343