provide afs_osi_TimedSleep
[openafs.git] / src / afs / NBSD / 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
11 #include <afsconfig.h>
12 #include "afs/param.h"
13
14
15 #include "afs/sysincludes.h"    /* Standard vendor system headers */
16 #include "afsincludes.h"        /* Afs-based standard headers */
17 #include "afs/afs_stats.h"      /* afs statistics */
18
19 static char waitV;
20
21 void
22 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
23 {
24     AFS_STATCNT(osi_InitWaitHandle);
25     achandle->proc = (caddr_t) 0;
26 }
27
28 /* cancel osi_Wait */
29 void
30 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
31 {
32     caddr_t proc;
33
34     AFS_STATCNT(osi_CancelWait);
35     proc = achandle->proc;
36     if (proc == 0)
37         return;
38     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
39     afs_osi_Wakeup(&waitV);
40 }
41
42 /* afs_osi_Wait
43  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
44  * Returns 0 if timeout and EINTR if signalled.
45  */
46 int
47 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
48 {
49     int code;
50     afs_int32 endTime, tid;
51
52     AFS_STATCNT(osi_Wait);
53     endTime = osi_Time() + (ams / 1000);
54     if (ahandle)
55         ahandle->proc = (caddr_t) curproc;
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
75 typedef struct afs_event {
76     struct afs_event *next;     /* next in hash chain */
77     char *event;                /* lwp event: an address */
78     int refcount;               /* Is it in use? */
79     int seq;                    /* Sequence number: this is incremented
80                                  * by wakeup calls; wait will not return until
81                                  * it changes */
82     int cond;
83 } afs_event_t;
84
85 #define HASHSIZE 128
86 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
87 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
88 int afs_evhashcnt = 0;
89
90 /* Get and initialize event structure corresponding to lwp event (i.e. address)
91  * */
92 static afs_event_t *
93 afs_getevent(char *event)
94 {
95     afs_event_t *evp, *newp = 0;
96     int hashcode;
97
98     AFS_ASSERT_GLOCK();
99     hashcode = afs_evhash(event);
100     evp = afs_evhasht[hashcode];
101     while (evp) {
102         if (evp->event == event) {
103             evp->refcount++;
104             return evp;
105         }
106         if (evp->refcount == 0)
107             newp = evp;
108         evp = evp->next;
109     }
110     if (!newp) {
111         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
112         afs_evhashcnt++;
113         newp->next = afs_evhasht[hashcode];
114         afs_evhasht[hashcode] = newp;
115         newp->seq = 0;
116     }
117     newp->event = event;
118     newp->refcount = 1;
119     return newp;
120 }
121
122 /* Release the specified event */
123 #define relevent(evp) ((evp)->refcount--)
124
125
126 void
127 afs_osi_Sleep(void *event)
128 {
129     struct afs_event *evp;
130     int seq;
131
132     evp = afs_getevent(event);
133     seq = evp->seq;
134     while (seq == evp->seq) {
135         AFS_ASSERT_GLOCK();
136         assert_wait((vm_offset_t) (&evp->cond), 0);
137         AFS_GUNLOCK();
138         thread_block();
139         AFS_GLOCK();
140     }
141     relevent(evp);
142 }
143
144 int
145 afs_osi_SleepSig(void *event)
146 {
147     afs_osi_Sleep(event);
148     return 0;
149 }
150
151 /* afs_osi_TimedSleep
152  * 
153  * Arguments:
154  * event - event to sleep on
155  * ams --- max sleep time in milliseconds
156  * aintok - 1 if should sleep interruptibly
157  *
158  * Returns 0 if timeout and EINTR if signalled.
159  */
160 int
161 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
162 {
163     int code = 0;
164     struct afs_event *evp;
165     int ticks;
166
167     ticks = (ams * afs_hz) / 1000;
168
169
170     evp = afs_getevent(event);
171
172     assert_wait((vm_offset_t) (&evp->cond), aintok);
173     AFS_GUNLOCK();
174     thread_set_timeout(ticks);
175     thread_block();
176     AFS_GLOCK();
177     /*    if (current_thread()->wait_result != THREAD_AWAKENED)
178      * code = EINTR; */
179
180     relevent(evp);
181     return code;
182 }
183
184
185 int
186 afs_osi_Wakeup(void *event)
187 {
188     int ret = 1;
189     struct afs_event *evp;
190
191     evp = afs_getevent(event);
192     if (evp->refcount > 1) {
193         evp->seq++;
194         thread_wakeup((vm_offset_t) (&evp->cond));
195         ret = 0;
196     }
197     relevent(evp);
198     return ret;
199 }