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