1 /**
2  * Operating system specific routines.
3  *
4  * Placed here to avoid cluttering
5  * up code with OS files.
6  *
7  * Compiler implementation of the
8  * $(LINK2 https://www.dlang.org, D programming language).
9  *
10  * Copyright:   Copyright (C) 1994-1998 by Symantec
11  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
12  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
13  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/os.d, backend/os.d)
15  */
16 
17 module dmd.backend.os;
18 
19 import core.stdc.stdio;
20 import core.stdc.time;
21 import core.stdc.stdlib;
22 import core.stdc.string;
23 
24 version (Posix)
25 {
26     import core.stdc.errno;
27     import core.sys.posix.fcntl;
28     import core.sys.posix.pthread;
29     import core.sys.posix.sys.stat;
30     import core.sys.posix.sys.types;
31     import core.sys.posix.unistd;
32     //#define GetLastError() errno
33 }
34 else version (Windows)
35 {
36     import core.sys.windows.stat;
37     import core.sys.windows.winbase;
38     import core.sys.windows.windef;
39 }
40 
41 version (CRuntime_Microsoft)
42     enum NEEDS_WIN32_NON_MS = false;
43 else version (Win32)
44     enum NEEDS_WIN32_NON_MS = true;
45 else
46     enum NEEDS_WIN32_NON_MS = false;
47 
48 version (Win64)
49     enum NEEDS_WIN32_NOT_WIN64 = false;
50 else version (Win32)
51     enum NEEDS_WIN32_NOT_WIN64 = true;
52 else
53     enum NEEDS_WIN32_NOT_WIN64 = false;
54 
55 
56 extern(C++):
57 
58 nothrow:
59 @safe:
60 
61 version (CRuntime_Microsoft)
62 {
63     import core.stdc.stdlib;
64 }
65 //debug = printf;
66 version (Windows)
67 {
68     extern(C++) void dll_printf(const char *format,...);
69     alias printf = dll_printf;
70 }
71 
72 /***********************************
73  * Called when there is an error returned by the operating system.
74  * This function does not return.
75  */
76 void os_error(int line = __LINE__)
77 {
78     version(Windows)
79         debug(printf) printf("System error: %ldL\n", GetLastError());
80     assert(0);
81 }
82 
83 static if (NEEDS_WIN32_NOT_WIN64)
84 {
85 
86 private __gshared HANDLE hHeap;
87 
88 @trusted
89 void *globalrealloc(void *oldp,size_t newsize)
90 {
91 static if (0)
92 {
93     void *p;
94 
95     // Initialize heap
96     if (!hHeap)
97     {   hHeap = HeapCreate(0,0x10000,0);
98         if (!hHeap)
99             os_error();
100     }
101 
102     newsize = (newsize + 3) & ~3L;      // round up to dwords
103     if (newsize == 0)
104     {
105         if (oldp && HeapFree(hHeap,0,oldp) == false)
106             os_error();
107         p = NULL;
108     }
109     else if (!oldp)
110     {
111         p = newsize ? HeapAlloc(hHeap,0,newsize) : null;
112     }
113     else
114         p = HeapReAlloc(hHeap,0,oldp,newsize);
115 }
116 else static if (1)
117 {
118     MEMORY_BASIC_INFORMATION query;
119     void *p;
120     BOOL bSuccess;
121 
122     if (!oldp)
123         p = VirtualAlloc (null, newsize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
124     else
125     {
126         VirtualQuery (oldp, &query, query.sizeof);
127         if (!newsize)
128         {
129             p = null;
130             goto L1;
131         }
132         else
133         {   newsize = (newsize + 0xFFFF) & ~0xFFFFL;
134 
135             if (query.RegionSize >= newsize)
136                 p = oldp;
137             else
138             {   p = VirtualAlloc(null,newsize,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
139                 if (p)
140                     memcpy(p,oldp,query.RegionSize);
141             L1:
142                 bSuccess = VirtualFree(oldp,query.RegionSize,MEM_DECOMMIT);
143                 if (bSuccess)
144                     bSuccess = VirtualFree(oldp,0,MEM_RELEASE);
145                 if (!bSuccess)
146                     os_error();
147             }
148         }
149     }
150 }
151 else
152 {
153     void *p;
154 
155     if (!oldp)
156         p = cast(void *)GlobalAlloc (0, newsize);
157     else if (!newsize)
158     {   GlobalFree(oldp);
159         p = null;
160     }
161     else
162         p = cast(void *)GlobalReAlloc(oldp,newsize,0);
163 }
164     debug(printf) printf("globalrealloc(oldp = %p, size = x%x) = %p\n",oldp,newsize,p);
165     return p;
166 }
167 
168 /*****************************************
169  * Functions to manage allocating a single virtual address space.
170  */
171 
172 @trusted
173 void *vmem_reserve(void *ptr,uint size)
174 {   void *p;
175 
176 version(none)
177 {
178     p = VirtualAlloc(ptr,size,MEM_RESERVE,PAGE_READWRITE);
179     debug(printf) printf("vmem_reserve(ptr = %p, size = x%lx) = %p\n",ptr,size,p);
180 }
181 else
182 {
183     debug(printf) printf("vmem_reserve(ptr = %p, size = x%lx) = %p\n",ptr,size,p);
184     p = VirtualAlloc(ptr,size,MEM_RESERVE,PAGE_READWRITE);
185     if (!p)
186         os_error();
187 }
188     return p;
189 }
190 
191 /*****************************************
192  * Commit memory.
193  * Returns:
194  *      0       failure
195  *      !=0     success
196  */
197 
198 @trusted
199 int vmem_commit(void *ptr, uint size)
200 {   int i;
201 
202     debug(printf) printf("vmem_commit(ptr = %p,size = x%lx)\n",ptr,size);
203     i = cast(int) VirtualAlloc(ptr,size,MEM_COMMIT,PAGE_READWRITE);
204     if (i == 0)
205         debug(printf) printf("failed to commit\n");
206     return i;
207 }
208 
209 @trusted
210 void vmem_decommit(void *ptr,uint size)
211 {
212     debug(printf) printf("vmem_decommit(ptr = %p, size = x%lx)\n",ptr,size);
213     if (ptr)
214     {   if (!VirtualFree(ptr, size, MEM_DECOMMIT))
215             os_error();
216     }
217 }
218 
219 @trusted
220 void vmem_release(void *ptr, uint size)
221 {
222     debug(printf) printf("vmem_release(ptr = %p, size = x%lx)\n",ptr,size);
223     if (ptr)
224     {
225         if (!VirtualFree(ptr, 0, MEM_RELEASE))
226             os_error();
227     }
228 }
229 
230 /********************************************
231  * Map file for read, copy on write, into virtual address space.
232  * Input:
233  *      ptr             address to map file to, if NULL then pick an address
234  *      size            length of the file
235  *      flag    0       read / write
236  *              1       read / copy on write
237  *              2       read only
238  * Returns:
239  *      NULL    failure
240  *      ptr     pointer to start of mapped file
241  */
242 
243 private __gshared HANDLE hFile = INVALID_HANDLE_VALUE;
244 private __gshared HANDLE hFileMap = null;
245 private __gshared void *pview;
246 private __gshared void *preserve;
247 private __gshared size_t preserve_size;
248 
249 @trusted
250 void *vmem_mapfile(const char *filename,void *ptr, uint size,int flag)
251 {
252     OSVERSIONINFO OsVerInfo;
253 
254     OsVerInfo.dwOSVersionInfoSize = OsVerInfo.sizeof;
255     GetVersionEx(&OsVerInfo);
256 
257     debug(printf) printf("vmem_mapfile(filename = '%s', ptr = %p, size = x%lx, flag = %d)\n",
258                          filename,ptr,size,flag);
259 
260     hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
261                         FILE_SHARE_READ | FILE_SHARE_WRITE, null,
262                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null);
263     if (hFile == INVALID_HANDLE_VALUE)
264         goto L1;                        // failure
265     debug(printf) printf(" file created\n");
266 
267     // Windows 95 does not implement PAGE_WRITECOPY (unfortunately treating
268     // it just like PAGE_READWRITE).
269     if (flag == 1 && OsVerInfo.dwPlatformId == 1)       // Windows 95, 98, ME
270         hFileMap = null;
271     else
272         hFileMap = CreateFileMappingA(hFile,null,
273                 (flag == 1) ? PAGE_WRITECOPY : PAGE_READWRITE,0,size,null);
274 
275     if (hFileMap == null)               // mapping failed
276     {
277 version(all)
278 {
279         // Win32s seems to always fail here.
280         DWORD nbytes;
281 
282         debug(printf) printf(" mapping failed\n");
283         // If it was NT failing, assert.
284         assert(OsVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT);
285 
286         // To work around, just read the file into memory.
287         assert(flag == 1);
288         preserve = vmem_reserve(ptr,size);
289         if (!preserve)
290             goto L2;
291         if (!vmem_commit(preserve,size))
292         {
293             vmem_release(preserve,size);
294             preserve = null;
295             goto L2;
296         }
297         preserve_size = size;
298         if (!ReadFile(hFile,preserve,size,&nbytes,null))
299             os_error();
300         assert(nbytes == size);
301         if (CloseHandle(hFile) != true)
302             os_error();
303         hFile = INVALID_HANDLE_VALUE;
304         return preserve;
305 }
306 else
307 {
308         // Instead of working around, we should find out why it failed.
309         os_error();
310 }
311 
312     }
313     else
314     {
315         debug(printf) printf(" mapping created\n");
316         pview = MapViewOfFileEx(hFileMap,flag ? FILE_MAP_COPY : FILE_MAP_WRITE,
317                 0,0,size,ptr);
318         if (pview == null)                      // mapping view failed
319         {   //os_error();
320             goto L3;
321         }
322     }
323     debug(printf) printf(" pview = %p\n",pview);
324 
325     return pview;
326 
327 L3:
328     if (CloseHandle(hFileMap) != true)
329         os_error();
330     hFileMap = null;
331 L2:
332     if (CloseHandle(hFile) != true)
333         os_error();
334     hFile = INVALID_HANDLE_VALUE;
335 L1:
336     return null;                        // failure
337 }
338 
339 /*****************************
340  * Set size of mapped file.
341  */
342 
343 @trusted
344 void vmem_setfilesize(uint size)
345 {
346     if (hFile != INVALID_HANDLE_VALUE)
347     {   if (SetFilePointer(hFile,size,null,FILE_BEGIN) == 0xFFFFFFFF)
348             os_error();
349         if (SetEndOfFile(hFile) == false)
350             os_error();
351     }
352 }
353 
354 /*****************************
355  * Unmap previous file mapping.
356  */
357 
358 @trusted
359 void vmem_unmapfile()
360 {
361     debug(printf) printf("vmem_unmapfile()\n");
362 
363     vmem_decommit(preserve,preserve_size);
364     vmem_release(preserve,preserve_size);
365     preserve = null;
366     preserve_size = 0;
367 
368 version(none)
369 {
370     if (pview)
371     {   int i;
372 
373         i = UnmapViewOfFile(pview);
374         debug(printf) printf("i = x%x\n",i);
375         if (i == false)
376             os_error();
377     }
378 }
379 else
380 {
381     // Note that under Windows 95, UnmapViewOfFile() seems to return random
382     // values, not TRUE or FALSE.
383     if (pview && UnmapViewOfFile(pview) == false)
384         os_error();
385 }
386     pview = null;
387 
388     if (hFileMap != null && CloseHandle(hFileMap) != true)
389         os_error();
390     hFileMap = null;
391 
392     if (hFile != INVALID_HANDLE_VALUE && CloseHandle(hFile) != true)
393         os_error();
394     hFile = INVALID_HANDLE_VALUE;
395 }
396 
397 /****************************************
398  * Determine a base address that we can use for mapping files to.
399  */
400 
401 @trusted
402 void *vmem_baseaddr()
403 {
404     OSVERSIONINFO OsVerInfo;
405     void *p;
406 
407     OsVerInfo.dwOSVersionInfoSize = OsVerInfo.sizeof;
408     GetVersionEx(&OsVerInfo);
409 
410     // These values for the address were determined by trial and error.
411     switch (OsVerInfo.dwPlatformId)
412     {
413         case VER_PLATFORM_WIN32s:               // Win32s
414             // The fact that this is a different address than other
415             // WIN32 implementations causes us a lot of grief.
416             p = cast(void *) 0xC0000000;
417             break;
418 
419         case 1: //VER_PLATFORM_WIN32_WINDOWS:   // Windows 95
420             // I've found 0x90000000..0xB work. All others fail.
421         default:                                // unknown
422             p = cast(void *) 0x90000000;
423             break;
424 
425         case VER_PLATFORM_WIN32_NT:             // Windows NT
426             // Pick a value that is not coincident with the base address
427             // of any commonly used system DLLs.
428             p = cast(void *) 0x38000000;
429             break;
430     }
431 
432     return p;
433 }
434 
435 /********************************************
436  * Calculate the amount of memory to reserve, adjusting
437  * *psize downwards.
438  */
439 
440 @trusted
441 void vmem_reservesize(uint *psize)
442 {
443     MEMORYSTATUS ms;
444     OSVERSIONINFO OsVerInfo;
445 
446     uint size;
447 
448     ms.dwLength = ms.sizeof;
449     GlobalMemoryStatus(&ms);
450     debug(printf) printf("dwMemoryLoad    x%lx\n",ms.dwMemoryLoad);
451     debug(printf) printf("dwTotalPhys     x%lx\n",ms.dwTotalPhys);
452     debug(printf) printf("dwAvailPhys     x%lx\n",ms.dwAvailPhys);
453     debug(printf) printf("dwTotalPageFile x%lx\n",ms.dwTotalPageFile);
454     debug(printf) printf("dwAvailPageFile x%lx\n",ms.dwAvailPageFile);
455     debug(printf) printf("dwTotalVirtual  x%lx\n",ms.dwTotalVirtual);
456     debug(printf) printf("dwAvailVirtual  x%lx\n",ms.dwAvailVirtual);
457 
458 
459     OsVerInfo.dwOSVersionInfoSize = OsVerInfo.sizeof;
460     GetVersionEx(&OsVerInfo);
461 
462     switch (OsVerInfo.dwPlatformId)
463     {
464         case VER_PLATFORM_WIN32s:               // Win32s
465         case 1: //VER_PLATFORM_WIN32_WINDOWS:   // Windows 95
466         default:                                // unknown
467             size = (ms.dwAvailPageFile < ms.dwAvailVirtual)
468                 ? ms.dwAvailPageFile
469                 : ms.dwAvailVirtual;
470             size = cast(ulong)size * 8 / 10;
471             size &= ~0xFFFF;
472             if (size < *psize)
473                 *psize = size;
474             break;
475 
476         case VER_PLATFORM_WIN32_NT:             // Windows NT
477             // NT can expand the paging file
478             break;
479     }
480 
481 }
482 
483 /********************************************
484  * Return amount of physical memory.
485  */
486 
487 @trusted
488 uint vmem_physmem()
489 {
490     MEMORYSTATUS ms;
491 
492     ms.dwLength = ms.sizeof;
493     GlobalMemoryStatus(&ms);
494     return ms.dwTotalPhys;
495 }
496 
497 //////////////////////////////////////////////////////////////
498 
499 /***************************************************
500  * Load library.
501  */
502 
503 private __gshared HINSTANCE hdll;
504 
505 @trusted
506 void os_loadlibrary(const char *dllname)
507 {
508     hdll = LoadLibrary(cast(LPCTSTR) dllname);
509     if (!hdll)
510         os_error();
511 }
512 
513 /*************************************************
514  */
515 
516 @trusted
517 void os_freelibrary()
518 {
519     if (hdll)
520     {
521         if (FreeLibrary(hdll) != true)
522             os_error();
523         hdll = null;
524     }
525 }
526 
527 /*************************************************
528  */
529 
530 @trusted
531 void *os_getprocaddress(const char *funcname)
532 {   void *fp;
533 
534     //printf("getprocaddress('%s')\n",funcname);
535     assert(hdll);
536     fp = cast(void *)GetProcAddress(hdll,cast(LPCSTR)funcname);
537     if (!fp)
538         os_error();
539     return fp;
540 }
541 
542 //////////////////////////////////////////////////////////////
543 
544 
545 /*********************************
546  */
547 
548 @trusted
549 void os_term()
550 {
551     if (hHeap)
552     {   if (HeapDestroy(hHeap) == false)
553         {   hHeap = null;
554             os_error();
555         }
556         hHeap = null;
557     }
558     os_freelibrary();
559 }
560 
561 /***************************************************
562  * Do our own storage allocator (being suspicious of the library one).
563  */
564 
565 version(all)
566 {
567 void os_heapinit() { }
568 void os_heapterm() { }
569 
570 }
571 else
572 {
573 static HANDLE hHeap;
574 
575 void os_heapinit()
576 {
577     hHeap = HeapCreate(0,0x10000,0);
578     if (!hHeap)
579         os_error();
580 }
581 
582 void os_heapterm()
583 {
584     if (hHeap)
585     {   if (HeapDestroy(hHeap) == false)
586             os_error();
587     }
588 }
589 
590 extern(Windows) void * calloc(size_t x,size_t y)
591 {   size_t size;
592 
593     size = x * y;
594     return size ? HeapAlloc(hHeap,HEAP_ZERO_MEMORY,size) : null;
595 }
596 
597 extern(Windows) void free(void *p)
598 {
599     if (p && HeapFree(hHeap,0,p) == false)
600         os_error();
601 }
602 
603 extern(Windows) void * malloc(size_t size)
604 {
605     return size ? HeapAlloc(hHeap,0,size) : null;
606 }
607 
608 extern(Windows) void * realloc(void *p,size_t newsize)
609 {
610     if (newsize == 0)
611         free(p);
612     else if (!p)
613         p = malloc(newsize);
614     else
615         p = HeapReAlloc(hHeap,0,p,newsize);
616     return p;
617 }
618 
619 }
620 
621 //////////////////////////////////////////
622 // Return a value that will hopefully be unique every time
623 // we call it.
624 
625 @trusted
626 uint os_unique()
627 {
628     ulong x;
629 
630     QueryPerformanceCounter(cast(LARGE_INTEGER *)&x);
631     return cast(uint)x;
632 }
633 
634 } // Win32
635 
636 /*******************************************
637  * Return !=0 if file exists.
638  *      0:      file doesn't exist
639  *      1:      normal file
640  *      2:      directory
641  */
642 
643 @trusted
644 int os_file_exists(const char *name)
645 {
646 version(Windows)
647 {
648     DWORD dw;
649     int result;
650 
651     dw = GetFileAttributesA(name);
652     if (dw == -1L)
653         result = 0;
654     else if (dw & FILE_ATTRIBUTE_DIRECTORY)
655         result = 2;
656     else
657         result = 1;
658     return result;
659 }
660 else version(Posix)
661 {
662     stat_t buf;
663 
664     return stat(name,&buf) == 0;        /* file exists if stat succeeded */
665 
666 }
667 else
668 {
669     return filesize(name) != -1L;
670 }
671 }
672 
673 /**************************************
674  * Get file size of open file. Return -1L on error.
675  */
676 
677 static if(NEEDS_WIN32_NON_MS)
678 {
679     extern extern (C) void*[] _osfhnd;
680 }
681 
682 @trusted
683 long os_file_size(int fd)
684 {
685     static if (NEEDS_WIN32_NON_MS)
686     {
687         return GetFileSize(_osfhnd[fd],null);
688     }
689     else
690     {
691         version(Windows)
692         {
693             return GetFileSize(cast(void*)_get_osfhandle(fd),null);
694         }
695         else
696         {
697             stat_t buf;
698             return (fstat(fd,&buf)) ? -1L : buf.st_size;
699         }
700     }
701 }
702 
703 /**************************************************
704  * For 16 bit programs, we need the 16 bit filename.
705  * Returns:
706  *      malloc'd string, NULL if none
707  */
708 
709 version(Windows)
710 {
711 @trusted
712 char *file_8dot3name(const char *filename)
713 {
714     HANDLE h;
715     WIN32_FIND_DATAA fileinfo;
716     char *buf;
717     size_t i;
718 
719     h = FindFirstFileA(filename,&fileinfo);
720     if (h == INVALID_HANDLE_VALUE)
721         return null;
722     if (fileinfo.cAlternateFileName[0])
723     {
724         for (i = strlen(filename); i > 0; i--)
725             if (filename[i] == '\\' || filename[i] == ':')
726             {   i++;
727                 break;
728             }
729         buf = cast(char *) malloc(i + 14);
730         if (buf)
731         {
732             memcpy(buf,filename,i);
733             strcpy(buf + i,fileinfo.cAlternateFileName.ptr);
734         }
735     }
736     else
737         buf = strdup(filename);
738     FindClose(h);
739     return buf;
740 }
741 }
742 
743 /**********************************************
744  * Write a file.
745  * Returns:
746  *      0       success
747  */
748 
749 @trusted
750 int file_write(char *name, void *buffer, uint len)
751 {
752 version(Posix)
753 {
754     int fd;
755     ssize_t numwritten;
756 
757     fd = open(name, O_CREAT | O_WRONLY | O_TRUNC,
758             S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
759     if (fd == -1)
760         goto err;
761 
762     numwritten = .write(fd, buffer, len);
763     if (len != numwritten)
764         goto err2;
765 
766     if (close(fd) == -1)
767         goto err;
768 
769     return 0;
770 
771 err2:
772     close(fd);
773 err:
774     return 1;
775 }
776 else version(Windows)
777 {
778     HANDLE h;
779     DWORD numwritten;
780 
781     h = CreateFileA(cast(LPCSTR)name,GENERIC_WRITE,0,null,CREATE_ALWAYS,
782         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,null);
783     if (h == INVALID_HANDLE_VALUE)
784     {
785         if (GetLastError() == ERROR_PATH_NOT_FOUND)
786         {
787             if (!file_createdirs(name))
788             {
789                 h = CreateFileA(cast(LPCSTR)name, GENERIC_WRITE, 0, null, CREATE_ALWAYS,
790                     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,null);
791                 if (h != INVALID_HANDLE_VALUE)
792                     goto Lok;
793             }
794         }
795         goto err;
796     }
797 
798 Lok:
799     if (WriteFile(h,buffer,len,&numwritten,null) != true)
800         goto err2;
801 
802     if (len != numwritten)
803         goto err2;
804 
805     if (!CloseHandle(h))
806         goto err;
807     return 0;
808 
809 err2:
810     CloseHandle(h);
811 err:
812     return 1;
813 }
814 }
815 
816 /********************************
817  * Create directories up to filename.
818  * Input:
819  *      name    path/filename
820  * Returns:
821  *      0       success
822  *      !=0     failure
823  */
824 
825 @trusted
826 int file_createdirs(char *name)
827 {
828 version(Posix)
829 {
830     return 1;
831 }
832 else version(Windows)
833 {
834     auto len = strlen(name);
835     char *path = cast(char *)alloca(len + 1);
836     char *p;
837 
838     memcpy(path, name, len + 1);
839 
840     for (p = path + len; ; p--)
841     {
842         if (p == path)
843             goto Lfail;
844         switch (*p)
845         {
846             case ':':
847             case '/':
848             case '\\':
849                 *p = 0;
850                 if (!CreateDirectory(cast(LPTSTR)path, null))
851                 {   // Failed
852                     if (file_createdirs(path))
853                         goto Lfail;
854                     if (!CreateDirectory(cast(LPTSTR)path, null))
855                         goto Lfail;
856                 }
857                 return 0;
858             default:
859                 continue;
860         }
861     }
862 
863 Lfail:
864     return 1;
865 }
866 }
867 
868 /***********************************
869  * Returns:
870  *   result of C library clock()
871  */
872 
873 int os_clock()
874 {
875     return cast(int) clock();
876 }
877 
878 /***********************************
879  * Return size of OS critical section.
880  * NOTE: can't use the sizeof() calls directly since cross compiling is
881  * supported and would end up using the host sizes rather than the target
882  * sizes.
883  */
884 
885 
886 
887 version(Windows)
888 {
889 int os_critsecsize32()
890 {
891     return 24;  // sizeof(CRITICAL_SECTION) for 32 bit Windows
892 }
893 
894 int os_critsecsize64()
895 {
896     return 40;  // sizeof(CRITICAL_SECTION) for 64 bit Windows
897 }
898 }
899 else version(linux)
900 {
901 int os_critsecsize32()
902 {
903     return 24; // sizeof(pthread_mutex_t) on 32 bit
904 }
905 
906 int os_critsecsize64()
907 {
908     return 40; // sizeof(pthread_mutex_t) on 64 bit
909 }
910 }
911 
912 else version(FreeBSD)
913 {
914 int os_critsecsize32()
915 {
916     return 4; // sizeof(pthread_mutex_t) on 32 bit
917 }
918 
919 int os_critsecsize64()
920 {
921     return 8; // sizeof(pthread_mutex_t) on 64 bit
922 }
923 }
924 
925 else version(OpenBSD)
926 {
927 int os_critsecsize32()
928 {
929     return 4; // sizeof(pthread_mutex_t) on 32 bit
930 }
931 
932 int os_critsecsize64()
933 {
934     return 8; // sizeof(pthread_mutex_t) on 64 bit
935 }
936 }
937 else version(DragonFlyBSD)
938 {
939 int os_critsecsize32()
940 {
941     return 4; // sizeof(pthread_mutex_t) on 32 bit
942 }
943 
944 int os_critsecsize64()
945 {
946     return 8; // sizeof(pthread_mutex_t) on 64 bit
947 }
948 }
949 
950 else version (OSX)
951 {
952 int os_critsecsize32()
953 {
954     version(X86_64)
955     {
956         assert(pthread_mutex_t.sizeof == 64);
957     }
958     else
959     {
960         assert(pthread_mutex_t.sizeof == 44);
961     }
962     return 44;
963 }
964 
965 int os_critsecsize64()
966 {
967     return 64;
968 }
969 }
970 
971 else version(Solaris)
972 {
973 int os_critsecsize32()
974 {
975     assert(pthread_mutex_t.sizeof == 24);
976     return 24;
977 }
978 
979 int os_critsecsize64()
980 {
981     assert(pthread_mutex_t.sizeof == 24);
982     return 24;
983 }
984 }
985 
986 /* This is the magic program to get the size on Posix systems:
987 
988 #if 0
989 #include <stdio.h>
990 #include <pthread.h>
991 
992 int main()
993 {
994     printf("%d\n", (int)sizeof(pthread_mutex_t));
995     return 0;
996 }
997 #endif
998 
999 #endif
1000 */