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