76dab435d5481ceb3420a6ebcde5301eb173b0c8
[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 afs_event_t *afs_evhasht[AFS_EVHASHSIZE];       /* Hash table for events */
197 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (AFS_EVHASHSIZE-1));
198 int afs_evhashcnt = 0;
199
200 /* Get and initialize event structure corresponding to lwp event (i.e. address)
201  * */
202 static afs_event_t *
203 afs_getevent(char *event)
204 {
205     afs_event_t *evp, *newp = 0;
206     int hashcode;
207
208     AFS_ASSERT_GLOCK();
209     hashcode = afs_evhash(event);
210     evp = afs_evhasht[hashcode];
211     while (evp) {
212         if (evp->event == event) {
213             evp->refcount++;
214             return evp;
215         }
216         if (evp->refcount == 0)
217             newp = evp;
218         evp = evp->next;
219     }
220     if (!newp) {
221         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
222         afs_evhashcnt++;
223         newp->next = afs_evhasht[hashcode];
224         afs_evhasht[hashcode] = newp;
225         cv_init(&newp->cond, "afsevent");
226         newp->seq = 0;
227     }
228     newp->event = event;
229     newp->refcount = 1;
230     return newp;
231 }
232
233 /* Release the specified event */
234 #define relevent(evp) ((evp)->refcount--)
235
236
237 void
238 afs_osi_Sleep(void *event)
239 {
240     struct afs_event *evp;
241     int seq;
242
243     evp = afs_getevent(event);
244     seq = evp->seq;
245     while (seq == evp->seq) {
246         AFS_ASSERT_GLOCK();
247         cv_wait(&evp->cond, &afs_global_mtx);
248     }
249     relevent(evp);
250 }
251
252 int
253 afs_osi_SleepSig(void *event)
254 {
255     struct afs_event *evp;
256     int seq, code = 0;
257
258     evp = afs_getevent(event);
259     seq = evp->seq;
260     while (seq == evp->seq) {
261         AFS_ASSERT_GLOCK();
262         code = cv_wait_sig(&evp->cond, &afs_global_mtx);
263         if (code) {
264             code = (code == EWOULDBLOCK) ? 0 : EINTR;
265             break;
266         }
267     }
268     relevent(evp);
269     return code;
270 }
271
272 /* afs_osi_TimedSleep
273  *
274  * Arguments:
275  * event - event to sleep on
276  * ams --- max sleep time in milliseconds
277  * aintok - 1 if should sleep interruptibly
278  *
279  * Returns 0 if timeout and EINTR if signalled.
280  */
281 int
282 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
283 {
284     int code;
285     struct afs_event *evp;
286     int ticks;
287
288     ticks = mstohz(ams);
289     ticks = ticks ? ticks : 1;
290     evp = afs_getevent(event);
291
292     AFS_ASSERT_GLOCK();
293     if (aintok) {
294         code = cv_timedwait_sig(&evp->cond, &afs_global_mtx, ticks);
295     } else {
296         code = cv_timedwait(&evp->cond, &afs_global_mtx, ticks);
297     }
298
299     switch (code) {
300     default:
301         code = EINTR;
302         break;
303     case EWOULDBLOCK:
304         code = 0;
305         break;
306     }
307
308     relevent(evp);
309     return code;
310 }
311
312
313 int
314 afs_osi_Wakeup(void *event)
315 {
316     int ret = 1;
317     struct afs_event *evp;
318
319     evp = afs_getevent(event);
320     if (evp->refcount > 1) {
321         evp->seq++;
322         cv_broadcast(&evp->cond);
323         ret = 0;
324     }
325     relevent(evp);
326     return 0;
327 }
328 #endif