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