1f6310a1eb699b9e26d90af1444bc005cbfac10e
[openafs.git] / src / afs / NBSD / osi_sleep.c
1 /*
2  * $Id: osi_sleep.c,v 1.9 2005/07/26 15:25:43 rees Exp $
3  */
4
5 /*
6 copyright 2002
7 the regents of the university of michigan
8 all rights reserved
9
10 permission is granted to use, copy, create derivative works
11 and redistribute this software and such derivative works
12 for any purpose, so long as the name of the university of
13 michigan is not used in any advertising or publicity
14 pertaining to the use or distribution of this software
15 without specific, written prior authorization.  if the
16 above copyright notice or any other identification of the
17 university of michigan is included in any copy of any
18 portion of this software, then the disclaimer below must
19 also be included.
20
21 this software is provided as is, without representation
22 from the university of michigan as to its fitness for any
23 purpose, and without warranty by the university of
24 michigan of any kind, either express or implied, including
25 without limitation the implied warranties of
26 merchantability and fitness for a particular purpose. the
27 regents of the university of michigan shall not be liable
28 for any damages, including special, indirect, incidental, or
29 consequential damages, with respect to any claim arising
30 out of or in connection with the use of the software, even
31 if it has been or is hereafter advised of the possibility of
32 such damages.
33 */
34
35 /*
36  * Copyright 2000, International Business Machines Corporation and others.
37  * All Rights Reserved.
38  *
39  * This software has been released under the terms of the IBM Public
40  * License.  For details, see the LICENSE file in the top-level source
41  * directory or online at http://www.openafs.org/dl/license10.html
42  */
43
44 #include <afsconfig.h>
45 #include "afs/param.h"
46
47 #include "afs/sysincludes.h"    /* Standard vendor system headers */
48 #include "afs/afsincludes.h"    /* Afs-based standard headers */
49 #include "afs/afs_stats.h"      /* afs statistics */
50
51 #if !defined(AFS_NBSD50_ENV)
52 static char waitV;
53
54 /* cancel osi_Wait */
55 void
56 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
57 {
58     caddr_t proc;
59
60     AFS_STATCNT(osi_CancelWait);
61     proc = achandle->proc;
62     if (proc == NULL)
63         return;
64     achandle->proc = NULL;
65     wakeup(&waitV);
66 }
67
68 /* afs_osi_Wait
69  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
70  * Returns 0 if timeout and EINTR if signalled.
71  */
72 int
73 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
74 {
75     int timo, code = 0;
76     struct timeval atv, time_now, endTime;
77     const struct timeval timezero = { 0, 0 };
78
79     AFS_STATCNT(osi_Wait);
80
81     atv.tv_sec = ams / 1000;
82     atv.tv_usec = (ams % 1000) * 1000;
83     getmicrouptime(&time_now);
84     timeradd(&atv, &time_now, &endTime);
85
86     if (ahandle)
87         ahandle->proc = (caddr_t) osi_curproc();
88     AFS_ASSERT_GLOCK();
89     AFS_GUNLOCK();
90
91     do {
92         timersub(&endTime, &time_now, &atv);
93         if (timercmp(&atv, &timezero, <))
94             break;
95         timo = tvtohz(&atv);
96         if (aintok) {
97             code = tsleep(&waitV, PCATCH | PVFS, "afs_W1", timo);
98         } else {
99             code = tsleep(&waitV, PVFS, "afs_W2", timo);
100         }
101         if (code)
102             code = (code == EWOULDBLOCK) ? 0 : EINTR;
103
104         getmicrouptime(&time_now);
105
106         /* if we were cancelled, quit now */
107         if (ahandle && (ahandle->proc == NULL)) {
108             /* we've been signalled */
109             break;
110         }
111     } while (timercmp(&time_now, &endTime, <));
112
113     AFS_GLOCK();
114
115     return code;
116 }
117
118 void
119 afs_osi_Sleep(void *event)
120 {
121     AFS_ASSERT_GLOCK();
122     AFS_GUNLOCK();
123     tsleep(event, PVFS, "afsslp", 0);
124     AFS_GLOCK();
125 }
126
127 int
128 afs_osi_SleepSig(void *event)
129 {
130     afs_osi_Sleep(event);
131     return 0;
132 }
133
134 int
135 afs_osi_Wakeup(void *event)
136 {
137     wakeup(event);
138     return 1;
139 }
140 #else
141 static char waitV;
142
143 void
144 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
145 {
146     AFS_STATCNT(osi_InitWaitHandle);
147     achandle->proc = (caddr_t) 0;
148 }
149
150 /* cancel osi_Wait */
151 void
152 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
153 {
154     caddr_t proc;
155
156     AFS_STATCNT(osi_CancelWait);
157     proc = achandle->proc;
158     if (proc == 0)
159         return;
160     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
161     afs_osi_Wakeup(&waitV);
162 }
163
164 /* afs_osi_Wait
165  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
166  * Returns 0 if timeout and EINTR if signalled.
167  */
168 int
169 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
170 {
171     int code;
172     afs_int32 endTime;
173
174     AFS_STATCNT(osi_Wait);
175     endTime = osi_Time() + (ams / 1000);
176     if (ahandle)
177         ahandle->proc = (caddr_t) osi_curproc();
178     do {
179         AFS_ASSERT_GLOCK();
180         code = afs_osi_TimedSleep(&waitV, ams, aintok);
181
182         if (code)
183             break;              /* if something happened, quit now */
184         /* if we we're cancelled, quit now */
185         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
186             /* we've been signalled */
187             break;
188         }
189     } while (osi_Time() < endTime);
190     return code;
191 }
192
193
194
195
196 typedef struct afs_event {
197     struct afs_event *next;     /* next in hash chain */
198     char *event;                /* lwp event: an address */
199     int refcount;               /* Is it in use? */
200     int seq;                    /* Sequence number: this is incremented
201                                  * by wakeup calls; wait will not return until
202                                  * it changes */
203     kcondvar_t cond;            /* Currently associated condition variable */
204 } afs_event_t;
205
206 #define HASHSIZE 128
207 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
208 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
209 int afs_evhashcnt = 0;
210
211 /* Get and initialize event structure corresponding to lwp event (i.e. address)
212  * */
213 static afs_event_t *
214 afs_getevent(char *event)
215 {
216     afs_event_t *evp, *newp = 0;
217     int hashcode;
218
219     AFS_ASSERT_GLOCK();
220     hashcode = afs_evhash(event);
221     evp = afs_evhasht[hashcode];
222     while (evp) {
223         if (evp->event == event) {
224             evp->refcount++;
225             return evp;
226         }
227         if (evp->refcount == 0)
228             newp = evp;
229         evp = evp->next;
230     }
231     if (!newp) {
232         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
233         afs_evhashcnt++;
234         newp->next = afs_evhasht[hashcode];
235         afs_evhasht[hashcode] = newp;
236         cv_init(&newp->cond, "afsevent");
237         newp->seq = 0;
238     }
239     newp->event = event;
240     newp->refcount = 1;
241     return newp;
242 }
243
244 /* Release the specified event */
245 #define relevent(evp) ((evp)->refcount--)
246
247
248 void
249 afs_osi_Sleep(void *event)
250 {
251     struct afs_event *evp;
252     int seq;
253
254     evp = afs_getevent(event);
255     seq = evp->seq;
256     while (seq == evp->seq) {
257         AFS_ASSERT_GLOCK();
258         cv_wait(&evp->cond, &afs_global_mtx);
259     }
260     relevent(evp);
261 }
262
263 int
264 afs_osi_SleepSig(void *event)
265 {
266     struct afs_event *evp;
267     int seq, code = 0;
268
269     evp = afs_getevent(event);
270     seq = evp->seq;
271     while (seq == evp->seq) {
272         AFS_ASSERT_GLOCK();
273         code = cv_wait_sig(&evp->cond, &afs_global_mtx);
274         if (code) {
275             code = (code == EWOULDBLOCK) ? 0 : EINTR;
276             break;
277         }
278     }
279     relevent(evp);
280     return code;
281 }
282
283 /* afs_osi_TimedSleep
284  *
285  * Arguments:
286  * event - event to sleep on
287  * ams --- max sleep time in milliseconds
288  * aintok - 1 if should sleep interruptibly
289  *
290  * Returns 0 if timeout and EINTR if signalled.
291  */
292 int
293 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
294 {
295     int code;
296     struct afs_event *evp;
297     int ticks;
298
299     ticks = mstohz(ams);
300     ticks = ticks ? ticks : 1;
301     evp = afs_getevent(event);
302
303     AFS_ASSERT_GLOCK();
304     if (aintok) {
305         code = cv_timedwait_sig(&evp->cond, &afs_global_mtx, ticks);
306     } else {
307         code = cv_timedwait(&evp->cond, &afs_global_mtx, ticks);
308     }
309
310     switch (code) {
311     default:
312         code = EINTR;
313         break;
314     case EWOULDBLOCK:
315         code = 0;
316         break;
317     }
318
319     relevent(evp);
320     return code;
321 }
322
323
324 int
325 afs_osi_Wakeup(void *event)
326 {
327     int ret = 1;
328     struct afs_event *evp;
329
330     evp = afs_getevent(event);
331     if (evp->refcount > 1) {
332         evp->seq++;
333         cv_broadcast(&evp->cond);
334         ret = 0;
335     }
336     relevent(evp);
337     return 0;
338 }
339 #endif