Linux: Simplify header file checks
[openafs.git] / src / afs / LINUX / 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
14 #include "afs/sysincludes.h"    /* Standard vendor system headers */
15 #include "afsincludes.h"        /* Afs-based standard headers */
16 #include "afs/afs_stats.h"      /* afs statistics */
17 #if defined(HAVE_LINUX_FREEZER_H)
18 #include <linux/freezer.h>
19 #endif
20
21 static char waitV, dummyV;
22
23 void
24 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
25 {
26     AFS_STATCNT(osi_InitWaitHandle);
27     achandle->proc = (caddr_t) 0;
28 }
29
30 /* cancel osi_Wait */
31 void
32 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)
39         return;
40     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
41     afs_osi_Wakeup(&waitV);
42 }
43
44 /* afs_osi_Wait
45  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
46  * Returns 0 if timeout and EINTR if signalled.
47  */
48 int
49 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
50 {
51     afs_int32 endTime;
52     int code;
53
54     AFS_STATCNT(osi_Wait);
55     endTime = osi_Time() + (ams / 1000);
56     if (ahandle)
57         ahandle->proc = (caddr_t) current;
58
59     do {
60         AFS_ASSERT_GLOCK();
61         code = afs_osi_TimedSleep(&waitV, ams, 1);
62         if (code)
63             break;
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
75 typedef struct afs_event {
76     struct afs_event *next;     /* next in hash chain */
77     char *event;                /* lwp event: an address */
78     int refcount;               /* Is it in use? */
79     int seq;                    /* Sequence number: this is incremented
80                                  * by wakeup calls; wait will not return until
81                                  * it changes */
82     wait_queue_head_t cond;
83 } afs_event_t;
84
85 #define HASHSIZE 128
86 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
87 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
88 int afs_evhashcnt = 0;
89
90 /* Get and initialize event structure corresponding to lwp event (i.e. address)
91  * */
92 static afs_event_t *
93 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         return NULL;
112
113     newp->event = event;
114     newp->refcount = 1;
115     return newp;
116 }
117
118 /* afs_addevent -- allocates a new event for the address.  It isn't returned;
119  *     instead, afs_getevent should be called again.  Thus, the real effect of
120  *     this routine is to add another event to the hash bucket for this
121  *     address.
122  *
123  * Locks:
124  *     Called with GLOCK held. However the function might drop
125  *     GLOCK when it calls osi_AllocSmallSpace for allocating
126  *     a new event (In Linux, the allocator drops GLOCK to avoid
127  *     a deadlock).
128  */
129
130 static void
131 afs_addevent(char *event)
132 {
133     int hashcode;
134     afs_event_t *newp;
135
136     AFS_ASSERT_GLOCK();
137     hashcode = afs_evhash(event);
138     newp = osi_linux_alloc(sizeof(afs_event_t), 0);
139     afs_evhashcnt++;
140     newp->next = afs_evhasht[hashcode];
141     afs_evhasht[hashcode] = newp;
142     init_waitqueue_head(&newp->cond);
143     newp->seq = 0;
144     newp->event = &dummyV;      /* Dummy address for new events */
145     newp->refcount = 0;
146 }
147
148 #ifndef set_current_state
149 #define set_current_state(x)            current->state = (x);
150 #endif
151
152 /* Release the specified event */
153 #define relevent(evp) ((evp)->refcount--)
154
155 /* afs_osi_SleepSig
156  *
157  * Waits for an event to be notified, returning early if a signal
158  * is received.  Returns EINTR if signaled, and 0 otherwise.
159  */
160 int
161 afs_osi_SleepSig(void *event)
162 {
163     struct afs_event *evp;
164     int seq, retval;
165 #ifdef DECLARE_WAITQUEUE
166     DECLARE_WAITQUEUE(wait, current);
167 #else
168     struct wait_queue wait = { current, NULL };
169 #endif
170
171     evp = afs_getevent(event);
172     if (!evp) {
173         afs_addevent(event);
174         evp = afs_getevent(event);
175     }
176
177     seq = evp->seq;
178     retval = 0;
179
180     add_wait_queue(&evp->cond, &wait);
181     while (seq == evp->seq) {
182         set_current_state(TASK_INTERRUPTIBLE);
183         AFS_ASSERT_GLOCK();
184         AFS_GUNLOCK();
185         schedule();
186 #ifdef CONFIG_PM
187         if (
188 #ifdef PF_FREEZE
189             current->flags & PF_FREEZE
190 #else
191 #if defined(STRUCT_TASK_STRUCT_HAS_TODO)
192             !current->todo
193 #else
194 #if defined(STRUCT_TASK_STRUCT_HAS_THREAD_INFO)
195             test_ti_thread_flag(current->thread_info, TIF_FREEZE)
196 #else
197             test_ti_thread_flag(task_thread_info(current), TIF_FREEZE)
198 #endif
199 #endif
200 #endif
201             )
202 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
203             refrigerator(PF_FREEZE);
204 #else
205             refrigerator();
206 #endif
207 #endif
208         AFS_GLOCK();
209         if (signal_pending(current)) {
210             retval = EINTR;
211             break;
212         }
213     }
214     remove_wait_queue(&evp->cond, &wait);
215     set_current_state(TASK_RUNNING);
216
217     relevent(evp);
218     return retval;
219 }
220
221 /* afs_osi_Sleep -- waits for an event to be notified, ignoring signals.
222  * - NOTE: that on Linux, there are circumstances in which TASK_INTERRUPTIBLE
223  *   can wake up, even if all signals are blocked
224  * - TODO: handle signals correctly by passing an indication back to the
225  *   caller that the wait has been interrupted and the stack should be cleaned
226  *   up preparatory to signal delivery
227  */
228 void
229 afs_osi_Sleep(void *event)
230 {
231     sigset_t saved_set;
232
233     SIG_LOCK(current);
234     saved_set = current->blocked;
235     sigfillset(&current->blocked);
236     RECALC_SIGPENDING(current);
237     SIG_UNLOCK(current);
238
239     afs_osi_SleepSig(event);
240
241     SIG_LOCK(current);
242     current->blocked = saved_set;
243     RECALC_SIGPENDING(current);
244     SIG_UNLOCK(current);
245 }
246
247 /* afs_osi_TimedSleep
248  * 
249  * Arguments:
250  * event - event to sleep on
251  * ams --- max sleep time in milliseconds
252  * aintok - 1 if should sleep interruptibly
253  *
254  * Returns 0 if timeout, EINTR if signalled, and EGAIN if it might
255  * have raced.
256  */
257 int
258 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
259 {
260     int code = 0;
261     long ticks = (ams * HZ / 1000) + 1;
262     struct afs_event *evp;
263 #ifdef DECLARE_WAITQUEUE
264     DECLARE_WAITQUEUE(wait, current);
265 #else
266     struct wait_queue wait = { current, NULL };
267 #endif
268
269     evp = afs_getevent(event);
270     if (!evp) {
271         afs_addevent(event);
272         evp = afs_getevent(event);
273     }
274
275     add_wait_queue(&evp->cond, &wait);
276     set_current_state(TASK_INTERRUPTIBLE);
277     /* always sleep TASK_INTERRUPTIBLE to keep load average
278      * from artifically increasing. */
279     AFS_GUNLOCK();
280
281     if (aintok) {
282         if (schedule_timeout(ticks))
283             code = EINTR;
284     } else
285         schedule_timeout(ticks);
286 #ifdef CONFIG_PM
287     if (
288 #ifdef PF_FREEZE
289             current->flags & PF_FREEZE
290 #else
291 #if defined(STRUCT_TASK_STRUCT_HAS_TODO)
292             !current->todo
293 #else
294 #if defined(STRUCT_TASK_STRUCT_HAS_THREAD_INFO)
295             test_ti_thread_flag(current->thread_info, TIF_FREEZE)
296 #else
297             test_ti_thread_flag(task_thread_info(current), TIF_FREEZE)
298 #endif
299 #endif
300 #endif
301             )
302 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
303         refrigerator(PF_FREEZE);
304 #else
305         refrigerator();
306 #endif
307 #endif
308
309     AFS_GLOCK();
310     remove_wait_queue(&evp->cond, &wait);
311     set_current_state(TASK_RUNNING);
312
313     relevent(evp);
314
315     return code;
316 }
317
318
319 int
320 afs_osi_Wakeup(void *event)
321 {
322     int ret = 2;
323     struct afs_event *evp;
324
325     evp = afs_getevent(event);
326     if (!evp)                   /* No sleepers */
327         return 1;
328
329     if (evp->refcount > 1) {
330         evp->seq++;
331         wake_up(&evp->cond);
332         ret = 0;
333     }
334     relevent(evp);
335     return ret;
336 }