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