Windows: record history of read lock threads
[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))
203         return;
204
205     /* setup boot time values */
206     GetSystemTime(&sysTime);
207     SystemTimeToFileTime(&sysTime, &fileTime);
208
209     /* change the base of the time so it won't be negative for a long time */
210     fileTime.dwHighDateTime -= 28000000;
211
212     bootTime.HighPart = fileTime.dwHighDateTime;
213     bootTime.LowPart = fileTime.dwLowDateTime;
214     /* now, bootTime is in 100 nanosecond units, and we'd really rather
215      * have it in 1 second units, units 10,000,000 times bigger.
216      * So, we divide.
217      */
218     bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
219     osi_bootTime = bootTime.LowPart;
220
221     /* initialize thread-local storage for sleep Info structures */
222     osi_SleepSlot = TlsAlloc();
223
224     /* init FD system */
225     osi_InitFD();
226
227     /* initialize critical regions and semaphores */
228     for(i=0;i<OSI_SLEEPHASHSIZE; i++) {
229         InitializeCriticalSection(&osi_critSec[i]);
230         osi_sleepers[i] = (osi_sleepInfo_t *) NULL;
231         osi_sleepersEnd[i] = (osi_sleepInfo_t *) NULL;
232     }
233
234     /* free list CS */
235     InitializeCriticalSection(&osi_sleepInfoAllocCS);
236
237     /* initialize cookie system */
238     InitializeCriticalSection(&osi_sleepFDCS);
239
240     /* register the FD type */
241     typep = osi_RegisterFDType("sleep", &osi_sleepFDOps, NULL);
242     if (typep) {
243         /* add formatting info */
244         osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 0,
245                              "Sleep address", OSI_DBRPC_HEX);
246         osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 1,
247                              "Thread ID", 0);
248         osi_AddFDFormatInfo(typep, OSI_DBRPC_REGIONINT, 2,
249                              "States", OSI_DBRPC_HEX);
250     }
251
252     osi_BaseInit();
253
254     osi_StatInit();
255
256     osi_InitQueue();
257
258     osi_EndOnce(&once);
259 }
260
261 void osi_TWait(osi_turnstile_t *turnp, int waitFor, void *patchp, DWORD *tidp, CRITICAL_SECTION *releasep)
262 {
263     osi_sleepInfo_t *sp;
264     unsigned int code;
265
266     sp = TlsGetValue(osi_SleepSlot);
267     if (sp == NULL) {
268         sp = osi_AllocSleepInfo();
269         TlsSetValue(osi_SleepSlot, sp);
270     }
271     else {
272         sp->states = 0;
273     }
274     sp->refCount = 0;
275     sp->waitFor = waitFor;
276     sp->value = (LONG_PTR) patchp;
277     sp->tidp   = tidp;
278     osi_QAddT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
279     if (!turnp->lastp)
280         turnp->lastp = sp;
281     LeaveCriticalSection(releasep);
282
283     /* now wait for the signal */
284     while(1) {
285         /* wait */
286         code = WaitForSingleObject(sp->sema,
287                                     /* timeout */ INFINITE);
288
289         /* if the reason for the wakeup was that we were signalled,
290          * break out, otherwise try again, since the semaphore count is
291          * decreased only when we get WAIT_OBJECT_0 back.
292          */
293         if (code == WAIT_OBJECT_0) break;
294     }   /* while we're waiting */
295
296     /* we're the only one who should be looking at or changing this
297      * structure after it gets signalled.  Sema sp->sema isn't signalled
298      * any longer after we're back from WaitForSingleObject, so we can
299      * free this element directly.
300      */
301     osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
302
303     osi_FreeSleepInfo(sp);
304
305     /* reobtain, since caller commonly needs it */
306     EnterCriticalSection(releasep);
307 }
308
309 /* must be called with a critical section held that guards the turnstile
310  * structure.  We remove the sleepInfo structure from the queue so we don't
311  * wake the guy again, but we don't free it because we're still using the
312  * semaphore until the guy waiting wakes up.
313  */
314 void osi_TSignal(osi_turnstile_t *turnp)
315 {
316     osi_sleepInfo_t *sp;
317
318     if (!turnp->lastp)
319         return;
320
321     sp = turnp->lastp;
322     turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
323     osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
324     sp->states |= OSI_SLEEPINFO_SIGNALLED;
325     ReleaseSemaphore(sp->sema, 1, (long *) 0);
326 }
327
328 /* like TSignal, only wake *everyone* */
329 void osi_TBroadcast(osi_turnstile_t *turnp)
330 {
331     osi_sleepInfo_t *sp;
332
333     while(sp = turnp->lastp) {
334         turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&sp->q);
335         osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &sp->q);
336         sp->states |= OSI_SLEEPINFO_SIGNALLED;
337         ReleaseSemaphore(sp->sema, 1, (long *) 0);
338     }   /* while someone's still asleep */
339 }
340
341 /* special turnstile signal for mutexes and locks.  Wakes up only those who
342  * will really be able to lock the lock.  The assumption is that everyone who
343  * already can use the lock has already been woken (and is thus not in the
344  * turnstile any longer).
345  *
346  * The stillHaveReaders parm is set to 1 if this is a convert from write to read,
347  * indicating that there is still at least one reader, and we should only wake
348  * up other readers.  We use it in a tricky manner: we just pretent we already woke
349  * a reader, and that is sufficient to prevent us from waking a writer.
350  *
351  * The crit sec. csp is released before the threads are woken, but after they
352  * are removed from the turnstile.  It helps ensure that we won't have a spurious
353  * context swap back to us if the release performs a context swap for some reason.
354  */
355 void osi_TSignalForMLs(osi_turnstile_t *turnp, int stillHaveReaders, CRITICAL_SECTION *csp)
356 {
357     osi_sleepInfo_t *tsp;               /* a temp */
358     osi_sleepInfo_t *nsp;               /* a temp */
359     osi_queue_t *wakeupListp;   /* list of dudes to wakeup after dropping lock */
360     int wokeReader;
361     unsigned short *sp;
362     unsigned char *cp;
363
364     wokeReader = stillHaveReaders;
365     wakeupListp = NULL;
366     while(tsp = turnp->lastp) {
367         /* look at each sleepInfo until we find someone we're not supposed to
368          * wakeup.
369          */
370         if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
371             if (wokeReader)
372                 break;
373         }
374         else
375             wokeReader = 1;
376
377         /* otherwise, we will wake this guy.  For now, remove from this list
378          * and move to private one, so we can do the wakeup after releasing
379          * the crit sec.
380          */
381         turnp->lastp = (osi_sleepInfo_t *) osi_QPrev(&tsp->q);
382         osi_QRemoveHT((osi_queue_t **) &turnp->firstp, (osi_queue_t **) &turnp->lastp, &tsp->q);
383
384         /* do the patching required for lock obtaining */
385         if (tsp->waitFor & OSI_SLEEPINFO_W4WRITE) {
386             cp = (void *) tsp->value;
387             (*cp) |= OSI_LOCKFLAG_EXCL;
388             tsp->tidp[0] = tsp->tid;
389         }
390         else if (tsp->waitFor & OSI_SLEEPINFO_W4READ) {
391             sp = (void *) tsp->value;
392             (*sp)++;
393             if ((*sp) <= OSI_RWLOCK_THREADS)
394                 tsp->tidp[(*sp)-1] = tsp->tid;
395         }
396
397         /* and add to our own list */
398         tsp->q.nextp = wakeupListp;
399         wakeupListp = &tsp->q;
400
401         /* now if we woke a writer, we're done, since it is pointless
402          * to wake more than one writer.
403          */
404         if (!wokeReader)
405             break;
406     }
407
408     /* hit end, or found someone we're not supposed to wakeup */
409     if (csp)
410         LeaveCriticalSection(csp);
411
412         /* finally, wakeup everyone we found.  Don't free things since the sleeper
413          * will free the sleepInfo structure.
414          */
415         for(tsp = (osi_sleepInfo_t *) wakeupListp; tsp; tsp = nsp) {
416             /* pull this out first, since *tsp *could* get freed immediately
417              * after the ReleaseSemaphore, if a context swap occurs.
418              */
419             nsp = (osi_sleepInfo_t *) tsp->q.nextp;
420             tsp->states |= OSI_SLEEPINFO_SIGNALLED;
421             ReleaseSemaphore(tsp->sema, 1, (long *) 0);
422         }
423 }
424
425 /* utility function to atomically (with respect to WakeSched)
426  * release an atomic counter spin lock and sleep on an
427  * address (value).
428  * Called with no locks held.
429  */
430 void osi_SleepSpin(LONG_PTR sleepValue, CRITICAL_SECTION *releasep)
431 {
432     LONG_PTR idx;
433     int code;
434     osi_sleepInfo_t *sp;
435     CRITICAL_SECTION *csp;
436
437     sp = TlsGetValue(osi_SleepSlot);
438     if (sp == NULL) {
439         sp = osi_AllocSleepInfo();
440         TlsSetValue(osi_SleepSlot, sp);
441     }
442     else {
443         sp->states = 0;
444     }
445     sp->refCount = 0;
446     sp->value = sleepValue;
447     idx = osi_SLEEPHASH(sleepValue);
448     csp = &osi_critSec[idx];
449     EnterCriticalSection(csp);
450     osi_QAddT((osi_queue_t **) &osi_sleepers[idx], (osi_queue_t **) &osi_sleepersEnd[idx], &sp->q);
451     sp->states |= OSI_SLEEPINFO_INHASH;
452     LeaveCriticalSection(releasep);
453     LeaveCriticalSection(csp);
454     osi_totalSleeps++;  /* stats */
455     while(1) {
456         /* wait */
457         code = WaitForSingleObject(sp->sema,
458                                     /* timeout */ INFINITE);
459
460         /* if the reason for the wakeup was that we were signalled,
461         * break out, otherwise try again, since the semaphore count is
462         * decreased only when we get WAIT_OBJECT_0 back.
463         */
464         if (code == WAIT_OBJECT_0) break;
465     }
466
467     /* now clean up */
468     EnterCriticalSection(csp);
469
470     /* must be signalled */
471     osi_assert(sp->states & OSI_SLEEPINFO_SIGNALLED);
472
473     /* free the sleep structure, must be done under bucket lock
474      * so that we can check reference count and serialize with
475      * those who change it.
476      */
477     osi_FreeSleepInfo(sp);
478
479     LeaveCriticalSection(csp);
480 }
481
482 /* utility function to wakeup someone sleeping in SleepSched */
483 void osi_WakeupSpin(LONG_PTR sleepValue)
484 {
485     LONG_PTR idx;
486     CRITICAL_SECTION *csp;
487     osi_sleepInfo_t *tsp;
488
489     idx = osi_SLEEPHASH(sleepValue);
490     csp = &osi_critSec[idx];
491     EnterCriticalSection(csp);
492         for(tsp=osi_sleepers[idx]; tsp; tsp=(osi_sleepInfo_t *) osi_QNext(&tsp->q)) {
493             if ((!(tsp->states & (OSI_SLEEPINFO_DELETED|OSI_SLEEPINFO_SIGNALLED)))
494                  && tsp->value == sleepValue) {
495                 ReleaseSemaphore(tsp->sema, 1, (long *) 0);
496                 tsp->states |= OSI_SLEEPINFO_SIGNALLED;
497             }
498         }
499     LeaveCriticalSection(csp);
500 }
501
502 void osi_Sleep(LONG_PTR sleepVal)
503 {
504     CRITICAL_SECTION *csp;
505
506     /* may as well save some code by using SleepSched again */
507     csp = &osi_baseAtomicCS[0];
508     EnterCriticalSection(csp);
509     osi_SleepSpin(sleepVal, csp);
510 }
511
512 void osi_Wakeup(LONG_PTR sleepVal)
513 {
514     /* how do we do osi_Wakeup on a per-lock package type? */
515
516     osi_WakeupSpin(sleepVal);
517 }
518
519 long osi_SleepFDCreate(osi_fdType_t *fdTypep, osi_fd_t **outpp)
520 {
521     osi_sleepFD_t *cp;
522
523     cp = (osi_sleepFD_t *)malloc(sizeof(*cp));
524     memset((void *) cp, 0, sizeof(*cp));
525     cp->idx = 0;
526     cp->sip = NULL;
527
528     /* done */
529     *outpp = &cp->fd;
530     return 0;
531 }
532
533 long osi_SleepFDClose(osi_fd_t *cp)
534 {
535     free((void *) cp);
536     return 0;
537 }
538
539 /* called with osi_sleepFDCS locked; returns with same, so that
540  * we know that the sleep info pointed to by the cookie won't change
541  * until the caller releases the lock.
542  */
543 void osi_AdvanceSleepFD(osi_sleepFD_t *cp)
544 {
545     int idx;            /* index we're dealing with */
546     int oidx;           /* index we locked */
547     osi_sleepInfo_t *sip;
548     osi_sleepInfo_t *nsip;
549
550     idx = 0;    /* so we go around once safely */
551     sip = NULL;
552     while(idx < OSI_SLEEPHASHSIZE) {
553         /* cp->sip should be held */
554         idx = cp->idx;
555         EnterCriticalSection(&osi_critSec[idx]);
556         oidx = idx;     /* remember original index; that's the one we locked */
557
558         /* if there's a sleep info structure in the FD, it should be held; it
559          * is the one we just processed, so we want to move on to the next.
560          * If not, then we want to process the chain in the bucket idx points
561          * to.
562          */
563         if ((sip = cp->sip) == NULL) {
564             sip = osi_sleepers[idx];
565             if (!sip) idx++;
566             else sip->refCount++;
567         }
568         else {
569             /* it is safe to release the current sleep info guy now
570              * since we hold the bucket lock.  Pull next guy out first,
571              * since if sip is deleted, Release will move him into
572              * free list.
573              */
574             nsip = (osi_sleepInfo_t *) sip->q.nextp;
575             osi_ReleaseSleepInfo(sip);
576             sip = nsip;
577
578             if (sip)
579                 sip->refCount++;
580             else
581                 idx++;
582         }
583         cp->idx = idx;
584         cp->sip = sip;
585         LeaveCriticalSection(&osi_critSec[oidx]);
586
587         /* now, if we advanced to a new sleep info structure, we're
588          * done, otherwise we continue and look at the next hash bucket
589          * until we're out of them.
590          */
591         if (sip)
592             break;
593     }
594 }
595
596
597 long osi_SleepFDGetInfo(osi_fd_t *ifdp, osi_remGetInfoParms_t *parmsp)
598 {
599     osi_sleepFD_t *fdp = (osi_sleepFD_t *) ifdp;
600     osi_sleepInfo_t *sip;
601     long code;
602
603     /* now, grab a mutex serializing all iterations over FDs, so that
604      * if the RPC screws up and sends us two calls on the same FD, we don't
605      * crash and burn advancing the same FD concurrently.  Probably paranoia,
606      * but you generally shouldn't trust stuff coming over the network.
607      */
608     EnterCriticalSection(&osi_sleepFDCS);
609
610     /* this next call advances the FD to the next guy, and simultaneously validates
611      * that the info from the network is valid.  If it isn't, we do our best to
612      * resynchronize our position, but we might return some info multiple times.
613      */
614     osi_AdvanceSleepFD(fdp);
615
616     /* now copy out info */
617     if (sip = fdp->sip) {       /* one '=' */
618         parmsp->idata[0] = sip->value;
619         parmsp->idata[1] = sip->tid;
620         parmsp->idata[2] = sip->states;
621         parmsp->icount = 3;
622         parmsp->scount = 0;
623         code = 0;
624     }
625     else code = OSI_DBRPC_EOF;
626
627     LeaveCriticalSection(&osi_sleepFDCS);
628
629     return code;
630 }
631
632 /* finally, DLL-specific code for NT */
633 BOOL APIENTRY DLLMain(HANDLE inst, DWORD why, char *reserved)
634 {
635     return 1;
636 }
637
638 /* some misc functions for setting hash table sizes */
639
640 /* return true iff x is prime */
641 int osi_IsPrime(unsigned long x)
642 {
643     unsigned long c;
644
645     /* even numbers aren't prime */
646     if ((x & 1) == 0 && x != 2) return 0;
647
648     for(c = 3; c<x; c += 2) {
649         /* see if x is divisible by c */
650         if ((x % c) == 0)
651             return 0;   /* yup, it ain't prime */
652
653         /* see if we've gone far enough; only have to compute until
654          * square root of x.
655          */
656         if (c*c > x)
657             return 1;
658     }
659
660     /* probably never get here */
661     return 1;
662 }
663
664 /* return first prime number less than or equal to x */
665 unsigned long osi_PrimeLessThan(unsigned long x) {
666     unsigned long c;
667
668     for(c = x; c > 1; c--) {
669         if (osi_IsPrime(c))
670             return c;
671     }
672
673     /* ever reached? */
674     return 1;
675 }
676
677 /* return the # of seconds since some fixed date */
678 unsigned long osi_GetBootTime(void)
679 {
680     return osi_bootTime;
681 }
682
683 static int (*notifFunc)(char *, char *, long) = NULL;
684
685 void osi_InitPanic(void *anotifFunc)
686 {
687     notifFunc = anotifFunc;
688 }
689
690 void osi_panic(char *msgp, char *filep, long line)
691 {
692     if (notifFunc)
693         (*notifFunc)(msgp, filep, line);
694
695     osi_LogPanic(msgp, filep, line);
696 }
697
698 /* get time in seconds since some relatively recent time */
699 time_t osi_Time(void)
700 {
701     FILETIME fileTime;
702     SYSTEMTIME sysTime;
703     unsigned long remainder;
704     LARGE_INTEGER bootTime;
705
706     /* setup boot time values */
707     GetSystemTime(&sysTime);
708     SystemTimeToFileTime(&sysTime, &fileTime);
709
710     /* change the base of the time so it won't be negative for a long time */
711     fileTime.dwHighDateTime -= 28000000;
712
713     bootTime.HighPart = fileTime.dwHighDateTime;
714     bootTime.LowPart = fileTime.dwLowDateTime;
715     /* now, bootTime is in 100 nanosecond units, and we'd really rather
716      * have it in 1 second units, units 10,000,000 times bigger.
717      * So, we divide.
718      */
719     bootTime = ExtendedLargeIntegerDivide(bootTime, 10000000, &remainder);
720 #ifdef __WIN64
721     return bootTime.QuadPart;
722 #else
723     return bootTime.LowPart;
724 #endif
725 }
726
727 /* get time in seconds since some relatively recent time */
728 void osi_GetTime(long *timesp)
729 {
730     FILETIME fileTime;
731     SYSTEMTIME sysTime;
732     unsigned long remainder;
733     LARGE_INTEGER bootTime;
734
735     /* setup boot time values */
736     GetSystemTime(&sysTime);
737     SystemTimeToFileTime(&sysTime, &fileTime);
738
739     /* change the base of the time so it won't be negative for a long time */
740     fileTime.dwHighDateTime -= 28000000;
741
742     bootTime.HighPart = fileTime.dwHighDateTime;
743     bootTime.LowPart = fileTime.dwLowDateTime;
744     /* now, bootTime is in 100 nanosecond units, and we'd really rather
745      * have it in 1 microsecond units, units 10 times bigger.
746      * So, we divide.
747      */
748     bootTime = ExtendedLargeIntegerDivide(bootTime, 10, &remainder);
749     bootTime = ExtendedLargeIntegerDivide(bootTime, 1000000, &remainder);
750     timesp[0] = bootTime.LowPart;               /* seconds */
751     timesp[1] = remainder;                      /* microseconds */
752 }