466e280d96e43bac95a468eeb3a2022f1e84bcf4
[openafs.git] / src / afs / FBSD / 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 #ifndef AFS_FBSD50_ENV
20 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
21 static char waitV;
22 #endif
23
24
25 void
26 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
27 {
28     AFS_STATCNT(osi_InitWaitHandle);
29 #ifdef AFS_FBSD50_ENV
30     cv_init(&achandle->wh_condvar, "afscondvar");
31     achandle->wh_inited = 1;
32 #else
33     achandle->proc = NULL;
34 #endif
35 }
36
37 /* cancel osi_Wait */
38 /* XXX
39  * I can't tell -- is this supposed to be cv_signal() or cv_waitq_remove()?
40  * Or perhaps cv_broadcast()?
41  * Assuming cv_signal() is the desired meaning.  -GAW
42  */
43 void
44 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
45 {
46 #ifndef AFS_FBSD50_ENV
47     caddr_t proc;
48 #endif
49
50     AFS_STATCNT(osi_CancelWait);
51
52 #ifdef AFS_FBSD50_ENV
53     /* XXX should not be necessary */
54     if (!achandle->wh_inited)
55         return;
56     AFS_ASSERT_GLOCK();
57     cv_signal(&achandle->wh_condvar);
58 #else
59     proc = achandle->proc;
60     if (proc == 0)
61         return;
62     achandle->proc = NULL;      /* so dude can figure out he was signalled */
63     afs_osi_Wakeup(&waitV);
64 #endif
65 }
66
67 /* afs_osi_Wait
68  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
69  * Returns 0 if timeout and EINTR if signalled.
70  */
71 int
72 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
73 {
74     int code;
75 #ifdef AFS_FBSD50_ENV
76     struct timeval tv;
77     int ticks;
78 #else
79     afs_int32 endTime;
80 #endif
81
82     AFS_STATCNT(osi_Wait);
83 #ifdef AFS_FBSD50_ENV
84     tv.tv_sec = ams / 1000;
85     tv.tv_usec = (ams % 1000) * 1000;
86     ticks = tvtohz(&tv);
87
88     AFS_ASSERT_GLOCK();
89     if (ahandle == NULL) {
90         /* This is nasty and evil and rude. */
91         code = msleep(&tv, &afs_global_mtx, (aintok ? PPAUSE|PCATCH : PVFS),
92             "afswait", ticks);
93     } else {
94         if (!ahandle->wh_inited)
95             afs_osi_InitWaitHandle(ahandle);    /* XXX should not be needed */
96
97         if (aintok)
98             code = cv_timedwait_sig(&ahandle->wh_condvar, &afs_global_mtx,
99                 ticks);
100         else
101             code = cv_timedwait(&ahandle->wh_condvar, &afs_global_mtx, ticks);
102     }
103 #else
104     endTime = osi_Time() + (ams / 1000);
105     if (ahandle)
106         ahandle->proc = (caddr_t) curproc;
107     do {
108         AFS_ASSERT_GLOCK();
109         code = osi_TimedSleep(&waitV, ams, aintok);
110         if (code)
111             break;              /* if something happened, quit now */
112         /* if we we're cancelled, quit now */
113         if (ahandle && (ahandle->proc == NULL)) {
114             /* we've been signalled */
115             break;
116         }
117     } while (osi_Time() < endTime);
118 #endif
119     return code;
120 }
121
122 /*
123  * All this gluck should probably also be replaced with CVs.
124  */
125 typedef struct afs_event {
126     struct afs_event *next;     /* next in hash chain */
127     char *event;                /* lwp event: an address */
128     int refcount;               /* Is it in use? */
129     int seq;                    /* Sequence number: this is incremented
130                                  * by wakeup calls; wait will not return until
131                                  * it changes */
132     int cond;
133 } afs_event_t;
134
135 #define HASHSIZE 128
136 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
137 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
138 int afs_evhashcnt = 0;
139
140 /* Get and initialize event structure corresponding to lwp event (i.e. address)
141  * */
142 static afs_event_t *
143 afs_getevent(char *event)
144 {
145     afs_event_t *evp, *newp = 0;
146     int hashcode;
147
148     AFS_ASSERT_GLOCK();
149     hashcode = afs_evhash(event);
150     evp = afs_evhasht[hashcode];
151     while (evp) {
152         if (evp->event == event) {
153             evp->refcount++;
154             return evp;
155         }
156         if (evp->refcount == 0)
157             newp = evp;
158         evp = evp->next;
159     }
160     if (!newp) {
161         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
162         afs_evhashcnt++;
163         newp->next = afs_evhasht[hashcode];
164         afs_evhasht[hashcode] = newp;
165         newp->seq = 0;
166     }
167     newp->event = event;
168     newp->refcount = 1;
169     return newp;
170 }
171
172 /* Release the specified event */
173 #define relevent(evp) ((evp)->refcount--)
174
175
176 void
177 afs_osi_Sleep(void *event)
178 {
179     struct afs_event *evp;
180     int seq;
181
182     evp = afs_getevent(event);
183     seq = evp->seq;
184     while (seq == evp->seq) {
185         AFS_ASSERT_GLOCK();
186 #ifdef AFS_FBSD50_ENV
187         msleep(event, &afs_global_mtx, PVFS, "afsslp", 0);
188 #else
189         AFS_GUNLOCK();
190         tsleep(event, PVFS, "afs_osi_Sleep", 0);
191         AFS_GLOCK();
192 #endif
193     }
194     relevent(evp);
195 }
196
197 int
198 afs_osi_SleepSig(void *event)
199 {
200     afs_osi_Sleep(event);
201     return 0;
202 }
203
204 #ifndef AFS_FBSD50_ENV
205 /* osi_TimedSleep
206  * 
207  * Arguments:
208  * event - event to sleep on
209  * ams --- max sleep time in milliseconds
210  * aintok - 1 if should sleep interruptibly
211  *
212  * Returns 0 if timeout and EINTR if signalled.
213  */
214 static int
215 osi_TimedSleep(char *event, afs_int32 ams, int aintok)
216 {
217     int code = 0;
218     struct afs_event *evp;
219     int ticks;
220     int seq, prio;
221
222     ticks = (ams * afs_hz) / 1000;
223
224
225     evp = afs_getevent(event);
226     seq = evp->seq;
227     AFS_GUNLOCK();
228     if (aintok)
229         prio = PCATCH | PPAUSE;
230     else
231         prio = PVFS;
232     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
233     AFS_GLOCK();
234     if (seq == evp->seq)
235         code = EINTR;
236     relevent(evp);
237     return code;
238 }
239 #endif /* not AFS_FBSD50_ENV */
240
241 int
242 afs_osi_Wakeup(void *event)
243 {
244     int ret = 1;
245     struct afs_event *evp;
246
247     evp = afs_getevent(event);
248     if (evp->refcount > 1) {
249         evp->seq++;
250         wakeup(event);
251         ret = 0;
252     }
253     relevent(evp);
254     return ret;
255 }