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