b82dc6d20b3ea8873543a45e2df1c3c136154326
[openafs.git] / src / WINNT / client_osi / osisleep.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 <afs/param.h>
13 #include <afs/stds.h>
14
15 #include <windows.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <assert.h>
19 #include "osi.h"
20
21 /* Locking hierarchy for these critical sections:
22  *
23  * 1. lock osi_sleepFDCS
24  * 2. lock osi_critSec[i]
25  * 3. lock osi_sleepInfoAllocCS
26  */
27
28 /* file descriptor for iterating over sleeping threads */
29 osi_fdOps_t osi_sleepFDOps = {
30         osi_SleepFDCreate,
31         osi_SleepFDGetInfo,
32         osi_SleepFDClose
33 };
34
35 /*
36  * Thread-local storage for sleep Info structures
37  */
38 DWORD osi_SleepSlot;
39
40 /* critical section serializing contents of all sleep FDs, so that
41  * concurrent GetInfo calls don't damage each other if applied
42  * to the same FD.
43  */
44 CRITICAL_SECTION osi_sleepFDCS;
45
46 /* critical regions used for SleepSched to guarantee atomicity.
47  * protects all sleep info structures while they're in the
48  * sleep hash table.
49  */
50 static CRITICAL_SECTION osi_critSec[OSI_SLEEPHASHSIZE];
51
52 /* the sleep info structure hash table.
53  * all active entries are in here.  In addition, deleted entries
54  * may be present, referenced by file descriptors from remote
55  * debuggers; these will have OSI_SLEEPINFO_DELETED set and
56  * should be ignored.
57  */
58 static osi_sleepInfo_t *osi_sleepers[OSI_SLEEPHASHSIZE];
59 static osi_sleepInfo_t *osi_sleepersEnd[OSI_SLEEPHASHSIZE];
60
61 /* allocate space for lock operations */
62 osi_lockOps_t *osi_lockOps[OSI_NLOCKTYPES];
63
64 /* some global statistics */
65 long osi_totalSleeps = 0;
66
67 /* critical section protecting sleepInfoFreeListp and all sleep entries in
68  * the free list.
69  */
70 CRITICAL_SECTION osi_sleepInfoAllocCS;
71
72 /* sleep entry free list */
73 osi_sleepInfo_t *osi_sleepInfoFreeListp;
74
75 /* boot time */
76 unsigned long osi_bootTime;
77
78 /* count of free entries in free list, protected by osi_sleepInfoAllocCS */
79 long osi_sleepInfoCount=0;
80
81 /* count of # of allocates of sleep info structures */
82 long osi_sleepInfoAllocs = 0;
83
84 /* the sleep bucket lock must be held.
85  * Releases the reference count and frees the structure if the item has
86  * been deleted.
87  */
88 void osi_ReleaseSleepInfo(osi_sleepInfo_t *ap)
89 {
90         if (--ap->refCount == 0 && (ap->states & OSI_SLEEPINFO_DELETED))
91                 osi_FreeSleepInfo(ap);
92 }
93
94 /* must be called with sleep bucket locked.
95  * Frees the structure if it has a 0 reference count (and removes it
96  * from the hash bucket).  Otherwise, we simply mark the item
97  * for deleting when the ref count hits zero.
98  */
99 void osi_FreeSleepInfo(osi_sleepInfo_t *ap)
100 {
101     LONG_PTR idx;
102
103     if (ap->refCount > 0) {
104         TlsSetValue(osi_SleepSlot, NULL);       /* don't reuse me */
105         ap->states |= OSI_SLEEPINFO_DELETED;
106         return;
107     }
108
109     /* remove from hash if still there */
110     if (ap->states & OSI_SLEEPINFO_INHASH) {
111         ap->states &= ~OSI_SLEEPINFO_INHASH;
112         idx = osi_SLEEPHASH(ap->value);
113         osi_QRemoveHT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &ap->q);
114     }
115
116     if (ap->states & OSI_SLEEPINFO_DELETED) {
117         EnterCriticalSection(&osi_sleepInfoAllocCS);
118         ap->q.nextp = (osi_queue_t *) osi_sleepInfoFreeListp;
119         osi_sleepInfoFreeListp = ap;
120         osi_sleepInfoCount++;
121         LeaveCriticalSection(&osi_sleepInfoAllocCS);
122     }
123 }
124
125 /* allocate a new sleep structure from the free list */
126 osi_sleepInfo_t *osi_AllocSleepInfo()
127 {
128         osi_sleepInfo_t *ap;
129
130         EnterCriticalSection(&osi_sleepInfoAllocCS);
131         if (!(ap = osi_sleepInfoFreeListp)) {
132                 ap = (osi_sleepInfo_t *) malloc(sizeof(osi_sleepInfo_t));
133                 ap->sema = CreateSemaphore(NULL, 0, 65536, (char *) 0);
134                 osi_sleepInfoAllocs++;
135         }
136         else {
137                 osi_sleepInfoFreeListp = (osi_sleepInfo_t *) ap->q.nextp;
138                 osi_sleepInfoCount--;
139         }
140         ap->tid = GetCurrentThreadId();
141         ap->states = 0; /* not signalled yet */
142         LeaveCriticalSection(&osi_sleepInfoAllocCS);
143
144         return ap;
145 }
146
147 int osi_Once(osi_once_t *argp)
148 {
149         long i;
150
151         while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
152                 Sleep(0);
153         }
154         
155         if (argp->done == 0) {
156                 argp->done = 1;
157                 return 1;
158         }
159
160         /* otherwise we've already been initialized, so clear lock and return */
161         InterlockedExchange(&argp->atomic, 0);
162         return 0;
163 }
164
165 void osi_EndOnce(osi_once_t *argp)
166 {
167         InterlockedExchange(&argp->atomic, 0);
168 }
169
170 int osi_TestOnce(osi_once_t *argp)
171 {
172         long localDone;
173         long i;
174
175         while ((i=InterlockedExchange(&argp->atomic, 1)) != 0) {
176                 Sleep(0);
177         }
178         
179         localDone = argp->done;
180
181         /* drop interlock */
182         InterlockedExchange(&argp->atomic, 0);
183
184         return (localDone? 0 : 1);
185 }
186
187 /* Initialize the package, should be called while single-threaded.
188  * Can be safely called multiple times.
189  * Must be called before any osi package calls.
190  */
191 void osi_Init(void)
192 {
193         int i;
194         static osi_once_t once;
195         unsigned long remainder;                /* for division output */
196         osi_fdType_t *typep;
197         SYSTEMTIME sysTime;
198         FILETIME fileTime;
199         osi_hyper_t bootTime;
200
201         /* check to see if already initialized; if so, claim success */
202         if (!osi_Once(&once)) return;
203
204         /* setup boot time values */
205         GetSystemTime(&sysTime);
206         SystemTimeToFileTime(&sysTime, &fileTime);
207
208         /* change the base of the time so it won't be negative for a long time */
209         fileTime.dwHighDateTime -= 28000000;
210
211         bootTime.HighPart = fileTime.dwHighDateTime;
212         bootTime.LowPart = fileTime.dwLowDateTime;
213         /* now, bootTime is in 100 nanosecond units, and we'd really rather
214          * have it in 1 second units, units 10,000,000 times bigger.
215          * So, we divide.
216          */
217         bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
218         osi_bootTime = bootTime.LowPart;
219
220         /* initialize thread-local storage for sleep Info structures */
221         osi_SleepSlot = TlsAlloc();
222
223         /* init FD system */
224         osi_InitFD();
225
226         /* initialize critical regions and semaphores */
227         for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
228                 InitializeCriticalSection(&osi_critSec[i]);
229                 osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
230                 osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
231         }
232
233         /* free list CS */
234         InitializeCriticalSection(&osi_sleepInfoAllocCS);
235
236         /* initialize cookie system */
237         InitializeCriticalSection(&osi_sleepFDCS);
238
239         /* register the FD type */
240         typep = osi_RegisterFDType("sleep", &osi_sleepFDOps, NULL);
241         if (typep) {
242                 /* add formatting info */
243                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
244                         "Sleep address", OSI_DBRPC_HEX);
245                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 1,
246                         "Thread ID", 0);
247                 osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
248                         "States", OSI_DBRPC_HEX);
249         }
250         
251         osi_BaseInit();
252
253         osi_StatInit();
254         
255         osi_InitQueue();
256
257         osi_EndOnce(&once);
258 }
259
260 void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, CRITICAL_SECTION *releasep)
261 {
262     osi_sleepInfo_t *sp;
263     unsigned int code;
264
265     sp = TlsGetValue(osi_SleepSlot);
266     if (sp == NULL) {
267         sp = osi_AllocSleepInfo();
268         TlsSetValue(osi_SleepSlot, sp);
269     }
270     else {
271         sp->states = 0;
272     }
273     sp->refCount = 0;
274     sp->waitFor = waitFor;
275     sp->value = (LONG_PTR) patchp;
276     osi_QAddT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
277     if (!turnp->lastp) 
278         turnp->lastp = sp;
279     LeaveCriticalSection(releasep);
280
281         /* now wait for the signal */
282         while(1) {
283                 /* wait */
284                 code = WaitForSingleObject(sp->sema,
285                         /* timeout */ INFINITE);
286
287                 /* if the reason for the wakeup was that we were signalled,
288                  * break out, otherwise try again, since the semaphore count is
289                  * decreased only when we get WAIT_OBJECT_0 back.
290                  */
291                 if (code == WAIT_OBJECT_0) break;
292         }       /* while we're waiting */
293         
294         /* we're the only one who should be looking at or changing this
295          * structure after it gets signalled.  Sema sp->sema isn't signalled
296          * any longer after we're back from WaitForSingleObject, so we can
297          * free this element directly.
298          */
299         osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
300         
301         osi_FreeSleepInfo(sp);
302         
303         /* reobtain, since caller commonly needs it */
304         EnterCriticalSection(releasep);
305 }
306
307 /* must be called with a critical section held that guards the turnstile
308  * structure.  We remove the sleepInfo structure from the queue so we don't
309  * wake the guy again, but we don't free it because we're still using the
310  * semaphore until the guy waiting wakes up.
311  */
312 void osi_TSignal(osi_turnstile_t *turnp)
313 {
314         osi_sleepInfo_t *sp;
315         
316         if (!turnp->lastp) 
317             return;
318         
319         sp = turnp->lastp;
320         turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
321         osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
322         sp->states |= OSI_SLEEPINFO_SIGNALLED;
323         ReleaseSemaphore(sp->sema, 1, (long *) 0);
324 }
325
326 /* like TSignal, only wake *everyone* */
327 void osi_TBroadcast(osi_turnstile_t *turnp)
328 {
329         osi_sleepInfo_t *sp;
330         
331         while(sp = turnp->lastp) {
332                 turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
333                 osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
334                 sp->states |= OSI_SLEEPINFO_SIGNALLED;
335                 ReleaseSemaphore(sp->sema, 1, (long *) 0);
336         }       /* while someone's still asleep */
337 }
338
339 /* special turnstile signal for mutexes and locks.  Wakes up only those who
340  * will really be able to lock the lock.  The assumption is that everyone who
341  * already can use the lock has already been woken (and is thus not in the
342  * turnstile any longer).
343  *
344  * The stillHaveReaders parm is set to 1 if this is a convert from write to read,
345  * indicating that there is still at least one reader, and we should only wake
346  * up other readers.  We use it in a tricky manner: we just pretent we already woke
347  * a reader, and that is sufficient to prevent us from waking a writer.
348  *
349  * The crit sec. csp is released before the threads are woken, but after they
350  * are removed from the turnstile.  It helps ensure that we won't have a spurious
351  * context swap back to us if the release performs a context swap for some reason.
352  */
353 void osi_TSignalForMLs(osi_turnstile_t *turnp, int stillHaveReaders, CRITICAL_SECTION *csp)
354 {
355         osi_sleepInfo_t *tsp;           /* a temp */
356         osi_sleepInfo_t *nsp;           /* a temp */
357         osi_queue_t *wakeupListp;       /* list of dudes to wakeup after dropping lock */
358         int wokeReader;
359         unsigned short *sp;
360         unsigned char *cp;
361         
362         wokeReader = stillHaveReaders;
363         wakeupListp = NULL;
364         while(tsp = turnp->lastp) {
365                 /* look at each sleepInfo until we find someone we're not supposed to
366                  * wakeup.
367                  */
368                 if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
369                         if (wokeReader) break;
370                 }
371                 else wokeReader = 1;
372                 
373                 /* otherwise, we will wake this guy.  For now, remove from this list
374                  * and move to private one, so we can do the wakeup after releasing
375                  * the crit sec.
376                  */
377                 turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
378                 osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &tsp->q);
379                 
380                 /* do the patching required for lock obtaining */
381                 if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
382                         cp = (void *) tsp->value;
383                         (*cp) |= OSI_LOCKFLAG_EXCL;
384                 }
385                 else if (tsp->waitFor & OSI_SLEEPINFO_W4READ) {
386                         sp = (void *) tsp->value;
387                         (*sp)++;
388                 }
389
390                 /* and add to our own list */
391                 tsp->q.nextp = wakeupListp;
392                 wakeupListp = &tsp->q;
393                 
394                 /* now if we woke a writer, we're done, since it is pointless
395                  * to wake more than one writer.
396                  */
397                 if (!wokeReader) break;
398         }
399         
400         /* hit end, or found someone we're not supposed to wakeup */
401         if (csp) LeaveCriticalSection(csp);
402         
403         /* finally, wakeup everyone we found.  Don't free things since the sleeper
404          * will free the sleepInfo structure.
405          */
406         for(tsp = (osi_sleepInfo_t *) wakeupListp; tsp; tsp = nsp) {
407                 /* pull this out first, since *tsp *could* get freed immediately
408                  * after the ReleaseSemaphore, if a context swap occurs.
409                  */
410                 nsp = (osi_sleepInfo_t *) tsp->q.nextp;
411                 tsp->states |= OSI_SLEEPINFO_SIGNALLED;
412                 ReleaseSemaphore(tsp->sema, 1, (long *) 0);
413         }
414 }
415
416 /* utility function to atomically (with respect to WakeSched)
417  * release an atomic counter spin lock and sleep on an
418  * address (value).
419  * Called with no locks held.
420  */
421 void osi_SleepSpin(LONG_PTR sleepValue, CRITICAL_SECTION *releasep)
422 {
423     register LONG_PTR idx;
424     int code;
425     osi_sleepInfo_t *sp;
426     CRITICAL_SECTION *csp;
427
428     sp = TlsGetValue(osi_SleepSlot);
429     if (sp == NULL) {
430         sp = osi_AllocSleepInfo();
431         TlsSetValue(osi_SleepSlot, sp);
432     }
433     else {
434         sp->states = 0;
435     }
436     sp->refCount = 0;
437     sp->value = sleepValue;
438     idx = osi_SLEEPHASH(sleepValue);
439     csp = &osi_critSec[idx];
440     EnterCriticalSection(csp);
441     osi_QAddT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &sp->q);
442     sp->states |= OSI_SLEEPINFO_INHASH;
443     LeaveCriticalSection(releasep);
444     LeaveCriticalSection(csp);
445     osi_totalSleeps++;  /* stats */
446     while(1) {
447         /* wait */
448         code = WaitForSingleObject(sp->sema,
449                                     /* timeout */ INFINITE);
450
451         /* if the reason for the wakeup was that we were signalled,
452         * break out, otherwise try again, since the semaphore count is
453         * decreased only when we get WAIT_OBJECT_0 back.
454         */
455         if (code == WAIT_OBJECT_0) break;
456     }
457
458     /* now clean up */
459     EnterCriticalSection(csp);
460
461     /* must be signalled */
462     osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
463
464     /* free the sleep structure, must be done under bucket lock
465      * so that we can check reference count and serialize with
466      * those who change it.
467      */
468     osi_FreeSleepInfo(sp);
469
470     LeaveCriticalSection(csp);
471 }
472
473 /* utility function to wakeup someone sleeping in SleepSched */
474 void osi_WakeupSpin(LONG_PTR sleepValue)
475 {
476     register LONG_PTR idx;
477     register CRITICAL_SECTION *csp;
478     register osi_sleepInfo_t *tsp;
479
480     idx = osi_SLEEPHASH(sleepValue);
481     csp = &osi_critSec[idx];
482     EnterCriticalSection(csp);
483         for(tsp=osi_sleepers[idx]; tsp; tsp=(osi_sleepInfo_t *) osi_QNext(&tsp->q)) {
484             if ((!(tsp->states & (OSI_SLEEPINFO_DELETED|OSI_SLEEPINFO_SIGNALLED)))
485                  && tsp->value == sleepValue) {
486                 ReleaseSemaphore(tsp->sema, 1, (long *) 0);
487                 tsp->states |= OSI_SLEEPINFO_SIGNALLED;
488             }
489         }       
490     LeaveCriticalSection(csp);
491 }       
492
493 void osi_Sleep(LONG_PTR sleepVal)
494 {
495         CRITICAL_SECTION *csp;
496         
497         /* may as well save some code by using SleepSched again */
498         csp = &osi_baseAtomicCS[0];
499         EnterCriticalSection(csp);
500         osi_SleepSpin(sleepVal, csp);
501 }
502
503 void osi_Wakeup(LONG_PTR sleepVal)
504 {
505         /* how do we do osi_Wakeup on a per-lock package type? */
506
507         osi_WakeupSpin(sleepVal);
508 }
509
510 long osi_SleepFDCreate(osi_fdType_t *fdTypep, osi_fd_t **outpp)
511 {
512         osi_sleepFD_t *cp;
513
514         cp = (osi_sleepFD_t *)malloc(sizeof(*cp));
515         memset((void *) cp, 0, sizeof(*cp));
516         cp->idx = 0;
517         cp->sip = NULL;
518
519         /* done */
520         *outpp = &cp->fd;
521         return 0;
522 }
523
524 long osi_SleepFDClose(osi_fd_t *cp)
525 {
526         free((void *) cp);
527         return 0;
528 }
529
530 /* called with osi_sleepFDCS locked; returns with same, so that
531  * we know that the sleep info pointed to by the cookie won't change
532  * until the caller releases the lock.
533  */
534 void osi_AdvanceSleepFD(osi_sleepFD_t *cp)
535 {
536         int idx;                /* index we're dealing with */
537         int oidx;               /* index we locked */
538         osi_sleepInfo_t *sip;
539         osi_sleepInfo_t *nsip;
540
541         idx = 0;        /* so we go around once safely */
542         sip = NULL;
543         while(idx < OSI_SLEEPHASHSIZE) {
544                 /* cp->sip should be held */
545                 idx = cp->idx;
546                 EnterCriticalSection(&osi_critSec[idx]);
547                 oidx = idx;     /* remember original index; that's the one we locked */
548
549                 /* if there's a sleep info structure in the FD, it should be held; it
550                  * is the one we just processed, so we want to move on to the next.
551                  * If not, then we want to process the chain in the bucket idx points
552                  * to.
553                  */
554                 if ((sip = cp->sip) == NULL) {
555                         sip = osi_sleepers[idx];
556                         if (!sip) idx++;
557                         else sip->refCount++;
558                 }
559                 else {
560                         /* it is safe to release the current sleep info guy now
561                          * since we hold the bucket lock.  Pull next guy out first,
562                          * since if sip is deleted, Release will move him into
563                          * free list.
564                          */
565                         nsip = (osi_sleepInfo_t *) sip->q.nextp;
566                         osi_ReleaseSleepInfo(sip);
567                         sip = nsip;
568                         
569                         if (sip) sip->refCount++;
570                         else idx++;
571                 }
572                 cp->idx = idx;
573                 cp->sip = sip;
574                 LeaveCriticalSection(&osi_critSec[oidx]);
575
576                 /* now, if we advanced to a new sleep info structure, we're
577                  * done, otherwise we continue and look at the next hash bucket
578                  * until we're out of them.
579                  */
580                 if (sip) break;
581         }
582 }
583
584
585 long osi_SleepFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
586 {
587     osi_sleepFD_t *fdp = (osi_sleepFD_t *) ifdp;
588     osi_sleepInfo_t *sip;
589     long code;
590
591     /* now, grab a mutex serializing all iterations over FDs, so that
592      * if the RPC screws up and sends us two calls on the same FD, we don't
593      * crash and burn advancing the same FD concurrently.  Probably paranoia,
594      * but you generally shouldn't trust stuff coming over the network.
595      */
596     EnterCriticalSection(&osi_sleepFDCS);
597
598     /* this next call advances the FD to the next guy, and simultaneously validates
599      * that the info from the network is valid.  If it isn't, we do our best to
600      * resynchronize our position, but we might return some info multiple times.
601      */
602     osi_AdvanceSleepFD(fdp);
603
604     /* now copy out info */
605     if (sip = fdp->sip) {       /* one '=' */
606         parmsp->idata[0] = sip->value;
607         parmsp->idata[1] = sip->tid;
608         parmsp->idata[2] = sip->states;
609         parmsp->icount = 3;
610         parmsp->scount = 0;
611         code = 0;
612     }
613     else code = OSI_DBRPC_EOF;
614
615     LeaveCriticalSection(&osi_sleepFDCS);
616
617     return code;
618 }
619
620 /* finally, DLL-specific code for NT */
621 BOOL APIENTRY DLLMain(HANDLE inst, DWORD why, char *reserved)
622 {
623         return 1;
624 }
625
626 /* some misc functions for setting hash table sizes */
627
628 /* return true iff x is prime */
629 int osi_IsPrime(unsigned long x)
630 {
631         unsigned long c;
632         
633         /* even numbers aren't prime */
634         if ((x & 1) == 0 && x != 2) return 0;
635
636         for(c = 3; c<x; c += 2) {
637                 /* see if x is divisible by c */
638                 if ((x % c) == 0) return 0;     /* yup, it ain't prime */
639                 
640                 /* see if we've gone far enough; only have to compute until
641                  * square root of x.
642                  */
643                 if (c*c > x) return 1;
644         }
645
646         /* probably never get here */
647         return 1;
648 }
649
650 /* return first prime number less than or equal to x */
651 unsigned long osi_PrimeLessThan(unsigned long x) {
652         unsigned long c;
653         
654         for(c = x; c > 1; c--) {
655                 if (osi_IsPrime(c)) return c;
656         }
657
658         /* ever reached? */
659         return 1;
660 }
661
662 /* return the # of seconds since some fixed date */
663 unsigned long osi_GetBootTime(void)
664 {
665         return osi_bootTime;
666 }
667
668 static int (*notifFunc)(char *, char *, long) = NULL;
669
670 void osi_InitPanic(void *anotifFunc)
671 {
672         notifFunc = anotifFunc;
673 }
674
675 void osi_panic(char *msgp, char *filep, long line)
676 {
677         osi_LogPanic(filep, line);
678
679         if (notifFunc)
680                 (*notifFunc)(msgp, filep, line);
681 }
682
683 /* get time in seconds since some relatively recent time */
684 time_t osi_Time(void)
685 {
686     FILETIME fileTime;
687     SYSTEMTIME sysTime;
688     unsigned long remainder;
689     LARGE_INTEGER bootTime;
690
691     /* setup boot time values */
692     GetSystemTime(&sysTime);
693     SystemTimeToFileTime(&sysTime, &fileTime);
694
695     /* change the base of the time so it won't be negative for a long time */
696     fileTime.dwHighDateTime -= 28000000;
697
698     bootTime.HighPart = fileTime.dwHighDateTime;
699     bootTime.LowPart = fileTime.dwLowDateTime;
700     /* now, bootTime is in 100 nanosecond units, and we'd really rather
701      * have it in 1 second units, units 10,000,000 times bigger.
702      * So, we divide.
703      */
704     bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
705 #ifdef __WIN64
706     return bootTime.QuadPart;
707 #else
708     return bootTime.LowPart;
709 #endif
710 }
711
712 /* get time in seconds since some relatively recent time */
713 void osi_GetTime(long *timesp)
714 {
715         FILETIME fileTime;
716         SYSTEMTIME sysTime;
717         unsigned long remainder;
718         LARGE_INTEGER bootTime;
719
720         /* setup boot time values */
721         GetSystemTime(&sysTime);
722         SystemTimeToFileTime(&sysTime, &fileTime);
723
724         /* change the base of the time so it won't be negative for a long time */
725         fileTime.dwHighDateTime -= 28000000;
726
727         bootTime.HighPart = fileTime.dwHighDateTime;
728         bootTime.LowPart = fileTime.dwLowDateTime;
729         /* now, bootTime is in 100 nanosecond units, and we'd really rather
730          * have it in 1 microsecond units, units 10 times bigger.
731          * So, we divide.
732          */
733         bootTime = ExtendedLargeIntegerDivide(bootTime, 10, &remainder);
734         bootTime = ExtendedLargeIntegerDivide(bootTime, 1000000, &remainder);
735         timesp[0] = bootTime.LowPart;           /* seconds */
736         timesp[1] = remainder;                  /* microseconds */
737 }