97d270727fa62a2463f68c877348dc346a2daf0e
[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
22
23 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
24
25 static char waitV;
26
27
28 void
29 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
30 {
31     AFS_STATCNT(osi_InitWaitHandle);
32     achandle->proc = (caddr_t) 0;
33 }
34
35 /* cancel osi_Wait */
36 void
37 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
38 {
39     caddr_t proc;
40
41     AFS_STATCNT(osi_CancelWait);
42     proc = achandle->proc;
43     if (proc == 0)
44         return;
45     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
46     afs_osi_Wakeup(&waitV);
47 }
48
49 /* afs_osi_Wait
50  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
51  * Returns 0 if timeout and EINTR if signalled.
52  */
53 int
54 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
55 {
56     int code;
57     afs_int32 endTime;
58
59     AFS_STATCNT(osi_Wait);
60     endTime = osi_Time() + (ams / 1000);
61     if (ahandle)
62         ahandle->proc = (caddr_t) curproc;
63     do {
64         AFS_ASSERT_GLOCK();
65         code = 0;
66         code = osi_TimedSleep(&waitV, ams, aintok);
67
68         if (code)
69             break;              /* if something happened, quit now */
70         /* if we we're cancelled, quit now */
71         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
72             /* we've been signalled */
73             break;
74         }
75     } while (osi_Time() < endTime);
76     return code;
77 }
78
79
80
81
82 typedef struct afs_event {
83     struct afs_event *next;     /* next in hash chain */
84     char *event;                /* lwp event: an address */
85     int refcount;               /* Is it in use? */
86     int seq;                    /* Sequence number: this is incremented
87                                  * by wakeup calls; wait will not return until
88                                  * it changes */
89     int cond;
90 } afs_event_t;
91
92 #define HASHSIZE 128
93 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
94 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
95 int afs_evhashcnt = 0;
96
97 /* Get and initialize event structure corresponding to lwp event (i.e. address)
98  * */
99 static afs_event_t *
100 afs_getevent(char *event)
101 {
102     afs_event_t *evp, *newp = 0;
103     int hashcode;
104
105     AFS_ASSERT_GLOCK();
106     hashcode = afs_evhash(event);
107     evp = afs_evhasht[hashcode];
108     while (evp) {
109         if (evp->event == event) {
110             evp->refcount++;
111             return evp;
112         }
113         if (evp->refcount == 0)
114             newp = evp;
115         evp = evp->next;
116     }
117     if (!newp) {
118         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
119         afs_evhashcnt++;
120         newp->next = afs_evhasht[hashcode];
121         afs_evhasht[hashcode] = newp;
122         newp->seq = 0;
123     }
124     newp->event = event;
125     newp->refcount = 1;
126     return newp;
127 }
128
129 /* Release the specified event */
130 #define relevent(evp) ((evp)->refcount--)
131
132
133 void
134 afs_osi_Sleep(void *event)
135 {
136     struct afs_event *evp;
137     int seq;
138
139     evp = afs_getevent(event);
140     seq = evp->seq;
141     while (seq == evp->seq) {
142         AFS_ASSERT_GLOCK();
143         AFS_GUNLOCK();
144         tsleep(event, PVFS, "afs_osi_Sleep", 0);
145         AFS_GLOCK();
146     }
147     relevent(evp);
148 }
149
150 int
151 afs_osi_SleepSig(void *event)
152 {
153     afs_osi_Sleep(event);
154     return 0;
155 }
156
157 /* osi_TimedSleep
158  * 
159  * Arguments:
160  * event - event to sleep on
161  * ams --- max sleep time in milliseconds
162  * aintok - 1 if should sleep interruptibly
163  *
164  * Returns 0 if timeout and EINTR if signalled.
165  */
166 static int
167 osi_TimedSleep(char *event, afs_int32 ams, int aintok)
168 {
169     int code = 0;
170     struct afs_event *evp;
171     int ticks;
172     int seq, prio;
173
174     ticks = (ams * afs_hz) / 1000;
175
176
177     evp = afs_getevent(event);
178     seq = evp->seq;
179     AFS_GUNLOCK();
180     if (aintok)
181         prio = PCATCH | PPAUSE;
182     else
183         prio = PVFS;
184     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
185     AFS_GLOCK();
186     if (seq == evp->seq)
187         code = EINTR;
188     relevent(evp);
189     return code;
190 }
191
192
193 int
194 afs_osi_Wakeup(void *event)
195 {
196     int ret = 1;
197     struct afs_event *evp;
198
199     evp = afs_getevent(event);
200     if (evp->refcount > 1) {
201         evp->seq++;
202         wakeup(event);
203         ret = 0;
204     }
205     relevent(evp);
206     return ret;
207 }