venus: Remove dedebug
[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