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