2486f55f8d62e09ccb17b3fd53acbac3d4a4172f
[openafs.git] / src / afs / DUX / 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 "../afs/param.h"       /* Should be always first */
11 #include "../afs/sysincludes.h" /* Standard vendor system headers */
12 #include "../afs/afsincludes.h" /* Afs-based standard headers */
13 #include "../afs/afs_stats.h"   /* afs statistics */
14
15
16
17 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok);
18 void afs_osi_Wakeup(char *event);
19 void afs_osi_Sleep(char *event);
20
21 static char waitV;
22
23
24 void afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
25 {
26     AFS_STATCNT(osi_InitWaitHandle);
27     achandle->proc = (caddr_t) 0;
28 }
29
30 /* cancel osi_Wait */
31 void afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
32 {
33     caddr_t proc;
34
35     AFS_STATCNT(osi_CancelWait);
36     proc = achandle->proc;
37     if (proc == 0) return;
38     achandle->proc = (caddr_t) 0;   /* so dude can figure out he was signalled */
39     afs_osi_Wakeup(&waitV);
40 }
41
42 /* afs_osi_Wait
43  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
44  * Returns 0 if timeout and EINTR if signalled.
45  */
46 int afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
47 {
48     int code;
49     afs_int32 endTime, tid;
50
51     AFS_STATCNT(osi_Wait);
52     endTime = osi_Time() + (ams/1000);
53     if (ahandle)
54         ahandle->proc = (caddr_t) u.u_procp;
55     do {
56         AFS_ASSERT_GLOCK();
57         code = 0;
58         code = osi_TimedSleep(&waitV, ams, aintok);
59
60         if (code) break;        /* if something happened, quit now */
61         /* if we we're cancelled, quit now */
62         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
63             /* we've been signalled */
64             break;
65         }
66     } while (osi_Time() < endTime);
67     return code;
68 }
69
70
71
72
73 typedef struct afs_event {
74     struct afs_event *next;     /* next in hash chain */
75     char *event;                /* lwp event: an address */
76     int refcount;               /* Is it in use? */
77     int seq;                    /* Sequence number: this is incremented
78                                    by wakeup calls; wait will not return until
79                                    it changes */
80     int cond;
81 } afs_event_t;
82
83 #define HASHSIZE 128
84 afs_event_t *afs_evhasht[HASHSIZE];/* Hash table for events */
85 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
86 int afs_evhashcnt = 0;
87
88 /* Get and initialize event structure corresponding to lwp event (i.e. address)
89  * */
90 static afs_event_t *afs_getevent(char *event)
91 {
92     afs_event_t *evp, *newp = 0;
93     int hashcode;
94
95     AFS_ASSERT_GLOCK();
96     hashcode = afs_evhash(event);
97     evp = afs_evhasht[hashcode];
98     while (evp) {
99         if (evp->event == event) {
100             evp->refcount++;
101             return evp;
102         }
103         if (evp->refcount == 0)
104             newp = evp;
105         evp = evp->next;
106     }
107     if (!newp) {
108         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof (afs_event_t));
109         afs_evhashcnt++;
110         newp->next = afs_evhasht[hashcode];
111         afs_evhasht[hashcode] = newp;
112         newp->seq = 0;
113     }
114     newp->event = event;
115     newp->refcount = 1;
116     return newp;
117 }
118
119 /* Release the specified event */
120 #define relevent(evp) ((evp)->refcount--)
121
122
123 void afs_osi_Sleep(char *event)
124 {
125     struct afs_event *evp;
126     int seq;
127
128     evp = afs_getevent(event);
129     seq = evp->seq;
130     while (seq == evp->seq) {
131         AFS_ASSERT_GLOCK();
132         assert_wait((vm_offset_t)(&evp->cond), 0);
133         AFS_GUNLOCK();
134         thread_block();
135         AFS_GLOCK();
136     }
137     relevent(evp);
138 }
139
140 /* osi_TimedSleep
141  * 
142  * Arguments:
143  * event - event to sleep on
144  * ams --- max sleep time in milliseconds
145  * aintok - 1 if should sleep interruptibly
146  *
147  * Returns 0 if timeout and EINTR if signalled.
148  */
149 static int osi_TimedSleep(char *event, afs_int32 ams, int aintok)
150 {
151     int code = 0;
152     struct afs_event *evp;
153     int ticks;
154
155     ticks = ( ams * afs_hz )/1000;
156
157
158     evp = afs_getevent(event);
159
160     assert_wait((vm_offset_t)(&evp->cond), aintok);
161     AFS_GUNLOCK();
162     thread_set_timeout(ticks);
163     thread_block();
164     AFS_GLOCK();
165     if (current_thread()->wait_result != THREAD_AWAKENED)
166         code = EINTR;
167     
168     relevent(evp);
169     return code;
170 }
171
172
173 void afs_osi_Wakeup(char *event)
174 {
175     struct afs_event *evp;
176
177     evp = afs_getevent(event);
178     if (evp->refcount > 1) {
179         evp->seq++;    
180         thread_wakeup((vm_offset_t)(&evp->cond));
181     }
182     relevent(evp);
183 }