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