Update codebase to remove clang warnings (and a couple of legit errors
[typhoon.git] / src / unix.c
1 /**
2
3 Copyright (c) Scott Gasch
4
5 Module Name:
6
7     unix.c
8
9 Abstract:
10
11     FreeBSD/Linux/OSX system dependent code.
12
13 Author:
14
15     Scott Gasch ([email protected]) 8 Apr 2004
16
17 Revision History:
18
19     $Id: unix.c 200 2006-07-05 20:05:07Z scott $
20
21 **/
22
23 #include "chess.h"
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28 #include <sys/mman.h>
29 #include <sys/select.h>
30 #include <sys/ipc.h>
31 #include <sys/sem.h>
32 #include <pthread.h>
33 #include <signal.h>
34 #include <errno.h>
35
36 #define SYS_MAX_HEAP_ALLOC_SIZE_BYTES 0xfff
37 #define HEAP 0x48656170
38 #define MMAP 0x4d6d6170
39
40 pthread_mutex_t g_SystemLock;
41 #define LOCK_SYSTEM     pthread_mutex_lock(&g_SystemLock)
42 #define UNLOCK_SYSTEM   pthread_mutex_unlock(&g_SystemLock)
43
44 #ifdef DEBUG
45 ULONG g_uTotalAlloced = 0;
46
47 #define ALLOC_HASH_SIZE 0x4000
48
49 typedef struct _ALLOC_RECORD
50 {
51     void *p;
52     ULONG uSize;
53 } ALLOC_RECORD;
54 ALLOC_RECORD g_AllocHash[ALLOC_HASH_SIZE];
55
56 #define PTR_TO_ALLOC_HASH(x) ((((ULONG)(x)) >> 3) & (ALLOC_HASH_SIZE - 1))
57
58 ULONG
59 GetHeapMemoryUsage(void)
60 {
61     Trace("There are now %u bytes outstanding.\n", g_uTotalAlloced);
62     return(g_uTotalAlloced);
63 }
64
65 static void 
66 ReleaseAllocHashEntry(void *p)
67 {
68     ULONG u = PTR_TO_ALLOC_HASH(p);
69     ULONG v = u;
70
71     LOCK_SYSTEM;
72     while(g_AllocHash[u].p != p)
73     {
74         u++;
75         u &= (ALLOC_HASH_SIZE - 1);
76         if (v == u) return;
77     }
78     g_AllocHash[u].p = NULL;
79     g_uTotalAlloced -= g_AllocHash[u].uSize;
80     UNLOCK_SYSTEM;
81
82 //    Trace("Freed %u bytes at %p.\n", g_AllocHash[u].uSize, p);
83 }
84
85 static void
86 MarkAllocHashEntry(void *p, ULONG uSize)
87 {
88     ULONG u = PTR_TO_ALLOC_HASH(p);
89
90     if (uSize > (1024 * 1024 * 30)) return;
91
92     LOCK_SYSTEM;
93     while(g_AllocHash[u].p != NULL)
94     {
95         u++;
96         u &= (ALLOC_HASH_SIZE - 1);
97     }
98     g_AllocHash[u].p = p;
99     g_AllocHash[u].uSize = uSize;
100     g_uTotalAlloced += uSize;
101     UNLOCK_SYSTEM;
102
103 //    Trace("Alloc %u bytes at %p.\n", g_AllocHash[u].uSize, p);
104 }
105 #endif // DEBUG
106
107 //
108 // Thread table
109 //
110 typedef struct _SYSTEM_THREAD_TABLE_ENTRY
111 {
112     DLIST_ENTRY links;
113     ULONG uWrapperHandle;
114     ULONG uTid;
115     ULONG uThreadParam;
116     pthread_t thread;
117     THREAD_ENTRYPOINT *pEntry;
118     ULONG uExitCode;
119 }
120 SYSTEM_THREAD_TABLE_ENTRY;
121 DLIST_ENTRY g_SystemThreadList;
122 ULONG g_uNextThreadHandle = 6000;
123
124 CHAR *
125 SystemGetTimeString(void)
126 /**
127
128 Routine description:
129
130     Get the current time string from the OS.  Not thread safe.
131
132 Parameters:
133
134     void
135
136 Return value:
137
138     CHAR
139
140 **/
141 {
142     static CHAR buf[32];
143     time_t t = time(NULL);
144     struct tm *p;
145
146     p = localtime(&t);
147     snprintf(buf, ARRAY_LENGTH(buf), 
148              "%u:%02u:%02u", p->tm_hour, p->tm_min, p->tm_sec);
149     return(buf);
150 }
151
152 CHAR *
153 SystemGetDateString(void)
154 /**
155
156 Routine description:
157
158     Get the current date string from the OS.  Not thread safe.
159
160 Parameters:
161
162     void
163
164 Return value:
165
166     CHAR
167
168 **/
169 {
170     static CHAR buf[32];
171     time_t t = time(NULL);
172     struct tm *p;
173
174     p = localtime(&t);
175     snprintf(buf, ARRAY_LENGTH(buf), 
176              "%u.%02u.%02u", p->tm_year + 1900, p->tm_mon + 1, p->tm_mday);
177     return(buf);
178 }
179
180 //
181 // Thread code
182 //
183
184 static SYSTEM_THREAD_TABLE_ENTRY *
185 _SystemGetThreadTableEntry(ULONG uThreadHandle)
186 /**
187
188 Routine description:
189
190     Support routine for thread functionality wrapper.  Given a
191     uThreadHandle look up its entry in the global table.
192
193 Parameters:
194
195     ULONG uThreadHandle
196
197 Return value:
198
199     SYSTEM_THREAD_TABLE_ENTRY *
200
201 **/
202 {
203     DLIST_ENTRY *p;
204     SYSTEM_THREAD_TABLE_ENTRY *q;
205     
206     LOCK_SYSTEM;
207     p = g_SystemThreadList.pFlink;
208     while(p != &g_SystemThreadList)
209     {
210         q = CONTAINING_STRUCT(p, SYSTEM_THREAD_TABLE_ENTRY, links);
211         if (q->uWrapperHandle == uThreadHandle)
212         {
213             goto end;
214         }
215         p = p->pFlink;
216     }
217     q = NULL;
218  end:
219     UNLOCK_SYSTEM;
220     return(q);
221 }
222
223 void *
224 SystemThreadEntryPoint(void *pParam)
225 /**
226
227 Routine description:
228
229     The first code that any newly created thread executes.
230
231 Parameters:
232
233     void *pParam
234
235 Return value:
236
237     void
238
239 **/
240 {
241     SYSTEM_THREAD_TABLE_ENTRY *p = (SYSTEM_THREAD_TABLE_ENTRY *)pParam;
242     ULONG uParam;
243     int i;
244     
245     LOCK_SYSTEM;
246     UNLOCK_SYSTEM;
247
248     uParam = p->uThreadParam;
249     i = (int)(*(p->pEntry))(uParam);          // call thread's user-supplied entry
250     return((void *)i);
251 }
252
253 FLAG 
254 SystemCreateThread(THREAD_ENTRYPOINT *pEntry, ULONG uParam, ULONG *puHandle)
255 /**
256
257 Routine description:
258
259     Wraps the OS/Library dependent thread creation call.
260
261 Parameters:
262
263     THREAD_ENTRYPOINT *pEntry : where should the new thread start?
264     ULONG uParam : parameter to pass to the new thread
265     ULONG *puHandle : "handle" to the new thread
266
267 Return value:
268
269     FLAG
270
271 **/
272 {
273     SYSTEM_THREAD_TABLE_ENTRY *p;
274
275     p = malloc(sizeof(SYSTEM_THREAD_TABLE_ENTRY));
276     if (NULL == p)
277     {
278         *puHandle = 0;
279         return(FALSE);
280     }
281     
282     LOCK_SYSTEM;
283     p->pEntry = pEntry;
284     p->uThreadParam = uParam;
285     if (0 != pthread_create(&(p->thread),
286                             NULL, 
287                             SystemThreadEntryPoint, 
288                             p))
289     {
290         free(p);
291         return(FALSE);
292     }
293     *puHandle = p->uWrapperHandle = g_uNextThreadHandle;
294     g_uNextThreadHandle++;
295     InsertHeadList(&g_SystemThreadList, &(p->links));
296     UNLOCK_SYSTEM;
297     return(TRUE);
298 }
299
300
301 FLAG 
302 SystemWaitForThreadToExit(ULONG uThreadHandle)
303 /**
304
305 Routine description:
306
307     Blocks until the thread whose handle is provieded exits.
308
309 Parameters:
310
311     ULONG uThreadHandle
312
313 Return value:
314
315     FLAG
316
317 **/
318 {
319     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
320     
321     pthread_join(q->thread, NULL);
322     return(TRUE);
323 }
324
325
326 FLAG 
327 SystemGetThreadExitCode(ULONG uThreadHandle, ULONG *puCode)
328 /**
329
330 Routine description:
331
332     Get the exit value of an already-exited thread.
333
334 Parameters:
335
336     ULONG uThreadHandle,
337     ULONG *puCode
338
339 Return value:
340
341     FLAG
342
343 **/
344 {
345     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
346     void *p;
347
348     pthread_join(q->thread, &p);
349     *puCode = ((ULONG)p);
350     return(TRUE);
351 }
352
353
354 FLAG 
355 SystemDeleteThread(ULONG uThreadHandle)
356 /**
357
358 Routine description:
359
360     Kill a thread.
361
362 Parameters:
363
364     ULONG uThreadHandle
365
366 Return value:
367
368     FLAG
369
370 **/
371 {
372     SYSTEM_THREAD_TABLE_ENTRY *q = _SystemGetThreadTableEntry(uThreadHandle);
373     
374     if (NULL != q)
375     {
376         pthread_kill(q->thread, SIGKILL);
377         LOCK_SYSTEM;
378         RemoveEntryList(&(q->links));
379         free(q);
380         UNLOCK_SYSTEM;
381         return(TRUE);
382     }
383     return(FALSE);
384 }
385
386
387
388 void FORCEINLINE 
389 SystemDebugBreakpoint(void)
390 /**
391
392 Routine description:
393
394     A hardcoded breakpoint.
395
396 Parameters:
397
398     void
399
400 Return value:
401
402     void
403
404 **/
405 {
406     __asm__("int3\n");
407 }
408
409 UINT64 FASTCALL 
410 SystemReadTimeStampCounter(void)
411 /**
412
413 Routine description:
414
415     Read the processor's timestamp counter.
416
417 Parameters:
418
419     void
420
421 Return value:
422
423     UINT64 FASTCALL
424
425 **/
426 {
427     __asm__("rdtsc;"
428         :
429         :
430         : "%eax", "%edx");
431 }
432
433
434 double INLINE
435 SystemTimeStamp(void)
436 /**
437
438 Routine description:
439
440     Return a timestamp to the caller.
441
442 Parameters:
443
444     void
445
446 Return value:
447
448     double
449
450 **/
451 {
452     struct timeval tv;
453
454     //
455     // Number of seconds and microseconds since the Epoch.
456     //
457     if (0 != gettimeofday(&tv, NULL))
458     {
459         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
460                   NULL, "gettimeofday", (void *)errno, NULL,
461                   __FILE__, __LINE__);
462     }
463     return((double)tv.tv_sec + (double)tv.tv_usec * 1.0e-6);
464 }
465
466
467 FLAG
468 SystemDoesFileExist(CHAR *szFilename)
469 /**
470
471 Routine description:
472
473     Determine if a file exists (non-atomically).
474
475 Parameters:
476
477     CHAR *szFilename
478
479 Return value:
480
481     FLAG
482
483 **/
484 {
485     struct stat sb;
486     int i = stat(szFilename, &sb);
487
488     if ((i == -1) && (errno == ENOENT)) return(FALSE);
489     return(TRUE);
490 }
491
492
493 static FLAG 
494 _SystemIsRoot(void)
495 /**
496
497 Routine description:
498
499     This code is called by SystemDependentInitialization.  Its job is to
500     determine whether this process is running with administrative powers.
501
502 Parameters:
503
504     void
505
506 Return value:
507
508     static FLAG
509
510 **/
511 {
512     if (0 == geteuid())
513     {
514         return(TRUE);
515     }
516     return(FALSE);
517 }
518
519
520 void FORCEINLINE 
521 SystemDeferExecution(ULONG dwMs)
522 /**
523
524 Routine description:
525
526     Sleep for a few ms.
527
528 Parameters:
529
530     ULONG dwMs
531
532 Return value:
533
534     void FORCEINLINE
535
536 **/
537 {
538     struct timeval t = { 0, dwMs * 1000 };
539     if (select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &t) < 0) 
540     {
541         if (usleep(dwMs * 1000) < 0) 
542         {
543             Bug("SystemDeferExecution: I have insomnia...\n");
544         }
545     }
546 }
547
548
549 static void *
550 _SystemCallMmap(ULONG dwSizeBytes)
551 /**
552
553 Routine description:
554
555     Wrapper around mmap.
556
557 Parameters:
558
559     ULONG dwSizeBytes
560
561 Return value:
562
563     static void
564
565 **/
566 {
567     void *pMem = mmap(0,
568                       (size_t)dwSizeBytes,
569                       PROT_READ | PROT_WRITE,
570                       MAP_ANON,
571                       -1,
572                       0);
573     if (MAP_FAILED == pMem)
574     {
575         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
576                   NULL, "mmap", (void *)errno, (void *)dwSizeBytes,
577                   __FILE__, __LINE__);
578     }
579     (void)madvise(pMem, dwSizeBytes, MADV_RANDOM | MADV_WILLNEED);
580     return(pMem);
581 }
582
583
584 static void 
585 _SystemCallMunmap(void *pMem)
586 /**
587
588 Routine description:
589
590     Wrapper around munmap
591
592 Parameters:
593
594     void *pMem
595
596 Return value:
597
598     static void
599
600 **/
601 {
602     if (0 != munmap(pMem, (size_t)-1))
603     {
604         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
605                   NULL, "munmap", (void *)errno, pMem,
606                   __FILE__, __LINE__);
607     }
608 }
609
610
611 static void *_SystemCallMalloc(ULONG dwSizeBytes)
612 /**
613
614 Routine description:
615
616     Wrapper around malloc.
617
618 Parameters:
619
620     ULONG dwSizeBytes
621
622 Return value:
623
624     static void
625
626 **/
627 {
628     void *p = malloc(dwSizeBytes);
629     if (NULL == p)
630     {
631         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
632                   NULL, "malloc", (void *)errno, (void *)dwSizeBytes,
633                   __FILE__, __LINE__);
634     }
635     memset(p, 0, dwSizeBytes);
636     return(p);
637 }
638
639
640 static void 
641 _SystemCallFree(void *p)
642 /**
643
644 Routine description:
645
646     Wrapper around free.
647
648 Parameters:
649
650     void *p
651
652 Return value:
653
654     static void
655
656 **/
657 {
658     free(p);
659 }
660
661 char *
662 SystemStrDup(char *p)
663 /**
664
665 Routine description:
666
667     Implements strdup functionality.
668
669 Parameters:
670
671     char *p
672
673 Return value:
674
675     char
676
677 **/
678 {
679     char *q = SystemAllocateMemory(strlen(p) + 1);
680     strcpy(q, p);
681     return(q);
682 }
683
684 void *
685 SystemAllocateMemory(ULONG dwSizeBytes)
686 /**
687
688 Routine description:
689  
690     Allocate some memory.
691
692 Parameters:
693
694     ULONG dwSizeBytes
695
696 Return value:
697
698     void
699
700 **/
701 {
702     DWORD *p;
703
704     if (0) // (dwSizeBytes > SYS_MAX_HEAP_ALLOC_SIZE_BYTES)
705     {
706         p = _SystemCallMmap(dwSizeBytes + sizeof(DWORD));
707         if (NULL == p)
708         {
709             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
710                       NULL, "mmap", (void *)errno, NULL,
711                       __FILE__, __LINE__);
712         }
713         *p = MMAP;
714         p += 1;
715     }
716     else
717     {
718         p = _SystemCallMalloc(dwSizeBytes + sizeof(DWORD));
719         if (NULL == p)
720         {
721             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
722                       NULL, "malloc", (void *)errno, NULL,
723                       __FILE__, __LINE__);
724         }
725         *p = HEAP;
726         p += 1;
727     }
728 #ifdef DEBUG
729     MarkAllocHashEntry(p, dwSizeBytes);
730 #endif
731     ASSERT(NULL != p);
732     return(p);
733 }
734
735 void 
736 SystemFreeMemory(void *pMemory)
737 /**
738
739 Routine description:
740
741     Free an allocation previously allocated by SystemAllocMemory.
742
743 Parameters:
744
745     void *pMemory
746
747 Return value:
748
749     void
750
751 **/
752 {
753     DWORD *p = pMemory;
754     
755     p -= 1;
756 #ifdef DEBUG
757     ReleaseAllocHashEntry(pMemory);
758 #endif
759     if (*p == HEAP)
760     {
761         _SystemCallFree(p);
762     }
763     else if (*p == MMAP)
764     {
765         _SystemCallMunmap(p);
766     }
767 #ifdef DEBUG
768     else
769     {
770         UtilPanic(SHOULD_NOT_GET_HERE,
771                   NULL, NULL, NULL, NULL,
772                   __FILE__, __LINE__);
773     }
774 #endif
775 }
776
777
778 void *
779 SystemAllocateLockedMemory(ULONG dwSizeBytes)
780 /**
781
782 Routine description:
783
784     Allocate non-pagable memory (if possible).
785
786 Parameters:
787
788     ULONG dwSizeBytes
789
790 Return value:
791
792     void
793
794 **/
795 {
796     void *p = SystemAllocateMemory(dwSizeBytes);
797     if (NULL != p)
798     {
799         if (0 != mlock(p, dwSizeBytes))
800         {
801             //
802             // Note: don't panic the program over this... do dump a 
803             // warning though as it should not happen.
804             //
805             Bug("WARNING: mlock for buffer at 0x%p (%u bytes) failed, "
806                 "errno=%d\n\n", p, dwSizeBytes, errno);
807         }
808     }
809     return(p);
810 }
811
812
813 FLAG 
814 SystemMakeMemoryReadOnly(void *pMemory, 
815                          ULONG dwSizeBytes)
816 /**
817
818 Routine description:
819
820     Make some memory region read-only (if possible).
821
822 Parameters:
823
824     void *pMemory,
825     ULONG dwSizeBytes
826
827 Return value:
828
829     FLAG
830
831 **/
832 {
833     if (0 != mprotect(pMemory, dwSizeBytes, PROT_READ))
834     {
835         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
836                   NULL, "mprotect", (void *)errno, (void *)PROT_READ,
837                   __FILE__, __LINE__);
838     }
839     return(TRUE);
840 }
841
842
843
844 FLAG 
845 SystemMakeMemoryReadWrite(void *pMemory, ULONG dwSizeBytes)
846 /**
847
848 Routine description:
849
850     Make a region of memory read/write.
851
852 Parameters:
853
854     void *pMemory,
855     ULONG dwSizeBytes
856
857 Return value:
858
859     FLAG
860
861 **/
862 {
863     if (0 != mprotect(pMemory, dwSizeBytes, PROT_READ | PROT_WRITE))
864     {
865         UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
866                   NULL, 
867                   "mprotect", 
868                   (void *)errno,
869                   (void *)(PROT_READ | PROT_WRITE),
870                   __FILE__, __LINE__);
871     }
872     return(TRUE);
873 }
874
875
876
877 FLAG 
878 SystemCopyFile(CHAR *szSource, CHAR *szDest)
879 /**
880
881 Routine description:
882
883     Make a copy of a file.
884
885 Parameters:
886
887     CHAR *szSource,
888     CHAR *szDest
889
890 Return value:
891
892     FLAG
893
894 **/
895 {
896     CHAR *buf = NULL;
897     CHAR *x = "/bin/cp -f ";
898     ULONG uLen = strlen(szSource) + strlen(szDest) + strlen(x) + 2;
899
900     buf = SystemAllocateMemory(uLen);
901     snprintf(buf, uLen, 
902              "%s%s %s", x, szSource, szDest);
903     if (0 == system(buf))
904     {
905         SystemFreeMemory(buf);
906         return(TRUE);
907     }
908     SystemFreeMemory(buf);
909     return(FALSE);
910 }
911
912
913 FLAG 
914 SystemDeleteFile(CHAR *szFile)
915 /**
916
917 Routine description:
918
919     Delete a file.
920
921 Parameters:
922
923     CHAR *szFile
924
925 Return value:
926
927     FLAG
928
929 **/
930 {
931     if (0 == unlink(szFile))
932     {
933         return(TRUE);
934     }
935     return(FALSE);
936 }
937
938
939 #define MAX_LOCKS (8)
940 typedef struct _UNIX_LOCK_ENTRY
941 {
942     pthread_mutex_t lock;
943     FLAG fInUse;
944 } UNIX_LOCK_ENTRY;
945 UNIX_LOCK_ENTRY g_rgLockTable[MAX_LOCKS];
946
947 ULONG
948 SystemCreateLock(void) 
949 {
950     ULONG u;
951
952     LOCK_SYSTEM;
953     for (u = 0; u < MAX_LOCKS; u++)
954     {
955         if (FALSE == g_rgLockTable[u].fInUse)
956         {
957             pthread_mutex_init(&(g_rgLockTable[u].lock), NULL);
958             g_rgLockTable[u].fInUse = TRUE;
959             goto end;
960         }
961     }
962     u = (ULONG)-1;                            // no free slot
963
964  end:
965     UNLOCK_SYSTEM;
966     return(u);
967 }
968
969 FLAG
970 SystemDeleteLock(ULONG u)
971 {
972     LOCK_SYSTEM;
973     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE))
974     {
975         pthread_mutex_destroy(&(g_rgLockTable[u].lock));
976         g_rgLockTable[u].fInUse = FALSE;
977         UNLOCK_SYSTEM;
978         return(TRUE);
979     }
980     UNLOCK_SYSTEM;
981     return(FALSE);
982 }
983
984 FLAG
985 SystemBlockingWaitForLock(ULONG u) 
986 {
987     pthread_mutex_t *p = NULL;
988     LOCK_SYSTEM;
989     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE)) 
990     {
991         p = &(g_rgLockTable[u].lock);
992     }
993     UNLOCK_SYSTEM;
994     if (p != NULL)
995     {
996         pthread_mutex_lock(p);
997         return(TRUE);
998     }
999     return(FALSE);
1000 }
1001
1002
1003 FLAG
1004 SystemReleaseLock(ULONG u) 
1005 {
1006     pthread_mutex_t *p = NULL;
1007     LOCK_SYSTEM;
1008     if ((u < MAX_LOCKS) && (g_rgLockTable[u].fInUse == TRUE)) 
1009     {
1010         p = &(g_rgLockTable[u].lock);
1011     }
1012     UNLOCK_SYSTEM;
1013     if (p != NULL) 
1014     {
1015         pthread_mutex_unlock(p);
1016         return(TRUE);
1017     }
1018     return(FALSE);
1019 }
1020
1021
1022 #define MAX_SEM (8)
1023 int g_rgSemaphores[MAX_SEM];
1024 #ifdef DEBUG
1025 ULONG g_rgSemValues[MAX_SEM];
1026 #endif
1027
1028 ULONG
1029 SystemCreateSemaphore(ULONG uValue) 
1030 {
1031     ULONG u;
1032     union semun {
1033             int val;
1034             struct semid_ds *buf;
1035             unsigned short  *array;
1036     } value;
1037
1038     if (uValue > MAX_USHORT) return((ULONG)-1);
1039     LOCK_SYSTEM;
1040     for (u = 0; u < MAX_SEM; u++) 
1041     {
1042         if (g_rgSemaphores[u] < 0) 
1043         {
1044             g_rgSemaphores[u] = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
1045             if (g_rgSemaphores[u] < 0) 
1046             {
1047                 u = (ULONG)-1;
1048                 goto end;
1049             }
1050             value.val = uValue;
1051             if (semctl(g_rgSemaphores[u], 0, SETVAL, value) < 0) 
1052             {
1053                 (void)SystemDeleteSemaphore(u);
1054                 u = (ULONG)-1;
1055                 goto end;
1056             }
1057 #ifdef DEBUG
1058             g_rgSemValues[u] = uValue;
1059             Trace("Semaphore #%u created, initial value is %u\n", 
1060                   u, uValue);
1061 #endif
1062             goto end;
1063         }
1064     }
1065     u = (ULONG)-1;
1066  end:
1067     UNLOCK_SYSTEM;
1068     return(u);
1069 }
1070
1071 FLAG 
1072 SystemDeleteSemaphore(ULONG u) {
1073     union semun {
1074             int val;
1075             struct semid_ds *buf;
1076             unsigned short  *array;
1077     } value;
1078
1079     LOCK_SYSTEM;
1080     if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0)) 
1081     {
1082         if (semctl(g_rgSemaphores[u], 0, IPC_RMID, value) < 0) 
1083         {
1084             return(FALSE);
1085         }
1086         g_rgSemaphores[u] = -1;
1087     }
1088     UNLOCK_SYSTEM;
1089     return(TRUE);
1090 }
1091
1092 void
1093 SystemReleaseSemaphoreResource(ULONG u) 
1094 {
1095     struct sembuf operation;
1096
1097     LOCK_SYSTEM;
1098     if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0)) 
1099     {
1100         operation.sem_num = u;
1101         operation.sem_op = +1;
1102         operation.sem_flg = 0;
1103         if (semop(g_rgSemaphores[u], &operation, 1) < 0) 
1104         {
1105             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
1106                       NULL, "semop", (void *)errno, (void *)0,
1107                       __FILE__, __LINE__);
1108         }
1109 #ifdef DEBUG
1110         g_rgSemValues[u] += 1;
1111         Trace("Semaphore #%u value incremented to %u\n", u, 
1112               g_rgSemValues[u]);
1113 #endif
1114     }
1115     UNLOCK_SYSTEM;
1116 }
1117
1118 void
1119 SystemObtainSemaphoreResource(ULONG u) 
1120 {
1121     struct sembuf operation;
1122
1123     LOCK_SYSTEM;
1124     if ((u < MAX_SEM) && (g_rgSemaphores[u] >= 0))
1125     {
1126         operation.sem_num = u;
1127         operation.sem_op = -1;
1128         operation.sem_flg = 0;
1129         UNLOCK_SYSTEM;
1130         if (semop(g_rgSemaphores[u], &operation, 1) < 0) 
1131         {
1132             UtilPanic(UNEXPECTED_SYSTEM_CALL_FAILURE,
1133                       NULL, "semop", (void *)errno, (void *)1,
1134                       __FILE__, __LINE__);
1135         }
1136 #ifdef DEBUG
1137         if (g_rgSemValues[u] > 0) 
1138         {
1139             g_rgSemValues[u] -= 1;
1140             Trace("Semaphore #%u value decremented to %u\n", u, 
1141                   g_rgSemValues[u]);
1142         }
1143 #endif
1144         return;
1145     }
1146     UNLOCK_SYSTEM;
1147 }
1148
1149
1150 FLAG
1151 SystemDependentInitialization(void)
1152 /**
1153
1154 Routine description:
1155
1156     This code is called to initialize operating system dependent code.
1157     It is unsynchronized.  It should only ever be called once.  It
1158     should definitely never be called by two threads at once!
1159
1160 Parameters:
1161
1162     void
1163
1164 Return value:
1165
1166     FLAG : TRUE on success, FALSE otherwise
1167
1168 **/
1169 {
1170     ULONG u;
1171 #ifdef DEBUG
1172     static FLAG fInit = FALSE;
1173
1174     if (TRUE == fInit)
1175     {
1176         Bug("SystemDependentInitialization code called more than once!\n");
1177         ASSERT(FALSE);
1178         return(FALSE);
1179     }
1180     fInit = TRUE;
1181
1182     memset(g_AllocHash, 0, sizeof(g_AllocHash));
1183 #endif
1184     for (u = 0; u < MAX_SEM; u++) 
1185     {
1186         g_rgSemaphores[u] = -1;
1187     }
1188     InitializeListHead(&g_SystemThreadList);
1189     pthread_mutex_init(&g_SystemLock, NULL);
1190     return(TRUE);
1191 }