339a6bedd944dcc4a3f7fad4e1c7a28f4e692a54
[openafs.git] / src / WINNT / client_osi / osithrd95.c
1 /* 
2  * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
3  *
4  * (C) COPYRIGHT IBM CORPORATION 1987, 1988
5  * LICENSED MATERIALS - PROPERTY OF IBM
6  *
7  */
8
9 /* Copyright (C) 1994 Cazamar Systems, Inc. */
10
11 #include "osi.h"
12 #include "lwp.h"
13 /*#include "lock95.h"*/
14 #include <assert.h>
15
16 #include <stdio.h>
17
18 /*
19 thread95.c
20
21 This code implements a partial OSI-over-LWP(and IOMGR) layer for threading
22 and synchronization, for the AFS NT code port to Windows 9x.
23 */
24
25 // It so happens that all code seen so far throws away *thread_id;
26 // unfortunately, callers do not send thread_id==NULL instead of getting
27 // a value and tossing it. :(
28 thread_t thrd_Create(int attributes, int stacksize, ThreadFunc func,
29                      void *parm, int flags, int *thread_id, char *name)
30 {
31   PROCESS lwp_pid;
32
33   // Reserve priority 0 for IOMGR; we use pri 1 by default
34   if (name)
35     LWP_CreateProcess(func, stacksize, 1, parm, name, &lwp_pid);
36   else
37     LWP_CreateProcess(func, stacksize, 1, parm, "thread", &lwp_pid);
38
39   // In principle, the "right" way to do thread_id is to create a mapping
40   // between thread_id integers and LWP PROCESS names, but we're not using
41   // the IDs for anything anyway, so...
42   // actually, it turns out PROCESS is a pointer, so we fudge with that for now
43   // just to return a nonzero value
44   *thread_id = (int) lwp_pid;
45
46   return lwp_pid;
47 }
48
49 thread_t thrd_Current()
50 {
51   PROCESS pid;
52   LWP_CurrentProcess(&pid);
53   return pid;
54 }
55
56 int thrd_Close(thread_t thrd)
57 {
58   int rc = LWP_DestroyProcess(thrd);
59   if (rc == LWP_SUCCESS)
60     return 0;
61   else
62     return -1;
63 }
64
65 /* The following thread-local-storage and critical-section functions are 
66    not used. */
67 /*
68 DWORD thrd_Alloc(void)
69 {
70   char **NewRock = NULL;
71   static int NextTag = 0;  // Because LWP is not preemptive, we need no mutex
72
73   NewRock = (char **) malloc (sizeof(LPVOID *));
74   if (NewRock == NULL)
75     return 0xFFFFFFFF;
76   *NewRock = (LPVOID *) malloc(sizeof(LPVOID));
77   if (*NewRock == NULL) {
78     free(NewRock);
79     return 0xFFFFFFFF;
80   }
81
82   if (LWP_NewRock(++NextTag,NewRock))
83     return 0xFFFFFFFF;
84   else
85     return NextTag;
86 }
87
88 LPVOID thrd_GetValue(DWORD Index)
89 {
90   char *ptr;
91   if (LWP_GetRock((int) Index, &ptr)) {
92     // SetLastError
93     return 0;
94   } else {
95     return * ((LPVOID *) ptr);
96   }
97 }
98
99 BOOL thrd_SetValue(DWORD Index, LPVOID Value) {
100   char *ptr;
101   if (LWP_GetRock((int) Index, &ptr)) {
102     // SetLastError
103     return 0;
104   } else {
105     * ((LPVOID *) ptr) = Value;
106     return TRUE;
107   }
108 }
109
110 #define LPCRITICAL_SECTION (struct Lock*)
111
112 #define thrd_InitCrit (Lock_Init)
113 #define thrd_EnterCrit (ObtainWriteLock)
114 #define thrd_LeaveCrit (ReleaseWriteLock)
115
116 // LWP has no formal destructor for locks.
117 #define thrd_DeleteCrit(x)   ;
118
119 */
120
121
122 /* Since LWP is nonpreemptive, arithmetic needs no special handling. */
123
124 LONG thrd_Increment(LPLONG number)
125 {
126   ++*number;
127   return *number;
128 }
129
130 LONG thrd_Decrement(LPLONG number)
131 {
132   --*number;
133   return *number;
134 }
135
136 LONG thrd_Exchange(LPLONG number, LONG value)
137 {
138   LONG oldval = *number;
139   *number = value;
140   return oldval;
141 }
142
143 // CreateEvent is always called with (NULL,(T/F),(T/F),NULL)
144 // This code will assume it and fail otherwise.
145 // SetLastError() is not implemented, i.e., if thrd_CreateEvent fails,
146 // there is no corresponding GetLastError() to pull out error codes
147 // at this time.
148 EVENT *thrd_CreateEvent(void *f, BOOL manual, BOOL startsignaled, void *g)
149 {
150   // LWP code checks eventnames against NULL as an error condition,
151   // so we start counting from 1 instead of zero.
152   // It turns out that LWP uses event names as unique integer values,
153   // even though these values are cast as char pointers.  We will use
154   // integers, since they are never dereferenced by LWP.
155   static unsigned long NextEventName = 1L;
156   EVENT *event;
157
158   // Startup stuff
159   if ((f != NULL) || (g != NULL)) {
160     // Panic!  This scenario is not implemented.
161     assert(0);
162     return NULL;
163   }
164
165   // Create an event
166   if ((event=(EVENT*)malloc(sizeof(EVENT))) == NULL)
167   {
168     // SetLastError out of memory
169     return NULL;
170   }
171   if (manual)
172     event->state = startsignaled ? manualsignal : manualunsig;
173   else
174     event->state = startsignaled ? autosignal : autounsig;
175   event->name = (char *) NextEventName;
176
177   // Increment NextEventName
178   ++NextEventName;
179
180   return event;
181 }
182
183 BOOL thrd_SetEvent(EVENT *event)
184 {
185   if (event==NULL)
186     return FALSE;
187   if (AUTOMATIC(event))
188     event->state = autosignal;
189   else
190     event->state = manualsignal;
191   LWP_SignalProcess(event->name);
192   return TRUE;
193 }
194
195 BOOL thrd_ResetEvent(EVENT *event)
196 {
197   if (event==NULL)
198     return FALSE;
199   if (AUTOMATIC(event))
200     event->state = autounsig;
201   else
202     event->state = manualunsig;
203   return TRUE;
204 }
205
206 // It appears there is a slight difference in the two wait schemes.
207 // Win32's WaitForSingleObject returns only when the wait is finished;
208 // LWP's WaitProcess may return randomly, and so requires while() wrapping
209 // (a little busywaiting).
210 DWORD thrd_WaitForSingleObject_Event(EVENT *event, DWORD timeoutms)
211 {
212   if (timeoutms != INFINITE) {
213     // Panic!
214     assert(0);
215     return WAIT_FAILED;
216   }
217   if (event == NULL) {
218     return WAIT_FAILED;
219   }
220   while (!SIGNALED(event))
221     LWP_WaitProcess(event->name);
222   if (AUTOMATIC(event))
223     event->state = autounsig;
224   return WAIT_OBJECT_0;
225 }
226
227 DWORD thrd_WaitForMultipleObjects_Event(DWORD count, EVENT* events[],
228                                         BOOL waitforall, DWORD timeoutms)
229 {
230   if ((timeoutms != INFINITE) || waitforall) {
231     // Panic!  This functionality not implemented.
232     assert(0);
233     return WAIT_FAILED;
234   }
235   if (events == NULL) {
236     return WAIT_FAILED;
237   }
238
239   // Do the actual wait
240   {
241     // Construct the list of LWP events to wait on
242     char *names[count+1];
243     int i;
244     for (i=0;i<count;++i) {
245       if (SIGNALED(events[i])) {
246         // We're done; one of the events is signaled.
247         if (AUTOMATIC(events[i]))
248           events[i]->state = autounsig;
249         return (WAIT_OBJECT_0 + i);
250       }
251       names[i] = events[i]->name;
252     }
253     names[count] = NULL;
254     
255     // Do the wait for something to signal
256     while (1) {
257       LWP_MwaitProcess(1,names);
258       // Find who got signalled: MwaitProcess doesn't tell us.
259       for (i=0; i<count; ++i) {
260         if (SIGNALED(events[i])) {
261           if (AUTOMATIC(events[i]))
262             events[i]->state = autounsig;
263           return WAIT_OBJECT_0 + i;
264         }
265       }
266     }
267     // not reached
268     assert(0);
269   }
270   // not reached
271   assert(0);
272 }
273
274 int osi_Once(osi_once_t *argp)
275 {
276      long i;
277
278      lock_ObtainMutex(&argp->atomic);
279
280      if (argp->done == 0) {
281           argp->done = 1;
282           return 1;
283      }
284
285      /* otherwise we've already been initialized, so clear lock and return */
286      lock_ReleaseMutex(&argp->atomic);
287      return 0;
288 }
289
290 void osi_EndOnce(osi_once_t *argp)
291 {
292      lock_ReleaseMutex(&argp->atomic);
293 }
294
295 int osi_TestOnce(osi_once_t *argp)
296 {
297      long localDone;
298      long i;
299
300      lock_ObtainMutex(&argp->atomic);
301
302      localDone = argp->done;
303
304      /* drop interlock */
305      lock_ReleaseMutex(&argp->atomic);
306
307      return (localDone? 0 : 1);
308 }
309
310 void osi_panic(char *s, char *f, long l)
311 {
312   fprintf(stderr, "Fatal error: %s at %s:%d\n", s, f, l);
313   exit(1);
314 }
315
316 /* return true iff x is prime */
317 int osi_IsPrime(unsigned long x)
318 {
319         unsigned long c;
320         
321         /* even numbers aren't prime */
322         if ((x & 1) == 0 && x != 2) return 0;
323
324         for(c = 3; c<x; c += 2) {
325                 /* see if x is divisible by c */
326                 if ((x % c) == 0) return 0;     /* yup, it ain't prime */
327                 
328                 /* see if we've gone far enough; only have to compute until
329                  * square root of x.
330                  */
331                 if (c*c > x) return 1;
332         }
333
334         /* probably never get here */
335         return 1;
336 }
337
338 /* return first prime number less than or equal to x */
339 unsigned long osi_PrimeLessThan(unsigned long x) {
340         unsigned long c;
341         
342         for(c = x; c > 1; c--) {
343                 if (osi_IsPrime(c)) return c;
344         }
345
346         /* ever reached? */
347         return 1;
348 }