OpenBSD: Complete implementation of afs_osi_TimedSleep
[openafs.git] / src / afs / OBSD / osi_sleep.c
1 /*
2  * $Id$
3  */
4
5 /*
6 copyright 2002
7 the regents of the university of michigan
8 all rights reserved
9
10 permission is granted to use, copy, create derivative works 
11 and redistribute this software and such derivative works 
12 for any purpose, so long as the name of the university of 
13 michigan is not used in any advertising or publicity 
14 pertaining to the use or distribution of this software 
15 without specific, written prior authorization.  if the 
16 above copyright notice or any other identification of the 
17 university of michigan is included in any copy of any 
18 portion of this software, then the disclaimer below must 
19 also be included.
20
21 this software is provided as is, without representation 
22 from the university of michigan as to its fitness for any 
23 purpose, and without warranty by the university of 
24 michigan of any kind, either express or implied, including 
25 without limitation the implied warranties of 
26 merchantability and fitness for a particular purpose. the 
27 regents of the university of michigan shall not be liable 
28 for any damages, including special, indirect, incidental, or 
29 consequential damages, with respect to any claim arising 
30 out of or in connection with the use of the software, even 
31 if it has been or is hereafter advised of the possibility of 
32 such damages.
33 */
34
35 /*
36  * Copyright 2000, International Business Machines Corporation and others.
37  * All Rights Reserved.
38  *
39  * This software has been released under the terms of the IBM Public
40  * License.  For details, see the LICENSE file in the top-level source
41  * directory or online at http://www.openafs.org/dl/license10.html
42  */
43
44 #include <afsconfig.h>
45 #include "afs/param.h"
46
47
48 #include "afs/sysincludes.h"    /* Standard vendor system headers */
49 #include "afs/afsincludes.h"    /* Afs-based standard headers */
50 #include "afs/afs_stats.h"      /* afs statistics */
51
52 static char waitV;
53
54
55 time_t
56 osi_Time()
57 {
58     struct timeval now;
59
60     getmicrotime(&now);
61     return now.tv_sec;
62 }
63
64 void
65 afs_osi_SetTime(osi_timeval_t * atv)
66 {
67     printf("afs attempted to set clock; use \"afsd -nosettime\"\n");
68 }
69
70 /* cancel osi_Wait */
71 void
72 afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
73 {
74     caddr_t proc;
75
76     AFS_STATCNT(osi_CancelWait);
77     proc = achandle->proc;
78     if (proc == NULL)
79         return;
80     achandle->proc = NULL;
81     wakeup(&waitV);
82 }
83
84 /* afs_osi_Wait
85  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
86  * Returns 0 if timeout and EINTR if signalled.
87  */
88 int
89 afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
90 {
91     int timo, code = 0;
92     struct timeval atv, now, endTime;
93
94     AFS_STATCNT(osi_Wait);
95
96     atv.tv_sec = ams / 1000;
97     atv.tv_usec = (ams % 1000) * 1000;
98     getmicrotime(&now);
99     timeradd(&atv, &now, &endTime);
100
101     if (ahandle)
102         ahandle->proc = (caddr_t) curproc;
103     AFS_ASSERT_GLOCK();
104     AFS_GUNLOCK();
105
106     do {
107         timersub(&endTime, &now, &atv);
108         timo = atv.tv_sec * hz + atv.tv_usec * hz / 1000000 + 1;
109         if (aintok) {
110             code = tsleep(&waitV, PCATCH | PVFS, "afs_W1", timo);
111             if (code)
112                 code = (code == EWOULDBLOCK) ? 0 : EINTR;
113         } else
114             tsleep(&waitV, PVFS, "afs_W2", timo);
115
116         /* if we were cancelled, quit now */
117         if (ahandle && (ahandle->proc == NULL)) {
118             /* we've been signalled */
119             break;
120         }
121         getmicrotime(&now);
122     } while (timercmp(&now, &endTime, <));
123
124     AFS_GLOCK();
125     return code;
126 }
127
128 /*
129  * All this gluck should probably also be replaced with CVs.
130  */
131 typedef struct afs_event {
132     struct afs_event *next;     /* next in hash chain */
133     char *event;                /* lwp event: an address */
134     int refcount;               /* Is it in use? */
135     int seq;                    /* Sequence number: this is incremented
136                                  * by wakeup calls; wait will not return until
137                                  * it changes */
138     int cond;
139 } afs_event_t;
140
141 #define HASHSIZE 128
142 afs_event_t *afs_evhasht[HASHSIZE];     /* Hash table for events */
143 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
144 int afs_evhashcnt = 0;
145
146 /* Get and initialize event structure corresponding to lwp event (i.e. address)
147  * */
148 static afs_event_t *
149 afs_getevent(char *event)
150 {
151     afs_event_t *evp, *newp = 0;
152     int hashcode;
153
154     AFS_ASSERT_GLOCK();
155     hashcode = afs_evhash(event);
156     evp = afs_evhasht[hashcode];
157     while (evp) {
158         if (evp->event == event) {
159             evp->refcount++;
160             return evp;
161         }
162         if (evp->refcount == 0)
163             newp = evp;
164         evp = evp->next;
165     }
166     if (!newp) {
167         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof(afs_event_t));
168         afs_evhashcnt++;
169         newp->next = afs_evhasht[hashcode];
170         afs_evhasht[hashcode] = newp;
171         newp->seq = 0;
172     }
173     newp->event = event;
174     newp->refcount = 1;
175     return newp;
176 }
177
178 /* Release the specified event */
179 #define relevent(evp) ((evp)->refcount--)
180
181 int
182 afs_osi_TimedSleep(void *event, afs_int32 ams, int aintok)
183 {
184     int code = 0;
185     struct afs_event *evp;
186     int seq, prio;
187     int ticks;
188
189     evp = afs_getevent(event);
190     seq = evp->seq;
191     AFS_GUNLOCK();
192     if (aintok)
193         prio = PCATCH | PPAUSE;
194     else
195         prio = PVFS;
196     ticks = (ams * afs_hz) / 1000;
197     code = tsleep(event, prio, "afs_osi_TimedSleep", ticks);
198     if (seq == evp->seq)
199         code = EINTR;
200     relevent(evp);
201     AFS_GLOCK();
202     return code;
203 }
204
205 void
206 afs_osi_Sleep(void *event)
207 {
208     AFS_ASSERT_GLOCK();
209     AFS_GUNLOCK();
210     tsleep(event, PVFS, "afsslp", 0);
211     AFS_GLOCK();
212 }
213
214 int
215 afs_osi_SleepSig(void *event)
216 {
217     afs_osi_Sleep(event);
218     return 0;
219 }
220
221 int
222 afs_osi_Wakeup(void *event)
223 {
224     wakeup(event);
225     return 1;
226 }