afs-suser-consistent-20040728
[openafs.git] / src / afs / DUX / 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 #include <afsconfig.h>
11 #include "afs/param.h"
12
13 RCSID
14     ("$Header$");
15
16 #include "afs/sysincludes.h"    /* Standard vendor system headers */
17 #include "afsincludes.h"        /* Afs-based standard headers */
18 #include "afs/afs_stats.h"      /* afs statistics */
19
20
21
22 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
23
24 static char waitV;
25
26
27 void
28 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
29 {
30     AFS_STATCNT(osi_InitWaitHandle);
31     achandle->proc = (caddr_t) 0;
32 }
33
34 /* cancel osi_Wait */
35 void
36 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
37 {
38     caddr_t proc;
39
40     AFS_STATCNT(osi_CancelWait);
41     proc = achandle->proc;
42     if (proc == 0)
43         return;
44     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
45     afs_osi_Wakeup(&waitV);
46 }
47
48 /* afs_osi_Wait
49  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
50  * Returns 0 if timeout and EINTR if signalled.
51  */
52 int
53 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
54 {
55     int code;
56     afs_int32 endTime, tid;
57
58     AFS_STATCNT(osi_Wait);
59     endTime = osi_Time() + (ams / 1000);
60     if (ahandle)
61         ahandle->proc = (caddr_t) u.u_procp;
62     do {
63         AFS_ASSERT_GLOCK();
64         code = 0;
65         code = osi_TimedSleep(&waitV, ams, aintok);
66
67         if (code)
68             break;              /* if something happened, quit now */
69         /* if we we're cancelled, quit now */
70         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
71             /* we've been signalled */
72             break;
73         }
74     } while (osi_Time() < endTime);
75     return code;
76 }
77
78
79
80
81 typedef struct afs_event {
82     struct afs_event *next;     /* next in hash chain */
83     char *event;                /* lwp event: an address */
84     int refcount;               /* Is it in use? */
85     int seq;                    /* Sequence number: this is incremented
86                                  * by wakeup calls; wait will not return until
87                                  * it changes */
88     int cond;
89 } afs_event_t;
90
91 #define HASHSIZE 128
92 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
93 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
94 int afs_evhashcnt = 0;
95
96 /* Get and initialize event structure corresponding to lwp event (i.e. address)
97  * */
98 static afs_event_t *
99 afs_getevent(char *event)
100 {
101     afs_event_t *evp, *newp = 0;
102     int hashcode;
103
104     AFS_ASSERT_GLOCK();
105     hashcode = afs_evhash(event);
106     evp = afs_evhasht[hashcode];
107     while (evp) {
108         if (evp->event == event) {
109             evp->refcount++;
110             return evp;
111         }
112         if (evp->refcount == 0)
113             newp = evp;
114         evp = evp->next;
115     }
116     if (!newp) {
117         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
118         afs_evhashcnt++;
119         newp->next = afs_evhasht[hashcode];
120         afs_evhasht[hashcode] = newp;
121         newp->seq = 0;
122     }
123     newp->event = event;
124     newp->refcount = 1;
125     return newp;
126 }
127
128 /* Release the specified event */
129 #define relevent(evp) ((evp)->refcount--)
130
131
132 void
133 afs_osi_Sleep(void *event)
134 {
135     struct afs_event *evp;
136     int seq;
137
138     evp = afs_getevent(event);
139     seq = evp->seq;
140     while (seq == evp->seq) {
141         AFS_ASSERT_GLOCK();
142         assert_wait((vm_offset_t) (&evp->cond), 0);
143         AFS_GUNLOCK();
144         thread_block();
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
173     ticks = (ams * afs_hz) / 1000;
174
175
176     evp = afs_getevent(event);
177
178     assert_wait((vm_offset_t) (&evp->cond), aintok);
179     AFS_GUNLOCK();
180     thread_set_timeout(ticks);
181     thread_block();
182     AFS_GLOCK();
183     if (current_thread()->wait_result != THREAD_AWAKENED)
184         code = EINTR;
185
186     relevent(evp);
187     return code;
188 }
189
190
191 int
192 afs_osi_Wakeup(void *event)
193 {
194     int ret = 1;
195     struct afs_event *evp;
196
197     evp = afs_getevent(event);
198     if (evp->refcount > 1) {
199         evp->seq++;
200         thread_wakeup((vm_offset_t) (&evp->cond));
201         ret = 0;
202     }
203     relevent(evp);
204     return ret;
205 }