pull-prototypes-to-head-20020821
[openafs.git] / src / afs / DARWIN / 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("$Header$");
14
15 #include "../afs/sysincludes.h" /* Standard vendor system headers */
16 #include "../afs/afsincludes.h" /* Afs-based standard headers */
17 #include "../afs/afs_stats.h"   /* afs statistics */
18
19
20 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
21
22 static char waitV;
23
24
25 void afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
26 {
27     AFS_STATCNT(osi_InitWaitHandle);
28     achandle->proc = (caddr_t) 0;
29 }
30
31 /* cancel osi_Wait */
32 void afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
33 {
34     caddr_t proc;
35
36     AFS_STATCNT(osi_CancelWait);
37     proc = achandle->proc;
38     if (proc == 0) return;
39     achandle->proc = (caddr_t) 0;   /* so dude can figure out he was signalled */
40     afs_osi_Wakeup(&waitV);
41 }
42
43 /* afs_osi_Wait
44  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
45  * Returns 0 if timeout and EINTR if signalled.
46  */
47 int afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
48 {
49     int code;
50     afs_int32 endTime, tid;
51     struct proc *p=current_proc();
52
53     AFS_STATCNT(osi_Wait);
54     endTime = osi_Time() + (ams/1000);
55     if (ahandle)
56         ahandle->proc = (caddr_t)p;
57     do {
58         AFS_ASSERT_GLOCK();
59         code = 0;
60         code = osi_TimedSleep(&waitV, ams, aintok);
61
62         if (code) break;        /* if something happened, quit now */
63         /* if we we're cancelled, quit now */
64         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
65             /* we've been signalled */
66             break;
67         }
68     } while (osi_Time() < endTime);
69     return code;
70 }
71
72
73
74 typedef struct afs_event {
75     struct afs_event *next;     /* next in hash chain */
76     char *event;                /* lwp event: an address */
77     int refcount;               /* Is it in use? */
78     int seq;                    /* Sequence number: this is incremented
79                                    by wakeup calls; wait will not return until
80                                    it changes */
81 } afs_event_t;
82
83 #define HASHSIZE 128
84 afs_event_t *afs_evhasht[HASHSIZE];/* Hash table for events */
85 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
86 int afs_evhashcnt = 0;
87
88 /* Get and initialize event structure corresponding to lwp event (i.e. address)
89  * */
90 static afs_event_t *afs_getevent(char *event)
91 {
92     afs_event_t *evp, *newp = 0;
93     int hashcode;
94
95     AFS_ASSERT_GLOCK();
96     hashcode = afs_evhash(event);
97     evp = afs_evhasht[hashcode];
98     while (evp) {
99         if (evp->event == event) {
100             evp->refcount++;
101             return evp;
102         }
103         if (evp->refcount == 0)
104             newp = evp;
105         evp = evp->next;
106     }
107     if (!newp) {
108         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof (afs_event_t));
109         afs_evhashcnt++;
110         newp->next = afs_evhasht[hashcode];
111         afs_evhasht[hashcode] = newp;
112         newp->seq = 0;
113     }
114     newp->event = event;
115     newp->refcount = 1;
116     return newp;
117 }
118
119 /* Release the specified event */
120 #define relevent(evp) ((evp)->refcount--)
121
122
123 void afs_osi_Sleep(void *event)
124 {
125     struct afs_event *evp;
126     int seq;
127
128     evp = afs_getevent(event);
129     seq = evp->seq;
130     while (seq == evp->seq) {
131         AFS_ASSERT_GLOCK();
132         AFS_GUNLOCK();
133 #ifdef AFS_DARWIN14_ENV
134         /* this is probably safe for all versions, but testing is hard */
135         sleep(event, PVFS);
136 #else
137         assert_wait((event_t)event, 0);
138         thread_block(0);
139 #endif
140         AFS_GLOCK();
141     }
142     relevent(evp);
143 }
144
145 int afs_osi_SleepSig(void *event)
146 {
147     afs_osi_Sleep(event);
148     return 0;
149 }
150
151 /* osi_TimedSleep
152  * 
153  * Arguments:
154  * event - event to sleep on
155  * ams --- max sleep time in milliseconds
156  * aintok - 1 if should sleep interruptibly
157  *
158  * Returns 0 if timeout and EINTR if signalled.
159  */
160 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok)
161 {
162     int code = 0;
163     struct afs_event *evp;
164     int ticks,seq;
165     int prio;
166
167     ticks = ( ams * afs_hz )/1000;
168
169
170     evp = afs_getevent(event);
171     seq=evp->seq;
172     AFS_GUNLOCK();
173 #ifdef AFS_DARWIN14_ENV
174     /* this is probably safe for all versions, but testing is hard. */
175     /* using tsleep instead of assert_wait/thread_set_timer/thread_block
176        allows shutdown to work in 1.4 */
177     /* lack of PCATCH does *not* prevent signal delivery, neither does 
178        a low priority. We would need to deal with ERESTART here if we 
179        wanted to mess with p->p_sigmask, and messing with p_sigignore is
180        not the way to go.... (someone correct me if I'm wrong)
181     */
182     if (aintok)
183        prio=PCATCH|PPAUSE;
184     else
185        prio=PVFS;
186     code=tsleep(event, prio, "afs_osi_TimedSleep", ticks);
187 #else 
188     assert_wait((event_t)event, aintok ? THREAD_ABORTSAFE : THREAD_UNINT);
189     thread_set_timer(ticks, NSEC_PER_SEC / hz);
190     thread_block(0);
191     code=0;
192 #endif
193     AFS_GLOCK();
194     if (seq == evp->seq)
195         code = EINTR;
196     
197     relevent(evp);
198     return code;
199 }
200
201
202 void afs_osi_Wakeup(void *event)
203 {
204     struct afs_event *evp;
205     
206     evp = afs_getevent(event);
207     if (evp->refcount > 1) {
208         evp->seq++;    
209 #ifdef AFS_DARWIN14_ENV
210     /* this is probably safe for all versions, but testing is hard. */
211         wakeup(event);
212 #else
213         thread_wakeup((event_t)event);
214 #endif
215     }
216     relevent(evp);
217 }