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