reindent-20030715
[openafs.git] / src / afs / AIX / 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
22 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
23
24 static char waitV;
25
26 static void
27 AfsWaitHack(struct trb *trb)
28 {
29     AFS_STATCNT(WaitHack);
30
31     e_clear_wait(trb->func_data, THREAD_TIMED_OUT);
32 }
33
34 void
35 afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
36 {
37     AFS_STATCNT(osi_InitWaitHandle);
38     achandle->proc = (caddr_t) 0;
39 }
40
41 /* cancel osi_Wait */
42 void
43 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
44 {
45     caddr_t proc;
46
47     AFS_STATCNT(osi_CancelWait);
48     proc = achandle->proc;
49     if (proc == 0)
50         return;
51     achandle->proc = (caddr_t) 0;       /* so dude can figure out he was signalled */
52     afs_osi_Wakeup(&waitV);
53 }
54
55 /* afs_osi_Wait
56  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
57  * Returns 0 if timeout and EINTR if signalled.
58  */
59 int
60 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
61 {
62     int code;
63     afs_int32 endTime, tid;
64
65     AFS_STATCNT(osi_Wait);
66     endTime = osi_Time() + (ams / 1000);
67     if (ahandle)
68         ahandle->proc = (caddr_t) thread_self();
69     do {
70         AFS_ASSERT_GLOCK();
71         code = 0;
72         code = osi_TimedSleep(&waitV, ams, aintok);
73
74         if (code)
75             break;              /* if something happened, quit now */
76         /* if we we're cancelled, quit now */
77         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
78             /* we've been signalled */
79             break;
80         }
81     } while (osi_Time() < endTime);
82     return code;
83 }
84
85
86
87
88 typedef struct afs_event {
89     struct afs_event *next;     /* next in hash chain */
90     char *event;                /* lwp event: an address */
91     int refcount;               /* Is it in use? */
92     int seq;                    /* Sequence number: this is incremented
93                                  * by wakeup calls; wait will not return until
94                                  * it changes */
95     tid_t cond;
96 } afs_event_t;
97
98 #define HASHSIZE 128
99 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
100 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
101 int afs_evhashcnt = 0;
102
103 /* Get and initialize event structure corresponding to lwp event (i.e. address)
104  * */
105 static afs_event_t *
106 afs_getevent(char *event)
107 {
108     afs_event_t *evp, *newp = 0;
109     int hashcode;
110
111     AFS_ASSERT_GLOCK();
112     hashcode = afs_evhash(event);
113     evp = afs_evhasht[hashcode];
114     while (evp) {
115         if (evp->event == event) {
116             evp->refcount++;
117             return evp;
118         }
119         if (evp->refcount == 0)
120             newp = evp;
121         evp = evp->next;
122     }
123     if (!newp) {
124         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
125         afs_evhashcnt++;
126         newp->next = afs_evhasht[hashcode];
127         afs_evhasht[hashcode] = newp;
128         newp->cond = EVENT_NULL;
129         newp->seq = 0;
130     }
131     newp->event = event;
132     newp->refcount = 1;
133     return newp;
134 }
135
136 /* Release the specified event */
137 #define relevent(evp) ((evp)->refcount--)
138
139
140 void
141 afs_osi_Sleep(void *event)
142 {
143     struct afs_event *evp;
144     int seq;
145
146     evp = afs_getevent(event);
147     seq = evp->seq;
148     while (seq == evp->seq) {
149         AFS_ASSERT_GLOCK();
150         e_assert_wait(&evp->cond, 0);
151         AFS_GUNLOCK();
152         e_block_thread();
153         AFS_GLOCK();
154     }
155     relevent(evp);
156 }
157
158 int
159 afs_osi_SleepSig(void *event)
160 {
161     afs_osi_Sleep(event);
162     return 0;
163 }
164
165 /* osi_TimedSleep
166  * 
167  * Arguments:
168  * event - event to sleep on
169  * ams --- max sleep time in milliseconds
170  * aintok - 1 if should sleep interruptibly
171  *
172  * Returns 0 if timeout and EINTR if signalled.
173  */
174 static int
175 osi_TimedSleep(char *event, afs_int32 ams, int aintok)
176 {
177     int code = 0;
178     struct afs_event *evp;
179     struct timestruc_t ticks;
180     struct trb *trb;
181     int rc;
182
183     ticks.tv_sec = ams / 1000;
184     ticks.tv_nsec = (ams - (ticks.tv_sec * 1000)) * 1000000;
185
186
187     evp = afs_getevent(event);
188
189     trb = talloc();
190     if (trb == NULL)
191         osi_Panic("talloc returned NULL");
192     trb->flags = 0;
193     trb->func = AfsWaitHack;
194     trb->eventlist = EVENT_NULL;
195     trb->ipri = INTTIMER;
196     trb->func_data = thread_self();
197     trb->timeout.it_value = ticks;
198
199     e_assert_wait(&evp->cond, aintok);
200     AFS_GUNLOCK();
201     tstart(trb);
202     rc = e_block_thread();
203     while (tstop(trb));
204     if (rc == THREAD_INTERRUPTED)
205         code = EINTR;
206     tfree(trb);
207     AFS_GLOCK();
208
209     relevent(evp);
210     return code;
211 }
212
213
214 int
215 afs_osi_Wakeup(void *event)
216 {
217     int ret = 1;
218     struct afs_event *evp;
219
220     evp = afs_getevent(event);
221     if (evp->refcount > 1) {
222         evp->seq++;
223         e_wakeup(&evp->cond);
224         ret = 0;
225     }
226     relevent(evp);
227     return ret;
228 }