Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / win32.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     win32.c
8
9 Abstract:
10
11     Windows(R) operating system dependent code.
12
13 Author:
14
15     Scott Gasch ([email protected]) 7 Apr 2004
16
17 Revision History:
18
19     $Id: win32.c 345 2007-12-02 22:56:42Z scott $
20
21 **/
22
23 #include "chess.h"
24 #define _WIN32_WINNT 0x403
25
26 #pragma warning(disable:4142) // benign redefinition of type
27 #include <windows.h>
28 #pragma warning(default:4142)
29
30 #define SYS_MAX_HEAP_ALLOC_SIZE_BYTES 0xfff
31
32 //
33 // Global system lock
34 //
35 CRITICAL_SECTION g_SystemLock;
36 #define LOCK_SYSTEM   EnterCriticalSection(&g_SystemLock)
37 #define UNLOCK_SYSTEM LeaveCriticalSection(&g_SystemLock)
38
39 //
40 // Thread table
41 //
42 typedef struct _SYSTEM_THREAD_TABLE_ENTRY
43 {
44     DLIST_ENTRY links;
45     ULONG uWrapperHandle;
46     ULONG uTid;
47     ULONG uThreadParam;
48     THREAD_ENTRYPOINT *pEntry;
49     ULONG uExitCode;
50     HANDLE hThread;
51 }
52 SYSTEM_THREAD_TABLE_ENTRY;
53 DLIST_ENTRY g_SystemThreadList;
54
55 //
56 // Global buffer to hold a bunch of system dependent numbers / settings
57 // 
58 typedef struct _SYS_INFORMATION_BUFFER
59 {
60     FLAG fPopulated;
61     SYSTEM_INFO si;
62     OSVERSIONINFOEX vi;
63     MEMORYSTATUS ms;
64 }
65 SYS_INFORMATION_BUFFER;
66 SYS_INFORMATION_BUFFER g_SystemInfoBuffer;
67
68 //
69 // The frequency and type of our TimeStamp timer
70 //
71 double g_dTimeStampFrequency = 0.0;
72 ULONG g_uTimeStampType = 0;
73 ULONG g_uMaxHeapAllocationSize = 0;
74
75 //
76 // A history of allocations
77 // 
78 #ifdef DEBUG
79 ULONG g_uTotalAlloced = 0;
80
81 #define ALLOC_HASH_SIZE 0x4000
82
83 typedef struct _ALLOC_RECORD
84 {
85     void *p;
86     ULONG uSize;
87 } ALLOC_RECORD;
88 ALLOC_RECORD g_AllocHash[ALLOC_HASH_SIZE];
89
90 #define PTR_TO_ALLOC_HASH(x) ((((ULONG_PTR)(x)) >> 3) & (ALLOC_HASH_SIZE - 1))
91
92 ULONG
93 GetHeapMemoryUsage(void)
94 {
95     Trace("There are now %u bytes outstanding.\n", g_uTotalAlloced);
96     return(g_uTotalAlloced);
97 }
98
99 static void 
100 ReleaseAllocHashEntry(void *p)
101 {
102     ULONG u = PTR_TO_ALLOC_HASH(p);
103     ULONG v = u;
104
105     LOCK_SYSTEM;
106     while(g_AllocHash[u].p != p)
107     {
108         u++;
109         u &= (ALLOC_HASH_SIZE - 1);
110         if (v == u) return;
111     }
112     g_AllocHash[u].p = NULL;
113     g_uTotalAlloced -= g_AllocHash[u].uSize;
114     UNLOCK_SYSTEM;
115
116 //    Trace("Freed %u bytes at 0x%p.\n", g_AllocHash[u].uSize, p);
117 }
118
119 static void
120 MarkAllocHashEntry(void *p, ULONG uSize)
121 {
122     ULONG u = PTR_TO_ALLOC_HASH(p);
123
124     if (uSize > (1024 * 1024 * 30)) return;
125
126     LOCK_SYSTEM;
127     while(g_AllocHash[u].p != NULL)
128     {
129         u++;
130         u &= (ALLOC_HASH_SIZE - 1);
131     }
132     g_AllocHash[u].p = p;
133     g_AllocHash[u].uSize = uSize;
134     g_uTotalAlloced += uSize;
135     UNLOCK_SYSTEM;
136
137 //    Trace("Alloc %u bytes at 0x%p.\n", g_AllocHash[u].uSize, p);
138 }
139 #endif
140
141
142 CHAR *
143 SystemStrDup(CHAR *p)
144 /**
145
146 Routine description:
147
148     Local implementation of strdup
149
150 Parameters:
151
152     CHAR *p
153
154 Return value:
155
156     CHAR
157
158 **/
159 {
160     CHAR *q = SystemAllocateMemory((ULONG)strlen(p) + 1);
161
162     ASSERT(strlen(p) < (size_t)MAX_ULONG);
163     strcpy(q, p);
164     return(q);
165 }
166
167
168 CHAR *
169 SystemGetDateString(void)
170 /**
171
172 Routine description:
173
174     Get the current date as a string.
175
176 Parameters:
177
178     void
179
180 Return value:
181
182     CHAR
183
184 **/
185 {
186     static CHAR buf[32];
187     SYSTEMTIME st;
188     
189     GetSystemTime(&st);
190
191     snprintf(buf, ARRAY_LENGTH(buf), 
192              "%u.%02u.%02u", st.wYear, st.wMonth, st.wDay);
193     return(buf);
194 }
195
196
197 CHAR *
198 SystemGetTimeString(void)
199 /**
200
201 Routine description:
202
203     Get the current time as a string.
204
205 Parameters:
206
207     void
208
209 Return value:
210
211     CHAR
212
213 **/
214 {
215     static CHAR buf[32];
216     SYSTEMTIME st;
217     
218     GetSystemTime(&st);
219
220     snprintf(buf, ARRAY_LENGTH(buf),
221              "%u:%02u:%02u", st.wHour, st.wMinute, st.wSecond);
222     return(buf);
223 }
224
225
226 void 
227 SystemDeferExecution(ULONG uMs)
228 /**
229
230 Routine description:
231
232     Sleep for some number of milliseconds.
233
234 Parameters:
235
236     ULONG uMs
237
238 Return value:
239
240     void
241
242 **/
243 {
244     Sleep(uMs);
245 }
246
247 static SYSTEM_THREAD_TABLE_ENTRY *
248 _SystemGetThreadTableEntry(ULONG uThreadHandle)
249 /**
250
251 Routine description:
252
253     Support code for the thread functionality wrapper.  Given a thread
254     "handle" return its thread table struct.
255
256 Parameters:
257
258     ULONG uThreadHandle
259
260 Return value:
261
262     SYSTEM_THREAD_TABLE_ENTRY *
263
264 **/
265 {
266     DLIST_ENTRY *p;
267     SYSTEM_THREAD_TABLE_ENTRY *q;
268
269     LOCK_SYSTEM;
270     p = g_SystemThreadList.pFlink;
271     while(p != &g_SystemThreadList)
272     {
273         q = CONTAINING_STRUCT(p, SYSTEM_THREAD_TABLE_ENTRY, links);
274         if (q->uWrapperHandle == uThreadHandle)
275         {
276             goto end;
277         }
278         p = p->pFlink;
279     }
280     q = NULL;
281  end:
282     UNLOCK_SYSTEM;
283     return(q);
284 }
285
286 int WINAPI 
287 SystemThreadEntryPoint(VOID *pParam)
288 /**
289
290 Routine description:
291
292     The real entry point of all new threads.  It calls into the user
293     specified entry point.
294
295 Parameters:
296
297     VOID *pParam
298
299 Return value:
300
301     int WINAPI
302
303 **/
304 {
305     SYSTEM_THREAD_TABLE_ENTRY *p = (SYSTEM_THREAD_TABLE_ENTRY *)pParam;
306     ULONG uParam;
307     int i;
308     
309     LOCK_SYSTEM;
310     UNLOCK_SYSTEM;
311
312     uParam = p->uThreadParam;
313     i = (int)(*(p->pEntry))(uParam);
314     return(i);
315 }
316
317 FLAG 
318 SystemCreateThread(THREAD_ENTRYPOINT *pEntry, ULONG uParam, ULONG *puHandle)
319 /**
320
321 Routine description:
322
323     Wrapper function to expose create thread functionality.
324
325 Parameters:
326
327     THREAD_ENTRYPOINT *pEntry,
328     ULONG uParam,
329     ULONG *puHandle
330
331 Return value:
332
333     FLAG
334
335 **/
336 {
337     SYSTEM_THREAD_TABLE_ENTRY *p;
338
339     p = HeapAlloc(GetProcessHeap(),
340                   HEAP_ZERO_MEMORY,
341                   sizeof(SYSTEM_THREAD_TABLE_ENTRY));
342     if (NULL == p)
343     {
344         *puHandle = 0;
345         return(FALSE);
346     }
347
348     LOCK_SYSTEM;
349     p->pEntry = pEntry;
350     p->uThreadParam = uParam;
351     p->hThread = CreateThread(NULL,
352                               0x6000,
353                               SystemThreadEntryPoint,
354                               (VOID *)p,
355                               0,
356                               &(p->uTid));
357     if (NULL == p->hThread)
358     {
359         (void)HeapFree(GetProcessHeap(), 0, p);
360         return(FALSE);
361     }
362     *puHandle = p->uWrapperHandle = p->uTid;
363     InsertHeadList(&g_SystemThreadList, &(p->links));
364     UNLOCK_SYSTEM;
365     return(TRUE);
366 }
367
368
369 FLAG 
370 SystemWaitForThreadToExit(ULONG uThreadHandle)
371 /**
372
373 Routine description:
374
375     Wait for the specified thread to exit.
376
377 Parameters:
378
379     ULONG uThreadHandle
380
381 Return value:
382
383     FLAG
384
385 **/
386 {
387     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
388     
389     if (WAIT_OBJECT_0 != WaitForSingleObject(q->hThread, INFINITE))
390     {
391         ASSERT(FALSE);
392         return(FALSE);
393     }
394     return(TRUE);
395 }
396
397
398 FLAG 
399 SystemGetThreadExitCode(ULONG uThreadHandle, ULONG *puCode)
400 /**
401
402 Routine description:
403
404     Get the specified thread's exit value.
405
406 Parameters:
407
408     ULONG uThreadHandle,
409     ULONG *puCode
410
411 Return value:
412
413     FLAG
414
415 **/
416 {
417     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
418     ULONG uCode;
419     
420     if (FALSE == GetExitCodeThread(q->hThread, &uCode))
421     {
422         return(FALSE);
423     }
424     if (STILL_ACTIVE == uCode)
425     {
426         return(FALSE);
427     }
428     *puCode = uCode;
429     return(TRUE);
430 }
431
432
433 FLAG 
434 SystemDeleteThread(ULONG uThreadHandle)
435 /**
436
437 Routine description:
438
439     Terminate a thread.
440
441 Parameters:
442
443     ULONG uThreadHandle
444
445 Return value:
446
447     FLAG
448
449 **/
450 {
451     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
452     ULONG u;
453     
454     if (NULL != q)
455     {
456         if (FALSE == SystemGetThreadExitCode(uThreadHandle, &u))
457         {
458             SystemWaitForThreadToExit(uThreadHandle);
459         }
460         CloseHandle(q->hThread);
461         LOCK_SYSTEM;
462         RemoveEntryList(&(q->links));
463         HeapFree(GetProcessHeap(), 0, q);
464         UNLOCK_SYSTEM;
465         return(TRUE);
466     }
467     return(FALSE);
468 }
469
470
471 static void
472 _SystemPopulateSystemInformationBuffer(void)
473 /**
474
475 Routine description:
476     
477     Populates global structure SYS_INFORMATION_BUFFER.  This code should
478     be called only once from SystemDependentInitialization.  It should
479     definitely never be called by more than one thread at a time.
480
481 Parameters:
482
483     void
484
485 Return value:
486
487     void
488
489 **/
490 {
491 #ifdef DEBUG
492     static FLAG fInit = FALSE;
493
494     if (TRUE == fInit)
495     {
496         Bug("_SystemPopulateSystemInformationBuffer: This code should "
497             "not be called more than once!\n");
498         ASSERT(FALSE);
499     }
500     fInit = TRUE;
501 #endif
502
503     //
504     // Make some calls to populate the global buffer
505     //
506     GetSystemInfo(&(g_SystemInfoBuffer.si));
507     
508     // 
509     // Note: This API is not present on Win9x
510     //
511     g_SystemInfoBuffer.vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
512     if (FALSE == GetVersionEx((OSVERSIONINFO *)&(g_SystemInfoBuffer.vi)))
513     {
514         Bug("_SystemPopulateSystemInformationBuffer: GetVersionEx "
515             "call failed, error=%u.\n", GetLastError());
516         ASSERT(FALSE);
517     }
518
519     GlobalMemoryStatus(&(g_SystemInfoBuffer.ms));
520     
521     g_SystemInfoBuffer.fPopulated = TRUE;
522 }
523
524
525 static FLAG 
526 _SystemEnablePrivilege(TCHAR *szPrivilegeName,
527                        FLAG fEnable)
528 /**
529
530 Routine description:
531
532     This code is called by SystemDependentInitialization to add some
533     privileges to our process' security token.
534
535 Parameters:
536
537     TCHAR *szPrivilegeName,
538     FLAG fEnable
539
540 Return value:
541
542     FLAG
543
544 **/
545 {
546     FLAG fMyRetVal = FALSE;                   // our return value
547     HANDLE hToken = INVALID_HANDLE_VALUE;     // handle to process token
548     PTOKEN_PRIVILEGES pNewPrivileges;         // privs to enable/disable
549     LUID Luid;                                // priv as a LUID
550     BYTE buf[sizeof(TOKEN_PRIVILEGES)+
551             ((1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES))];
552
553     pNewPrivileges = (PTOKEN_PRIVILEGES)buf;
554     
555     //
556     // Try to open the thread's security token first.
557     // 
558     if (FALSE == OpenThreadToken(GetCurrentThread(),
559                                  TOKEN_ADJUST_PRIVILEGES,
560                                  FALSE,
561                                  &hToken))
562     {
563         //
564         // Well that failed.  If it is because there is no thread token then
565         // try to open the process' security token.
566         //
567         if (ERROR_NO_TOKEN == GetLastError())
568         {
569             if (FALSE == OpenProcessToken(GetCurrentProcess(),
570                                           TOKEN_ADJUST_PRIVILEGES,
571                                           &hToken))
572             {
573                 //
574                 // Can't open the process token either.  Fail.
575                 // 
576                 goto end;
577             }
578         }
579         else
580         { 
581             //
582             // Failed to open the thread token for some other reason.  Fail.
583             // 
584             goto end;
585         }
586     }
587     
588     //
589     // Convert priv name to an LUID.
590     //
591     if (FALSE == LookupPrivilegeValue(NULL,
592                                       szPrivilegeName,
593                                       &Luid))
594     {
595         goto end;
596     }
597     
598     //
599     // Construct new data struct to enable / disable the privi.
600     //
601     pNewPrivileges->PrivilegeCount = 1;
602     pNewPrivileges->Privileges[0].Luid = Luid;
603     pNewPrivileges->Privileges[0].Attributes = 
604         fEnable ? SE_PRIVILEGE_ENABLED : 0;
605
606     //
607     // Adjust the privileges on the token.
608     //
609     fMyRetVal = AdjustTokenPrivileges(hToken,
610                                       FALSE,
611                                       pNewPrivileges,
612                                       0,
613                                       NULL,
614                                       NULL);
615     if (TRUE == fMyRetVal)
616     {
617         //
618         // This boneheaded API returns TRUE and then expects the
619         // caller to test GetLastError to see if it really worked.
620         // 
621         if (ERROR_SUCCESS != GetLastError())
622         {
623             fMyRetVal = FALSE;
624         }
625     }
626     
627  end:
628     if (INVALID_HANDLE_VALUE != hToken)
629     {
630         CloseHandle(hToken);
631     }
632     return(fMyRetVal);
633 }
634
635
636 void FORCEINLINE 
637 SystemDebugBreakpoint(void)
638 /**
639
640 Routine description:
641
642     A hardcoded breakpoint.
643
644 Parameters:
645
646     void
647
648 Return value:
649
650     void
651
652 **/
653 {
654     DebugBreak();
655 }
656
657 #define SYS_HIGH_PERFORMANCE_TIMER (1)
658 #define SYS_GET_TICK_COUNT         (2)
659 #define SYS_MS_PER_SECOND          (1000)
660
661 double
662 SystemTimeStamp(void)
663 /**
664
665 Routine description:
666
667     Return a timestamp to the caller.  The precision of this timestamp
668     is based on whether the machine supports a high resolution timer.
669     If not, this code rolls back to use GetTickCount().
670
671     This code relies on some initialization code in SystemDependent-
672     Initialization.  Once that code has executed, this code is thread
673     safe.
674
675 Parameters:
676
677     void
678
679 Return value:
680
681     double
682
683 **/
684 {
685     double dRetVal;
686     UINT64 u64;
687
688     switch(g_uTimeStampType)
689     {
690         case SYS_HIGH_PERFORMANCE_TIMER:
691             QueryPerformanceCounter((LARGE_INTEGER *)&u64);
692             dRetVal = u64 * g_dTimeStampFrequency;
693             break;
694         case SYS_GET_TICK_COUNT:
695             dRetVal = GetTickCount() / SYS_MS_PER_SECOND;
696             break;
697         default:
698             dRetVal = 0.0;
699             Bug("SystemTimeStamp: You have to call SystemDependent"
700                 "Initialization before you can call this code.\n");
701             ASSERT(FALSE);
702             break;
703     }
704     return(dRetVal);
705 }
706
707
708 FLAG 
709 SystemDoesFileExist(CHAR *szFilename)
710 /**
711
712 Routine description:
713
714     Determine if a file exists (non-atomically).
715
716 Parameters:
717
718     CHAR *szFilename
719
720 Return value:
721
722     FLAG
723
724 **/
725 {
726     if (INVALID_FILE_ATTRIBUTES == GetFileAttributesA(szFilename))
727     {
728         if (GetLastError() == ERROR_FILE_NOT_FOUND)
729         {
730             return(FALSE);
731         }
732     }
733     return(TRUE);
734 }
735
736
737 static FLAG 
738 _SystemIsAdministrator(void)
739 /**
740
741 Routine description:
742
743     This code is called by SystemDependentInitialization.  Its job is to
744     determine whether this process is running with administrative powers.
745
746 Parameters:
747
748     void
749
750 Return value:
751
752     static FLAG
753
754 **/
755 {
756     BOOL fIsMember = FALSE;                   // our return value
757     SID *pAdminSid = NULL;                    // ptr to admin sid
758     SID_IDENTIFIER_AUTHORITY NtAuthority =    // used to create admin sid
759         SECURITY_NT_AUTHORITY;
760     
761     //
762     // Allocate and initialize a SID for the admin group.
763     // 
764     if (FALSE == AllocateAndInitializeSid(&NtAuthority,
765                                           2,
766                                           SECURITY_BUILTIN_DOMAIN_RID,
767                                           DOMAIN_ALIAS_RID_ADMINS,
768                                           0, 0, 0, 0, 0, 0,
769                                           &pAdminSid)) 
770     {
771         goto end;
772     }
773     
774     //
775     // SID allocation succeeded, check this thread or process token
776     // for membership in the admin group.
777     // 
778     if (FALSE == CheckTokenMembership(NULL,
779                                       pAdminSid,
780                                       &fIsMember))
781     {
782         fIsMember = FALSE;
783     }
784     
785  end:
786     if (NULL != pAdminSid)
787     {
788         FreeSid(pAdminSid);
789     }
790     
791     return(fIsMember);
792 }
793
794
795 static void *
796 _SystemCallVirtualAlloc(ULONG dwSizeBytes)
797 /**
798
799 Routine description:
800
801     Wrapper around VirtualAlloc
802
803 Parameters:
804
805     ULONG dwSizeBytes
806
807 Return value:
808
809     static void
810
811 **/
812 {
813     SIZE_T size = dwSizeBytes;
814     void *pMem = NULL;
815     
816     pMem = VirtualAlloc(NULL,
817                         size,
818                         MEM_RESERVE | MEM_COMMIT, 
819                         PAGE_READWRITE);
820     if (NULL == pMem)
821     {
822         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
823                   NULL, "VirtualAlloc", GetLastError(), size,
824                   __FILE__, __LINE__);
825     }
826     return(pMem);
827 }
828
829 static void 
830 _SystemCallVirtualFree(void *pMem)
831 /**
832
833 Routine description:
834
835     Wrapper around VirtualFree
836
837 Parameters:
838
839     void *pMem
840
841 Return value:
842
843     static void
844
845 **/
846 {
847     BOOL fRetVal = FALSE;
848
849     if (NULL != pMem)
850     {
851         fRetVal = VirtualFree(pMem, 0, MEM_RELEASE);
852         if (FALSE == fRetVal)
853         {
854             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
855                       NULL, "VirtualFree", GetLastError(), pMem,
856                       __FILE__, __LINE__);
857         }
858     }
859 }
860
861 static void *
862 _SystemCallHeapAlloc(ULONG dwSizeBytes)
863 /**
864
865 Routine description:
866
867     Wrapper around HeapAlloc.  Returns a zeroed buffer from the heap.
868     While on the subject of heaps, let me take a moment to extol the
869     value of the Win32 Application Verifier / PageHeap code.  This is
870     code that sanity checks the actions of an app.  It is especially
871     good at finding heap misuse (double frees, reuse after free,
872     buffer overruns, etc...)  It also catches things like
873     CRITICAL_SECTION abuse and HANDLE abuse.  To enable it, use
874     appverif.exe.
875
876 Parameters:
877
878     ULONG dwSizeBytes
879
880 Return value:
881
882     static void
883
884 **/
885 {
886     void *p = HeapAlloc(GetProcessHeap(),
887                         HEAP_ZERO_MEMORY,
888                         dwSizeBytes);
889     if (NULL == p)
890     {
891         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
892                   NULL, "HeapAlloc", GetLastError(), dwSizeBytes,
893                   __FILE__, __LINE__);
894     }
895     return(p);
896 }
897
898 static void 
899 _SystemCallHeapFree(void *pMem)
900 /**
901
902 Routine description:
903
904     Wrapper around HeapFree
905
906 Parameters:
907
908     void *pMem
909
910 Return value:
911
912     static void
913
914 **/
915 {
916     if (FALSE == HeapFree(GetProcessHeap(),
917                           0,
918                           pMem))
919     {
920         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
921                   NULL, "HeapFree", GetLastError(), pMem,
922                   __FILE__, __LINE__);
923     }
924 }
925
926 void 
927 SystemFreeMemory(void *pMem)
928 /**
929
930 Routine description:
931
932     Free memory
933
934 Parameters:
935
936     void *pMem
937
938 Return value:
939
940     static void
941
942 **/
943 {
944     _SystemCallHeapFree(pMem);
945 #ifdef DEBUG
946     ReleaseAllocHashEntry(pMem);
947 #endif
948 }
949
950 void *
951 SystemAllocateMemory(ULONG dwSizeBytes)
952 /**
953
954 Routine description:
955
956     Allocate some memory, either from the heap or from VirtualAlloc
957     depending on the size of the request.  The buffer returned by
958     this call is guaranteed to be zeroed out.  Buffers allocated by
959     this call should be freed via a call to SystemFreeMemory when
960     they are no longer needed.
961
962 Parameters:
963
964     ULONG dwSizeBytes : size of the buffer needed in bytes
965
966 Return value:
967
968     void
969
970 **/
971 {
972     BYTE *p;
973
974     p = _SystemCallHeapAlloc(dwSizeBytes);
975 #ifdef DEBUG
976     MarkAllocHashEntry(p, dwSizeBytes);
977 #endif
978     return(p);
979 }
980
981
982 void *
983 SystemAllocateLockedMemory(ULONG dwSizeBytes)
984 /**
985
986 Routine description:
987
988     Allocate a buffer that is locked in memory (i.e. non-pagable).
989
990 Parameters:
991
992     ULONG dwSizeBytes
993
994 Return value:
995
996     void
997
998 **/
999 {
1000     void *p = _SystemCallVirtualAlloc(dwSizeBytes);
1001
1002     if (NULL != p)
1003     {
1004         if (FALSE == VirtualLock(p, dwSizeBytes))
1005         {
1006             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
1007                       NULL, "VirtualLock", GetLastError(), p,
1008                       __FILE__, __LINE__);
1009         }
1010     }
1011 #ifdef DEBUG
1012     MarkAllocHashEntry(p, dwSizeBytes);
1013 #endif
1014     return(p);
1015 }
1016
1017
1018 FLAG 
1019 SystemMakeMemoryReadOnly(void *pMemory, 
1020                          ULONG dwSizeBytes)
1021 /**
1022
1023 Routine description:
1024
1025 Parameters:
1026
1027     void *pMemory,
1028     ULONG dwSizeBytes
1029
1030 Return value:
1031
1032     FLAG
1033
1034 **/
1035 {
1036     BOOL fRetVal = FALSE;
1037     ULONG dwJunk;
1038     
1039     fRetVal = VirtualProtect(pMemory, 
1040                              dwSizeBytes, 
1041                              PAGE_READONLY, 
1042                              &dwJunk);
1043     if (FALSE == fRetVal)
1044     {
1045         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
1046                   NULL, "VirtualProtect", GetLastError(), pMemory,
1047                   __FILE__, __LINE__);
1048     }
1049     return((FLAG)fRetVal);
1050 }
1051
1052 FLAG 
1053 SystemMakeMemoryNoAccess(void *pMemory, 
1054                          ULONG dwSizeBytes)
1055 /**
1056
1057 Routine description:
1058
1059 Parameters:
1060
1061     void *pMemory,
1062     ULONG dwSizeBytes
1063
1064 Return value:
1065
1066     FLAG
1067
1068 **/
1069 {
1070     BOOL fRetVal = FALSE;
1071     ULONG dwJunk;
1072     
1073     fRetVal = VirtualProtect(pMemory, 
1074                              dwSizeBytes, 
1075                              PAGE_NOACCESS,
1076                              &dwJunk);
1077     if (FALSE == fRetVal)
1078     {
1079         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
1080                   NULL, "VirtualProtect", GetLastError(), pMemory,
1081                   __FILE__, __LINE__);
1082     }
1083     return((FLAG)fRetVal);
1084 }
1085
1086
1087 FLAG 
1088 SystemCopyFile(CHAR *szSource, CHAR *szDest)
1089 /**
1090
1091 Routine description:
1092
1093 Parameters:
1094
1095     CHAR *szSource,
1096     CHAR *szDest
1097
1098 Return value:
1099
1100     FLAG
1101
1102 **/
1103 {
1104     return(CopyFileA(szSource, szDest, TRUE));
1105 }
1106
1107
1108 FLAG 
1109 SystemDeleteFile(CHAR *szFile)
1110 /**
1111
1112 Routine description:
1113
1114 Parameters:
1115
1116     CHAR *szFile
1117
1118 Return value:
1119
1120     FLAG
1121
1122 **/
1123 {
1124     return(DeleteFileA(szFile));
1125 }
1126
1127
1128 FLAG 
1129 SystemMakeMemoryReadWrite(void *pMemory, ULONG dwSizeBytes)
1130 /**
1131
1132 Routine description:
1133
1134 Parameters:
1135
1136     void *pMemory,
1137     ULONG dwSizeBytes
1138
1139 Return value:
1140
1141     FLAG
1142
1143 **/
1144 {
1145     BOOL fRetVal = FALSE;
1146     ULONG dwJunk;
1147     
1148     fRetVal = VirtualProtect(pMemory, 
1149                              dwSizeBytes, 
1150                              PAGE_READWRITE, 
1151                              &dwJunk);
1152     if (FALSE == fRetVal)
1153     {
1154         Bug("SystemMakeMemoryReadWrite: VirtualProtect for buffer at %p "
1155             "(size %u) failed, error=%u.\n", pMemory, dwSizeBytes,
1156             GetLastError());
1157     }
1158     return(fRetVal);
1159 }
1160
1161
1162 UINT64 FASTCALL 
1163 SystemReadTimeStampCounter(void)
1164 /**
1165
1166 Routine description:
1167
1168 Parameters:
1169
1170     void
1171
1172 Return value:
1173
1174     UINT64 FASTCALL
1175
1176 **/
1177 {
1178 #if defined(_X86_)
1179     _asm {
1180         rdtsc
1181     }
1182 #elif defined(_AMD64_)
1183     UINT64 itc;
1184     itc = __rdtsc();
1185     return itc;
1186 #elif defined(_IA64_)
1187     UINT64 itc;
1188     itc = __getReg(CV_IA64_ApITC);
1189     return itc;
1190 #else
1191 #error Unknown architecture
1192 #endif
1193 }
1194
1195 #define MAX_LOCKS (8)
1196 typedef struct _WIN32_LOCK_ENTRY
1197 {
1198     CRITICAL_SECTION lock;
1199     FLAG fInUse;
1200 } WIN32_LOCK_ENTRY;
1201 WIN32_LOCK_ENTRY g_rgLockTable[MAX_LOCKS];
1202
1203 ULONG
1204 SystemCreateLock(void) 
1205 {
1206     ULONG u;
1207
1208     LOCK_SYSTEM;
1209     for (u = 0; u < MAX_LOCKS; u++)
1210     {
1211         if (FALSE == g_rgLockTable[u].fInUse)
1212         {
1213             InitializeCriticalSection(&(g_rgLockTable[u].lock));
1214             g_rgLockTable[u].fInUse = TRUE;
1215             goto end;
1216         }
1217     }
1218     u = (ULONG)-1;                            // no free slot
1219
1220  end:
1221     UNLOCK_SYSTEM;
1222     return(u);
1223 }
1224
1225 FLAG
1226 SystemDeleteLock(ULONG u)
1227 {
1228     LOCK_SYSTEM;
1229     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE)) 
1230     {
1231         DeleteCriticalSection(&(g_rgLockTable[u].lock));
1232         g_rgLockTable[u].fInUse = FALSE;
1233         UNLOCK_SYSTEM;
1234         return(TRUE);
1235     }
1236     UNLOCK_SYSTEM;
1237     return(FALSE);
1238 }
1239
1240 FLAG
1241 SystemBlockingWaitForLock(ULONG u) 
1242 {
1243     CRITICAL_SECTION *p = NULL;
1244     LOCK_SYSTEM;
1245     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE)) 
1246     {
1247         p = &(g_rgLockTable[u].lock);
1248     }
1249     UNLOCK_SYSTEM;
1250     if (p != NULL) 
1251     {
1252         EnterCriticalSection(p);
1253         Trace("lock at %p is obtained.\n", p);
1254         return(TRUE);
1255     }
1256     return(FALSE);
1257 }
1258
1259
1260 FLAG
1261 SystemReleaseLock(ULONG u) 
1262 {
1263     CRITICAL_SECTION *p = NULL;
1264     LOCK_SYSTEM;
1265     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE)) 
1266     {
1267         p = &(g_rgLockTable[u].lock);
1268     }
1269     UNLOCK_SYSTEM;
1270     if (p != NULL) 
1271     {
1272         LeaveCriticalSection(p);
1273         Trace("lock at %p is released.\n", p);
1274         return(TRUE);
1275     }
1276     return(FALSE);
1277 }
1278
1279
1280 #define MAX_SEMS (8)
1281 HANDLE g_rgSemHandles[MAX_SEMS];
1282
1283 ULONG 
1284 SystemCreateSemaphore(ULONG uValue) 
1285 {
1286     ULONG u;
1287     LOCK_SYSTEM;
1288     for (u = 0; u < MAX_SEMS; u++) 
1289     {
1290         if (g_rgSemHandles[u] == (HANDLE)NULL) 
1291         {
1292             g_rgSemHandles[u] = CreateSemaphore(NULL, uValue, uValue, NULL);
1293             if (NULL == g_rgSemHandles[u]) 
1294             {
1295                 u = (ULONG)-1;
1296             }
1297             goto end;
1298         }
1299     }
1300     u = (ULONG)-1;
1301
1302  end:
1303     UNLOCK_SYSTEM;
1304     return(u);
1305 }
1306
1307 FLAG
1308 SystemDeleteSemaphore(ULONG u) 
1309 {
1310     LOCK_SYSTEM;
1311     if ((u < MAX_SEMS) && (g_rgSemHandles[u] != (HANDLE)NULL)) 
1312     {
1313         (void)CloseHandle(g_rgSemHandles[u]);
1314         g_rgSemHandles[u] = (HANDLE)NULL;
1315         UNLOCK_SYSTEM;
1316         return(TRUE);
1317     }
1318     UNLOCK_SYSTEM;
1319     return(FALSE);
1320 }
1321
1322 void
1323 SystemReleaseSemaphoreResource(ULONG u) 
1324 {
1325     LOCK_SYSTEM;
1326     if ((u < MAX_SEMS) && (g_rgSemHandles[u] != (HANDLE)NULL)) 
1327     {
1328         ReleaseSemaphore(g_rgSemHandles[u], +1, NULL);
1329     }
1330     UNLOCK_SYSTEM;
1331 }
1332
1333 void
1334 SystemObtainSemaphoreResource(ULONG u) 
1335 {
1336     HANDLE h;
1337     LOCK_SYSTEM;
1338     if ((u < MAX_SEMS) && (g_rgSemHandles[u] != (HANDLE)NULL)) 
1339     {
1340         h = g_rgSemHandles[u];
1341         UNLOCK_SYSTEM;
1342         (void)WaitForSingleObject(h, INFINITE);
1343         return;
1344     }
1345     UNLOCK_SYSTEM;
1346 }
1347
1348       
1349
1350 FLAG 
1351 SystemDependentInitialization(void)
1352 /**
1353
1354 Routine description:
1355
1356     This code is called to initialize operating system dependent code.
1357     It is unsynchronized.  It should only ever be called once.  It
1358     should definitely never be called by two threads at once!
1359
1360 Parameters:
1361
1362     void
1363
1364 Return value:
1365
1366     FLAG : TRUE on success, FALSE otherwise
1367
1368 **/
1369 {
1370     UINT64 u64;
1371 #ifdef DEBUG
1372     static FLAG fInit = FALSE;
1373
1374     if (TRUE == fInit)
1375     {
1376         Bug("SystemDependentInitialization code called more than once!\n");
1377         ASSERT(FALSE);
1378         return(FALSE);
1379     }
1380     fInit = TRUE;
1381 #endif
1382
1383     //
1384     // Initialize the system dependent lock
1385     //
1386     __try
1387     {
1388         InitializeCriticalSection(&g_SystemLock);
1389     }
1390     __except(EXCEPTION_EXECUTE_HANDLER)
1391     {
1392         Bug("SystemDependentInitialization: InitializeCriticalSection "
1393             "raised an exception, bailing out.\n");
1394         return(FALSE);
1395     }
1396
1397     //
1398     // Clear a pool of handles
1399     //
1400     memset(g_rgLockTable, 0, sizeof(g_rgLockTable));
1401     memset(g_rgSemHandles, 0, sizeof(g_rgSemHandles));
1402
1403     //
1404     // Populate global system info buffer
1405     //
1406     _SystemPopulateSystemInformationBuffer();
1407
1408     //
1409     // Enable some privileges in this process' security token
1410     //
1411     if (FALSE == _SystemEnablePrivilege(SE_INC_BASE_PRIORITY_NAME, TRUE))
1412     {
1413         Trace("NOTICE: Can't enable SE_INC_BASE_PRIORITY_NAME privilege, "
1414               "error=%u\n", GetLastError());
1415     }
1416     if (FALSE == _SystemEnablePrivilege(SE_LOCK_MEMORY_NAME, TRUE))
1417     {
1418         Trace("NOTICE: Can't enable SE_LOCK_MEMORY_NAME privilege, "
1419               "error=%u\n", GetLastError());
1420     }
1421     
1422     //
1423     // Don't let the system hibernate/suspend while the chess program
1424     // is running.
1425     // 
1426     (void)SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
1427
1428     //
1429     // Determine the precision of our SystemTimeStamp() code
1430     //
1431     ASSERT(g_uTimeStampType == 0);
1432     if (FALSE != QueryPerformanceFrequency((LARGE_INTEGER *)&u64))
1433     {
1434         g_dTimeStampFrequency = 1.0 / u64;
1435         g_uTimeStampType = SYS_HIGH_PERFORMANCE_TIMER;
1436     }
1437     else
1438     {
1439         g_dTimeStampFrequency = 1.0 / 1000.0;
1440         g_uTimeStampType = SYS_GET_TICK_COUNT;
1441     }
1442     ASSERT(g_dTimeStampFrequency > 0.0);
1443
1444     g_uMaxHeapAllocationSize = 0x1000;
1445     InitializeListHead(&g_SystemThreadList);
1446
1447     return(TRUE);
1448 }