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