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