darwin-updates-20040613
[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
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 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
22
23 static char waitV;
24
25
26 void
27 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
35 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
36 {
37     caddr_t proc;
38
39     AFS_STATCNT(osi_CancelWait);
40     proc = achandle->proc;
41     if (proc == 0)
42         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
52 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
53 {
54     int code;
55     afs_int32 endTime, tid;
56     struct proc *p = current_proc();
57
58     AFS_STATCNT(osi_Wait);
59     endTime = osi_Time() + (ams / 1000);
60     if (ahandle)
61         ahandle->proc = (caddr_t) p;
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 typedef struct afs_event {
81     struct afs_event *next;     /* next in hash chain */
82     char *event;                /* lwp event: an address */
83     int refcount;               /* Is it in use? */
84     int seq;                    /* Sequence number: this is incremented
85                                  * by wakeup calls; wait will not return until
86                                  * it changes */
87 } afs_event_t;
88
89 #define HASHSIZE 128
90 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
91 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
92 int afs_evhashcnt = 0;
93
94 /* Get and initialize event structure corresponding to lwp event (i.e. address)
95  * */
96 static afs_event_t *
97 afs_getevent(char *event)
98 {
99     afs_event_t *evp, *newp = 0;
100     int hashcode;
101
102     AFS_ASSERT_GLOCK();
103     hashcode = afs_evhash(event);
104     evp = afs_evhasht[hashcode];
105     while (evp) {
106         if (evp->event == event) {
107             evp->refcount++;
108             return evp;
109         }
110         if (evp->refcount == 0)
111             newp = evp;
112         evp = evp->next;
113     }
114     if (!newp) {
115         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
116         afs_evhashcnt++;
117         newp->next = afs_evhasht[hashcode];
118         afs_evhasht[hashcode] = newp;
119         newp->seq = 0;
120     }
121     newp->event = event;
122     newp->refcount = 1;
123     return newp;
124 }
125
126 /* Release the specified event */
127 #define relevent(evp) ((evp)->refcount--)
128
129
130 void
131 afs_osi_Sleep(void *event)
132 {
133     struct afs_event *evp;
134     int seq;
135
136     evp = afs_getevent(event);
137     seq = evp->seq;
138     while (seq == evp->seq) {
139         AFS_ASSERT_GLOCK();
140         AFS_GUNLOCK();
141 #ifdef AFS_DARWIN14_ENV
142         /* this is probably safe for all versions, but testing is hard */
143         sleep(event, PVFS);
144 #else
145         assert_wait((event_t) event, 0);
146         thread_block(0);
147 #endif
148         AFS_GLOCK();
149     }
150     relevent(evp);
151 }
152
153 int
154 afs_osi_SleepSig(void *event)
155 {
156     afs_osi_Sleep(event);
157     return 0;
158 }
159
160 /* osi_TimedSleep
161  * 
162  * Arguments:
163  * event - event to sleep on
164  * ams --- max sleep time in milliseconds
165  * aintok - 1 if should sleep interruptibly
166  *
167  * Returns 0 if timeout and EINTR if signalled.
168  */
169 static int
170 osi_TimedSleep(char *event, afs_int32 ams, int aintok)
171 {
172     int code = 0;
173     struct afs_event *evp;
174     int ticks, seq;
175     int prio;
176
177     ticks = (ams * afs_hz) / 1000;
178
179
180     evp = afs_getevent(event);
181     seq = evp->seq;
182     AFS_GUNLOCK();
183 #ifdef AFS_DARWIN14_ENV
184     /* this is probably safe for all versions, but testing is hard. */
185     /* using tsleep instead of assert_wait/thread_set_timer/thread_block
186      * allows shutdown to work in 1.4 */
187     /* lack of PCATCH does *not* prevent signal delivery, neither does 
188      * a low priority. We would need to deal with ERESTART here if we 
189      * wanted to mess with p->p_sigmask, and messing with p_sigignore is
190      * not the way to go.... (someone correct me if I'm wrong)
191      */
192     if (aintok)
193         prio = PCATCH | PPAUSE;
194     else
195         prio = PVFS;
196     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
197 #else
198     assert_wait((event_t) event, aintok ? THREAD_ABORTSAFE : THREAD_UNINT);
199     thread_set_timer(ticks, NSEC_PER_SEC / hz);
200     thread_block(0);
201     code = 0;
202 #endif
203     AFS_GLOCK();
204     if (seq == evp->seq)
205         code = EINTR;
206
207     relevent(evp);
208     return code;
209 }
210
211
212 int
213 afs_osi_Wakeup(void *event)
214 {
215     struct afs_event *evp;
216     int ret = 1;
217
218     evp = afs_getevent(event);
219     if (evp->refcount > 1) {
220         evp->seq++;
221 #ifdef AFS_DARWIN14_ENV
222         /* this is probably safe for all versions, but testing is hard. */
223         wakeup(event);
224 #else
225         thread_wakeup((event_t) event);
226 #endif
227         ret = 0;
228     }
229     relevent(evp);
230     return ret;
231 }