25e862fef293ec81c358ec1dd88fb17dce1b7417
[openafs.git] / src / afs / HPUX / 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("$Header$");
14
15 #include "afs/sysincludes.h"    /* Standard vendor system headers */
16 #include "afsincludes.h"        /* Afs-based standard headers */
17 #include "afs/afs_stats.h"   /* afs statistics */
18
19 #if defined(AFS_HPUX1122_ENV)
20 void afs_osi_Wakeup(char *event);
21 void afs_osi_Sleep(char *event);
22 #endif
23
24 static char waitV;
25
26 /* call procedure aproc with arock as an argument, in ams milliseconds */
27 static int afs_osi_CallProc(aproc, arock, ams)
28     register void (*aproc)();
29     register char *arock;
30     afs_int32 ams;
31 {
32     int code;
33
34     AFS_STATCNT(osi_CallProc);
35     AFS_GUNLOCK();
36     /* hz is in cycles/second, and timeout's 3rd parm is in cycles */
37     code = timeout(aproc, arock, (ams * afs_hz)/1000 + 1);
38     AFS_GLOCK();
39     return code;
40 }
41
42 /* cancel a timeout, whether or not it has already occurred */
43 static int afs_osi_CancelProc(aproc, arock)
44     register void (*aproc)();
45     register char *arock; 
46 {
47     int code = 0;
48     AFS_STATCNT(osi_CancelProc);
49
50     AFS_GUNLOCK();
51     code = untimeout(aproc, arock);
52     AFS_GLOCK();
53     return code;
54 }
55
56 static void AfsWaitHack()
57 {
58     AFS_STATCNT(WaitHack);
59     wakeup(&waitV);
60 }
61
62 void afs_osi_InitWaitHandle(struct afs_osi_WaitHandle *achandle)
63 {
64     AFS_STATCNT(osi_InitWaitHandle);
65     achandle->proc = (caddr_t) 0;
66 }
67
68 /* cancel osi_Wait */
69 void afs_osi_CancelWait(struct afs_osi_WaitHandle *achandle)
70 {
71     caddr_t proc;
72
73     AFS_STATCNT(osi_CancelWait);
74     proc = achandle->proc;
75     if (proc == 0) return;
76     achandle->proc = (caddr_t) 0;   /* so dude can figure out he was signalled */
77     afs_osi_Wakeup(&waitV);
78 }
79
80 /* afs_osi_Wait
81  * Waits for data on ahandle, or ams ms later.  ahandle may be null.
82  * Returns 0 if timeout and EINTR if signalled.
83  */
84 int afs_osi_Wait(afs_int32 ams, struct afs_osi_WaitHandle *ahandle, int aintok)
85 {
86     int code;
87     afs_int32 endTime, tid;
88
89     AFS_STATCNT(osi_Wait);
90     endTime = osi_Time() + (ams/1000);
91     if (ahandle)
92         ahandle->proc = (caddr_t) u.u_procp;
93     do {
94         AFS_ASSERT_GLOCK();
95         code = 0;
96         /* do not do anything for solaris, digital, AIX, and SGI MP */
97         afs_osi_CallProc(AfsWaitHack, (char *) u.u_procp, ams);
98         afs_osi_Sleep(&waitV); /* for HP 10.0 */
99
100         /* do not do anything for solaris, digital, and SGI MP */
101         afs_osi_CancelProc(AfsWaitHack,  (char *) u.u_procp); 
102         if (code) break;        /* if something happened, quit now */
103         /* if we we're cancelled, quit now */
104         if (ahandle && (ahandle->proc == (caddr_t) 0)) {
105             /* we've been signalled */
106             break;
107         }
108     } while (osi_Time() < endTime);
109     return code;
110 }
111
112 int afs_osi_SleepSig(void *event)
113 {
114     afs_osi_Sleep(event);
115     return 0;
116 }
117
118 int afs_osi_Wakeup(void *event)
119 {
120     wakeup((caddr_t) event);
121     return 0;
122 }
123
124 #if defined(AFS_HPUX1122_ENV)
125
126 /* on HP 11.22 we are using beta semiphore for AFS_GLOCK */
127
128 typedef struct afs_event {
129     struct afs_event *next;     /* next in hash chain */
130     char *event;                /* lwp event: an address */
131     int refcount;               /* Is it in use? */
132     int seq;                    /* Sequence number: this is incremented
133                                    by wakeup calls; wait will not return until
134                                    it changes */
135 } afs_event_t;
136
137 #define HASHSIZE 128
138 afs_event_t *afs_evhasht[HASHSIZE];/* Hash table for events */
139 #define afs_evhash(event)       (afs_uint32) ((((long)event)>>2) & (HASHSIZE-1));
140 int afs_evhashcnt = 0;
141
142 /* Get and initialize event structure corresponding to lwp event (i.e. address)
143  * */
144 static afs_event_t *afs_getevent(char *event)
145 {
146     afs_event_t *evp, *newp = 0;
147     int hashcode;
148
149     AFS_ASSERT_GLOCK();
150     hashcode = afs_evhash(event);
151     evp = afs_evhasht[hashcode];
152     while (evp) {
153         if (evp->event == event) {
154             evp->refcount++;
155             return evp;
156         }
157         if (evp->refcount == 0)
158             newp = evp;
159         evp = evp->next;
160     }
161     if (!newp) {
162         newp = (afs_event_t *) osi_AllocSmallSpace(sizeof (afs_event_t));
163         afs_evhashcnt++;
164         newp->next = afs_evhasht[hashcode];
165         afs_evhasht[hashcode] = newp;
166         newp->seq = 0;
167     }
168     newp->event = event;
169     newp->refcount = 1;
170     return newp;
171 }
172
173
174 /* Release the specified event */
175 #define relevent(evp) ((evp)->refcount--)
176
177 void afs_osi_Sleep(char *event)
178 {
179     struct afs_event *evp;
180     int seq;
181
182     evp = afs_getevent(event);
183     seq = evp->seq;
184     while (seq == evp->seq) {
185         AFS_ASSERT_GLOCK();
186         get_sleep_lock(event);
187         AFS_GUNLOCK();
188         sleep(event, PZERO-2);
189         AFS_GLOCK();
190     }
191     relevent(evp);
192 }
193
194 void afs_osi_Wakeup(char *event)
195 {
196     struct afs_event *evp;
197     lock_t * sleep_lock;
198
199     evp = afs_getevent(event);
200     sleep_lock = get_sleep_lock(event);
201     if (evp->refcount > 1) {
202         evp->seq++;
203         wakeup(event);
204     }
205     spinunlock(sleep_lock);
206 }
207 #endif