8 void *GC_mmapAnon (void *start
, size_t length
) {
9 return Windows_mmapAnon (start
, length
);
12 void GC_release (void *base
, size_t length
) {
13 Windows_release (base
, length
);
16 void *GC_extendHead (void *base
, size_t length
) {
17 return Windows_mmapAnon (base
, length
);
20 void *GC_extendTail (void *base
, size_t length
) {
21 return Windows_extend (base
, length
);
24 uintmax_t GC_physMem (void) {
26 MEMORYSTATUSEX memstat
;
27 memstat
.dwLength
= sizeof(memstat
);
28 GlobalMemoryStatusEx(&memstat
);
29 return (uintmax_t)memstat
.ullTotalPhys
;
32 memstat
.dwLength
= sizeof(memstat
);
33 GlobalMemoryStatus(&memstat
);
34 return (uintmax_t)memstat
.dwTotalPhys
;
38 size_t GC_pageSize (void) {
40 GetSystemInfo(&sysinfo
);
41 return (size_t)sysinfo
.dwAllocationGranularity
;
44 HANDLE
fileDesHandle (int fd
) {
45 // The temporary prevents a "cast does not match function type" warning.
48 t
= _get_osfhandle (fd
);
52 int mkstemp (char *template) {
57 if (0 == GetTempPath (sizeof (file_path
), file_path
))
58 diee ("unable to make temporary file");
59 strncpy (templ
, template, sizeof (templ
) - 1);
60 templ
[sizeof (templ
) - 1] = 0x00;
61 if (0 == GetTempFileName (file_path
, templ
, 0, file_name
))
62 diee ("unable to make temporary file");
63 return _open (file_name
, _O_CREAT
| _O_RDWR
, _S_IREAD
| _S_IWRITE
);
66 /* ------------------------------------------------- */
68 /* ------------------------------------------------- */
71 #define EPOCHFILETIME (116444736000000000i64)
73 #define EPOCHFILETIME (116444736000000000LL)
76 /* The basic plan is to get an initial time using GetSystemTime
77 * that is good up to ~10ms accuracy. From then on, we compute
78 * using deltas with the high-resolution (> microsecond range)
79 * performance timers. A 64-bit accumulator holds microseconds
80 * since (*nix) epoch. This is good for over 500,000 years before
81 * wrap-around becomes a concern.
83 * However, we might need to watch out for wrap-around with the
84 * QueryPerformanceCounter, because it could be measuring at a higher
85 * frequency than microseconds.
87 * This function only strives to allow a program to run for
88 * 100 years without being restarted.
90 int gettimeofday (struct timeval
*tv
,
91 __attribute__ ((unused
)) struct timezone
*tz
) {
92 static LARGE_INTEGER frequency
; /* ticks/second */
93 static LARGE_INTEGER baseCounter
; /* ticks since last rebase */
94 static LARGE_INTEGER baseMicroSeconds
; /* unix time at last rebase */
96 LARGE_INTEGER nowCounter
;
97 LARGE_INTEGER deltaCounter
;
98 LARGE_INTEGER nowMicroSeconds
;
99 double deltaMicroseconds
;
101 /* This code is run the first time gettimeofday is called. */
102 if (frequency
.QuadPart
== 0) {
104 /* tzset prepares the localtime function. I don't
105 * really understand why it's here and not there,
106 * but this has been the case since before svn logs.
107 * So I leave it here to preserve the status-quo.
111 QueryPerformanceCounter(&baseCounter
);
112 QueryPerformanceFrequency(&frequency
);
113 if (frequency
.QuadPart
== 0)
114 die("no high resolution clock");
116 GetSystemTimeAsFileTime (&ft
);
117 baseMicroSeconds
.LowPart
= ft
.dwLowDateTime
;
118 baseMicroSeconds
.HighPart
= ft
.dwHighDateTime
;
119 baseMicroSeconds
.QuadPart
-= EPOCHFILETIME
;
120 baseMicroSeconds
.QuadPart
/= 10; /* 100ns -> 1ms */
123 /* Use the high res counter ticks to calculate the delta.
124 * A double has 52+1 bits of precision. This means it can fit
125 * deltas of up to 9007199254 seconds, or 286 years. We could
126 * rebase before an overflow, but 286 is already > 100.
128 QueryPerformanceCounter(&nowCounter
);
129 deltaCounter
.QuadPart
= nowCounter
.QuadPart
- baseCounter
.QuadPart
;
130 deltaMicroseconds
= deltaCounter
.QuadPart
;
131 deltaMicroseconds
/= frequency
.QuadPart
;
132 deltaMicroseconds
*= 1000000.0;
133 nowMicroSeconds
.QuadPart
=
134 baseMicroSeconds
.QuadPart
+ deltaMicroseconds
;
136 /* If the frequency too fast, we need to check for wrap around.
137 * 2**32 seconds is 136 years, so if HighPart == 0 we don't need to
138 * waste a system call on GetSystemTimeAsFileTime.
140 if (frequency
.HighPart
!= 0) {
141 LARGE_INTEGER nowLowResMicroSeconds
;
144 /* Use low res timer to detect performance counter wrap-around. */
145 GetSystemTimeAsFileTime (&ft
);
146 nowLowResMicroSeconds
.LowPart
= ft
.dwLowDateTime
;
147 nowLowResMicroSeconds
.HighPart
= ft
.dwHighDateTime
;
148 nowLowResMicroSeconds
.QuadPart
-= EPOCHFILETIME
;
149 nowLowResMicroSeconds
.QuadPart
/= 10;
151 /* If deltaMicroseconds deviates by more than a second from the low
152 * resolution timer, assume the high performance counter has wrapped.
153 * One second is a safe margin b/c QueryPerformanceFrequency must fit
154 * in a 64-bit integer. Therefore any wrap must exceed one second.
156 if (nowMicroSeconds
.QuadPart
+ 1000000 < nowLowResMicroSeconds
.QuadPart
) {
157 baseCounter
= nowCounter
;
158 baseMicroSeconds
= nowLowResMicroSeconds
;
159 nowMicroSeconds
= nowLowResMicroSeconds
;
162 /* The above wrap-around detection destroys high resolution timing.
163 * However, if one needs high resolution timing, then one is querying
164 * gettimeofday quite often. Therefore, rebase the clock before any
165 * wrap around troubles happen. We don't do this too often as it
166 * introduces clock drift.
168 if ((deltaCounter
.HighPart
& 0xffff0000UL
) != 0) {
169 baseCounter
= nowCounter
;
170 baseMicroSeconds
= nowMicroSeconds
;
174 tv
->tv_sec
= (long)(nowMicroSeconds
.QuadPart
/ 1000000);
175 tv
->tv_usec
= (long)(nowMicroSeconds
.QuadPart
% 1000000);
180 /* ------------------------------------------------- */
182 /* ------------------------------------------------- */
184 /* We use the kernel's TimerQueues -- see:
185 * http://msdn.microsoft.com/en-us/library/ms686796(VS.85).aspx
188 static HANDLE MainThread
= NULL
;
189 static HANDLE TimerQueue
= NULL
;
190 static HANDLE RealTimer
= NULL
;
191 static HANDLE VirtTimer
= NULL
;
192 static HANDLE ProfTimer
= NULL
;
193 static HANDLE PrioTimer
= NULL
;
194 static void (*SIGALRM_handler
)(int sig
) = SIG_DFL
;
195 static void (*SIGVTAM_handler
)(int sig
) = SIG_DFL
;
196 static void (*SIGPROF_handler
)(int sig
) = SIG_DFL
;
198 /* The timer handler is fired in another thread.
199 * The idea is to suspend the main thread and resume it once we're done.
200 * This will appear more-or-less the same as if a Unix system had received
201 * the signal. We will also be firing the handler in the timer thread itself
202 * for performance reasons (MLton uses this mechanism to do multi-threading).
203 * This means the signal handlers must be fast, which they are since they
204 * just mark the signal to be processed later.
207 static VOID CALLBACK
MLton_SIGALRM(__attribute__ ((unused
)) PVOID myArg
,
208 __attribute__ ((unused
)) BOOLEAN timeout
) {
209 SuspendThread(MainThread
);
210 if (SIGALRM_handler
== SIG_IGN
) {
212 } else if (SIGALRM_handler
== SIG_DFL
) {
215 (*SIGALRM_handler
)(SIGALRM
);
217 ResumeThread(MainThread
);
219 static VOID CALLBACK
MLton_SIGVTAM(__attribute__ ((unused
)) PVOID myArg
,
220 __attribute__ ((unused
)) BOOLEAN timeout
) {
221 SuspendThread(MainThread
);
222 if (SIGVTAM_handler
== SIG_IGN
) {
224 } else if (SIGVTAM_handler
== SIG_DFL
) {
227 (*SIGVTAM_handler
)(SIGVTALRM
);
229 ResumeThread(MainThread
);
231 static VOID CALLBACK
MLton_SIGPROF(__attribute__ ((unused
)) PVOID myArg
,
232 __attribute__ ((unused
)) BOOLEAN timeout
) {
233 SuspendThread(MainThread
);
234 if (SIGPROF_handler
== SIG_IGN
) {
236 } else if (SIGPROF_handler
== SIG_DFL
) {
239 (*SIGPROF_handler
)(SIGPROF
);
241 ResumeThread(MainThread
);
244 static void CALLBACK
fixPriority(__attribute__ ((unused
)) PVOID myArg
,
245 __attribute__ ((unused
)) BOOLEAN timeout
) {
246 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL
);
247 DeleteTimerQueueTimer(TimerQueue
, PrioTimer
, NULL
);
250 static int MLTimer(HANDLE
*timer
,
251 const struct itimerval
*value
,
252 WAITORTIMERCALLBACK callback
) {
253 DWORD DueTime
, Period
;
255 /* Initialize the TimerQueue */
256 if (MainThread
== 0) {
257 /* This call improves the resolution of the scheduler from
258 * 16ms to about 2ms in my testing. Sadly it requires winmm.
262 TimerQueue
= CreateTimerQueue();
263 if (TimerQueue
== NULL
) { errno
= ENOMEM
; return -1; }
265 /* We need to get the TimerQueue to have higher priority.
266 * From my testing, if it has the same priority as the main
267 * thread and the main thread is busy, your best resolution
268 * is a terribly slow 188ms. By boosting the priority of the
269 * timer thread to ABOVE_NORMAL, I've gotten down to 2ms.
271 CreateTimerQueueTimer(&PrioTimer
, TimerQueue
, fixPriority
,
272 0, 1, 0, WT_EXECUTEINTIMERTHREAD
);
274 /* We need a handle to the main thread usable by the timer
275 * thread. GetCurrentThread() is a self-reference so we need
276 * to copy it to a new handle for it to work in other threads.
278 DuplicateHandle(GetCurrentProcess(), /* source process */
279 GetCurrentThread(), /* source handle */
280 GetCurrentProcess(), /* target process */
281 &MainThread
, /* target handle */
282 0, /* access (ignored) */
283 FALSE
, /* not inheritable */
284 DUPLICATE_SAME_ACCESS
);
286 if (MainThread
== 0) die("Cannot get handle to initial thread");
289 /* Windows uses ms accuracy for TimerQueues */
290 DueTime
= value
->it_value
.tv_sec
* 1000
291 + (value
->it_value
.tv_usec
+ 999) / 1000;
292 Period
= value
->it_interval
.tv_sec
* 1000
293 + (value
->it_interval
.tv_usec
+ 999) / 1000;
296 DeleteTimerQueueTimer(TimerQueue
, *timer
, NULL
);
304 if (!CreateTimerQueueTimer(
305 timer
, /* output: created timer */
306 TimerQueue
, /* The queue which holds the timers */
307 callback
, /* Invoked on timer events */
308 0, /* myArg for the callback */
309 DueTime
, /* Must be non-zero => time till first event */
310 Period
, /* Time till the event repeats (forever) */
311 WT_EXECUTEINTIMERTHREAD
)) { /* Don't use a thread pool */
319 int setitimer (int which
,
320 const struct itimerval
*value
,
321 struct itimerval
*ovalue
) {
322 if (ovalue
!= 0) die("setitimer doesn't support retrieving old state");
325 case ITIMER_REAL
: return MLTimer(&RealTimer
, value
, &MLton_SIGALRM
);
326 case ITIMER_VIRT
: return MLTimer(&VirtTimer
, value
, &MLton_SIGVTAM
);
327 case ITIMER_PROF
: return MLTimer(&ProfTimer
, value
, &MLton_SIGPROF
);
328 default: errno
= EINVAL
; return -1;
333 static void catcher(__attribute__ ((unused
)) int signo
) {
335 context
.ContextFlags
= CONTEXT_CONTROL
;
337 GetThreadContext(MainThread
, &context
);
338 #if defined(__i386__)
339 GC_handleSigProf((code_pointer
) context
.Eip
);
340 #elif defined(__x86_64__)
341 GC_handleSigProf((code_pointer
) context
.Rip
);
343 GC_handleSigProf((code_pointer
) context
.Iar
);
344 #elif defined(_ALPHA_)
345 GC_handleSigProf((code_pointer
) context
.Fir
);
347 GC_handleSigProf((code_pointer
) context
.Fir
);
349 GC_handleSigProf((code_pointer
) context
.Pc
);
351 #error Profiling handler is missing for this architecture
355 void GC_setSigProfHandler (struct sigaction
*sa
) {
357 sa
->sa_handler
= (_sig_func_ptr
)&catcher
;
360 /* ------------------------------------------------- */
362 /* ------------------------------------------------- */
364 static struct rlimit rlimits
[RLIM_NLIMITS
];
366 static void initRlimits (void) {
367 static int done
= FALSE
;
373 for (lim
= 0; lim
< RLIM_NLIMITS
; ++lim
) {
374 rlimits
[lim
].rlim_cur
= 0;
375 rlimits
[lim
].rlim_max
= UINT_MAX
;
379 int getrlimit (int resource
, struct rlimit
*rlp
) {
381 if (resource
< 0 or resource
>= RLIM_NLIMITS
) {
385 *rlp
= rlimits
[resource
];
389 int setrlimit (int resource
, const struct rlimit
*rlp
) {
391 if (resource
< 0 or resource
>= RLIM_NLIMITS
) {
395 if (rlp
->rlim_cur
< rlimits
[resource
].rlim_max
)
396 rlimits
[resource
].rlim_cur
= rlp
->rlim_cur
;
401 rlimits
[resource
].rlim_max
= rlp
->rlim_max
;
405 /* ------------------------------------------------- */
407 /* ------------------------------------------------- */
409 /* GetProcessTimes and GetSystemTimeAsFileTime are documented at:
410 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocesstimes.asp
412 int getrusage (int who
, struct rusage
*usage
) {
413 /* FILETIME has dw{High,Low}DateTime which store the number of
414 * 100-nanoseconds since January 1, 1601
416 FILETIME creation_time
;
418 FILETIME kernel_time
;
421 uint64_t user_usecs
, kernel_usecs
;
423 if (who
== RUSAGE_CHILDREN
) {
424 // !!! could use exit_time - creation_time from cwait
425 memset(usage
, 0, sizeof(struct rusage
));
429 if (who
!= RUSAGE_SELF
) {
434 if (GetProcessTimes(GetCurrentProcess(),
435 &creation_time
, &exit_time
,
436 &kernel_time
, &user_time
) == 0) {
441 kernel_usecs
= kernel_time
.dwHighDateTime
;
442 kernel_usecs
<<= sizeof(kernel_time
.dwHighDateTime
)*8;
443 kernel_usecs
|= kernel_time
.dwLowDateTime
;
446 user_usecs
= user_time
.dwHighDateTime
;
447 user_usecs
<<= sizeof(user_time
.dwHighDateTime
)*8;
448 user_usecs
|= user_time
.dwLowDateTime
;
451 usage
->ru_utime
.tv_sec
= user_usecs
/ 1000000;
452 usage
->ru_utime
.tv_usec
= user_usecs
% 1000000;
453 usage
->ru_stime
.tv_sec
= kernel_usecs
/ 1000000;
454 usage
->ru_stime
.tv_usec
= kernel_usecs
% 1000000;
458 /* ------------------------------------------------- */
460 /* ------------------------------------------------- */
462 __attribute__ ((noreturn
))
463 int poll (__attribute__ ((unused
)) struct pollfd
*ufds
,
464 __attribute__ ((unused
)) unsigned int nfds
,
465 __attribute__ ((unused
)) int timeout
) {
466 die ("poll not implemented");
469 /* ------------------------------------------------- */
471 /* ------------------------------------------------- */
473 static void GetWin32FileName (int fd
, char* fname
) {
475 DWORD fileSize
, fileSizeHi
;
479 tmp
= _get_osfhandle (fd
);
481 fileSize
= GetFileSize (fh
, &fileSizeHi
);
482 fhmap
= CreateFileMapping (fh
, NULL
, PAGE_READONLY
, 0, fileSize
, NULL
);
484 pMem
= MapViewOfFile (fhmap
, FILE_MAP_READ
, 0, 0, 1);
486 GetMappedFileNameA (GetCurrentProcess(),
487 pMem
, fname
, MAX_PATH
);
488 UnmapViewOfFile (pMem
);
494 int fchmod (int filedes
, mode_t mode
) {
495 char fname
[MAX_PATH
+ 1];
497 GetWin32FileName (filedes
, fname
);
498 return _chmod (fname
, mode
);
501 int fchdir (int filedes
) {
502 char fname
[MAX_PATH
+ 1];
504 GetWin32FileName (filedes
, fname
);
505 return chdir (fname
);
508 __attribute__ ((noreturn
))
509 int chown (__attribute__ ((unused
)) const char *path
,
510 __attribute__ ((unused
)) uid_t owner
,
511 __attribute__ ((unused
)) gid_t group
) {
512 die ("chown not implemented");
515 __attribute__ ((noreturn
))
516 int fchown (__attribute__ ((unused
)) int fd
,
517 __attribute__ ((unused
)) uid_t owner
,
518 __attribute__ ((unused
)) gid_t group
) {
519 die ("fchown not implemented");
522 __attribute__ ((noreturn
))
523 long fpathconf (__attribute__ ((unused
)) int filedes
,
524 __attribute__ ((unused
)) int name
) {
525 die ("fpathconf not implemented");
528 __attribute__ ((noreturn
))
529 int link (__attribute__ ((unused
)) const char *oldpath
,
530 __attribute__ ((unused
)) const char *newpath
) {
531 die ("link not implemented");
534 int lstat (const char *file_name
, struct stat
*buf
) {
535 /* Win32 doesn't really have links. */
536 return stat (file_name
, buf
);
539 __attribute__ ((noreturn
))
540 int mkfifo (__attribute__ ((unused
)) const char *pathname
,
541 __attribute__ ((unused
)) mode_t mode
) {
542 die ("mkfifo not implemented");
545 __attribute__ ((noreturn
))
546 long pathconf (__attribute__ ((unused
)) const char *path
,
547 __attribute__ ((unused
)) int name
) {
548 die ("pathconf not implemented");
551 __attribute__ ((noreturn
))
552 int readlink (__attribute__ ((unused
)) const char *path
,
553 __attribute__ ((unused
)) char *buf
,
554 __attribute__ ((unused
)) size_t bufsiz
) {
555 die ("readlink not implemented");
558 __attribute__ ((noreturn
))
559 int symlink (__attribute__ ((unused
)) const char *oldpath
,
560 __attribute__ ((unused
)) const char *newpath
) {
561 die ("symlink not implemented");
564 int truncate (const char *path
, off_t len
) {
567 if ((fd
= open(path
, O_RDWR
)) == -1)
569 if (ftruncate(fd
, len
) < 0) {
578 /* ------------------------------------------------- */
580 /* ------------------------------------------------- */
582 __attribute__ ((noreturn
))
583 int fcntl (__attribute__ ((unused
)) int fd
,
584 __attribute__ ((unused
)) int cmd
,
586 die ("fcntl not implemented");
593 int pipe (int filedes
[2]) {
597 /* We pass no security attributes (0), so the current policy gets
598 * inherited. The pipe is set to NOT stay open in child processes.
599 * This will be corrected using DuplicateHandle in create()
600 * The 4k buffersize is choosen b/c that's what linux uses.
602 if (!CreatePipe(&read_h
, &write_h
, 0, 4096)) {
603 errno
= ENOMEM
; /* fake errno: out of resources */
606 /* This requires Win98+
607 * Choosing text/binary mode is defered till a later setbin/text call
609 filedes
[0] = _open_osfhandle((intptr_t)read_h
, _O_RDONLY
);
610 filedes
[1] = _open_osfhandle((intptr_t)write_h
, _O_WRONLY
);
611 if (filedes
[0] == -1 or filedes
[1] == -1) {
612 if (filedes
[0] == -1)
614 else close(filedes
[0]);
615 if (filedes
[1] == -1)
616 CloseHandle(write_h
);
617 else close(filedes
[1]);
625 /* ------------------------------------------------- */
627 /* ------------------------------------------------- */
629 __attribute__ ((noreturn
))
630 char *ctermid (__attribute__ ((unused
)) char* s
) {
631 die ("*ctermid not implemented");
634 __attribute__ ((noreturn
))
635 gid_t
getegid (void) {
636 die ("getegid not implemented");
639 __attribute__ ((noreturn
))
640 uid_t
geteuid (void) {
641 die ("geteuid not implemented");
644 __attribute__ ((noreturn
))
645 gid_t
getgid (void) {
646 die ("getgid not implemented");
649 __attribute__ ((noreturn
))
650 int getgroups (__attribute__ ((unused
)) int size
,
651 __attribute__ ((unused
)) gid_t list
[]) {
652 die ("getgroups not implemented");
655 __attribute__ ((noreturn
))
656 char *getlogin (void) {
657 die ("getlogin not implemented");
660 __attribute__ ((noreturn
))
661 pid_t
getpgid(__attribute__ ((unused
)) pid_t pid
) {
662 die ("getpgid not implemented");
665 __attribute__ ((noreturn
))
666 pid_t
getpgrp(void) {
667 die ("getpgrp not implemented");
670 __attribute__ ((noreturn
))
671 pid_t
getppid (void) {
672 die ("getppid not implemented");
675 __attribute__ ((noreturn
))
676 uid_t
getuid (void) {
677 die ("getuid not implemented");
680 int setenv (const char *name
, const char *value
, int overwrite
) {
681 /* We could use _putenv, but then we'd need a temporary buffer for
682 * use to concat name=value.
684 if (not overwrite
and getenv (name
)) {
686 return -1; /* previous mingw setenv was buggy and returned 0 */
689 if (SetEnvironmentVariable (name
, value
)) {
690 errno
= ENOMEM
; /* this happens often in Windows.. */
697 __attribute__ ((noreturn
))
698 int setgid (__attribute__ ((unused
)) gid_t gid
) {
699 die ("setgid not implemented");
702 __attribute__ ((noreturn
))
703 int setgroups (__attribute__ ((unused
)) size_t size
,
704 __attribute__ ((unused
)) const gid_t
*list
) {
705 die ("setgroups not implemented");
708 __attribute__ ((noreturn
))
709 int setpgid (__attribute__ ((unused
)) pid_t pid
,
710 __attribute__ ((unused
)) pid_t pgid
) {
711 die ("setpgid not implemented");
714 __attribute__ ((noreturn
))
715 pid_t
setsid (void) {
716 die ("setsid not implemented");
719 __attribute__ ((noreturn
))
720 int setuid (__attribute__ ((unused
)) uid_t uid
) {
721 die ("setuid not implemented");
724 __attribute__ ((noreturn
))
725 long sysconf (__attribute__ ((unused
)) int name
) {
726 die ("sysconf not implemented");
729 __attribute__ ((noreturn
))
730 clock_t times (__attribute__ ((unused
)) struct tms
*buf
) {
731 die ("times not implemented");
734 __attribute__ ((noreturn
))
735 char *ttyname (__attribute__ ((unused
)) int desc
) {
736 die ("*ttyname not implemented");
739 static void setMachine (struct utsname
*buf
) {
741 const char* platform
= "unknown";
745 level
= si
.dwProcessorType
;
746 switch (si
.wProcessorArchitecture
) {
747 case PROCESSOR_ARCHITECTURE_INTEL
:
748 if (level
< 3) level
= 3;
749 if (level
> 6) level
= 6;
752 case PROCESSOR_ARCHITECTURE_IA64
: platform
= "ia64"; break;
753 case PROCESSOR_ARCHITECTURE_AMD64
: platform
= "amd64"; break;
754 case PROCESSOR_ARCHITECTURE_PPC
: platform
= "ppc"; break;
755 case PROCESSOR_ARCHITECTURE_ALPHA
: platform
= "alpha"; break;
756 case PROCESSOR_ARCHITECTURE_MIPS
: platform
= "mips"; break;
757 case PROCESSOR_ARCHITECTURE_ARM
: platform
= "arm"; break;
758 case PROCESSOR_ARCHITECTURE_ALPHA64
: platform
= "alpha64"; break;
759 /* SHX? MSIL? IA32_ON_WIN64? */
760 default: platform
= "unknown"; break;
762 sprintf (buf
->machine
, platform
, level
);
765 static void setSysname (struct utsname
*buf
) {
767 const char* os
= "??";
770 /* Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. */
772 void (WINAPI
*pGNSI
)(LPSYSTEM_INFO
);
773 pGNSI
= (void(WINAPI
*)(LPSYSTEM_INFO
))
774 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
775 "GetNativeSystemInfo");
782 osv
.dwOSVersionInfoSize
= sizeof (osv
);
783 /* Try to get extended information in order to be able to match the O.S. more
784 precisely using osv.wProductType */
785 if (! GetVersionEx ((OSVERSIONINFO
*)(void*) &osv
)) {
786 ZeroMemory(&osv
, sizeof(OSVERSIONINFOEX
));
787 osv
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
788 GetVersionEx((OSVERSIONINFO
*)(void*) &osv
);
790 switch (osv
.dwPlatformId
) {
791 case VER_PLATFORM_WIN32_NT
:
793 if (osv
.dwMinorVersion
== 0) {
794 if (osv
.dwMajorVersion
<= 6) {
795 if (osv
.wProductType
== VER_NT_WORKSTATION
)
799 } else os
= "NTx_64";
800 } else if (osv
.dwMinorVersion
<= 2) os
= "XP_64";
803 if (osv
.dwMinorVersion
== 0) {
804 if (osv
.dwMajorVersion
<= 4) os
= "NT";
805 else if (osv
.dwMajorVersion
<= 5) os
= "2000";
807 if (osv
.wProductType
== VER_NT_WORKSTATION
) {
808 if (si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
)
813 if (si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
)
819 } else if (osv
.dwMinorVersion
<= 1) os
= "XP";
820 else if (osv
.dwMinorVersion
<= 2) {
821 if (si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_AMD64
)
828 case VER_PLATFORM_WIN32_WINDOWS
:
829 if (osv
.dwMinorVersion
== 0) os
= "95";
830 else if (osv
.dwMinorVersion
< 90) os
= "98";
831 else if (osv
.dwMinorVersion
== 90) os
= "Me";
834 case VER_PLATFORM_WIN32s
:
835 os
= "31"; /* aka DOS + Windows 3.1 */
842 #define mingw_name "MINGW64"
844 #define mingw_name "MINGW32"
846 sprintf (buf
->sysname
, "%s_%s-%d.%d", mingw_name
,
847 os
, (int)osv
.dwMajorVersion
, (int)osv
.dwMinorVersion
);
850 int uname (struct utsname
*buf
) {
851 MLton_initSockets(); /* needed for gethostname */
854 unless (0 == gethostname (buf
->nodename
, sizeof (buf
->nodename
))) {
855 strcpy (buf
->nodename
, "unknown");
858 sprintf (buf
->release
, "%d", __MINGW64_VERSION_MINOR
);
859 sprintf (buf
->version
, "%d", __MINGW64_VERSION_MAJOR
);
861 sprintf (buf
->release
, "%d", __MINGW32_MINOR_VERSION
);
862 sprintf (buf
->version
, "%d", __MINGW32_MAJOR_VERSION
);
867 /* ------------------------------------------------- */
869 /* ------------------------------------------------- */
871 int alarm (int secs
) {
872 struct itimerval
new;
873 new.it_interval
.tv_usec
= 0;
874 new.it_interval
.tv_sec
= 0;
875 new.it_value
.tv_usec
= 0;
876 new.it_value
.tv_sec
= secs
;
877 return setitimer(ITIMER_REAL
, &new, 0);
880 __attribute__ ((noreturn
))
882 die ("fork not implemented");
885 int kill (pid_t pid
, int sig
) {
886 HANDLE h
= (HANDLE
)pid
;
887 unless (TerminateProcess (h
, SIGNALLED_BIT
| sig
)) {
894 int nanosleep (const struct timespec
*req
, struct timespec
*rem
) {
895 Sleep (req
->tv_sec
* 1000 + (req
->tv_nsec
+ 999999) / 1000000);
901 __attribute__ ((noreturn
))
903 die ("pause not implemented");
906 unsigned int sleep (unsigned int seconds
) {
907 Sleep (seconds
* 1000);
911 __attribute__ ((noreturn
))
912 pid_t
wait (__attribute__ ((unused
)) int *status
) {
913 die ("wait not implemented");
916 pid_t
waitpid (pid_t pid
, int *status
, int options
) {
920 /* pid <= 0 is handled in stub-mingw.sml */
923 delay
= ((options
& WNOHANG
) != 0) ? 0 : INFINITE
;
925 switch (WaitForSingleObject (h
, delay
)) {
926 case WAIT_OBJECT_0
: /* process has exited */
928 case WAIT_TIMEOUT
: /* process has not exited */
930 default: /* some sort of error */
935 unless (GetExitCodeProcess (h
, (DWORD
*)status
)) {
943 /* ------------------------------------------------- */
945 /* ------------------------------------------------- */
947 int sigaction (int signum
,
948 const struct sigaction
*newact
,
949 struct sigaction
*oldact
) {
952 if (signum
< 0 or signum
>= NSIG
) {
963 old
= SIGALRM_handler
;
964 if (newact
) SIGALRM_handler
= newact
->sa_handler
;
967 old
= SIGVTAM_handler
;
968 if (newact
) SIGVTAM_handler
= newact
->sa_handler
;
971 old
= SIGPROF_handler
;
972 if (newact
) SIGPROF_handler
= newact
->sa_handler
;
975 old
= signal (signum
, newact
?newact
->sa_handler
:0);
976 if (!newact
) signal (signum
, old
);
981 oldact
->sa_handler
= old
;
985 int sigaddset (sigset_t
*set
, const int signum
) {
986 if (signum
< 0 or signum
>= NSIG
) {
990 *set
|= SIGTOMASK (signum
);
994 int sigdelset (sigset_t
*set
, const int signum
) {
995 if (signum
< 0 or signum
>= NSIG
) {
999 *set
&= ~SIGTOMASK (signum
);
1003 int sigemptyset (sigset_t
*set
) {
1004 *set
= (sigset_t
) 0;
1008 int sigfillset (sigset_t
*set
) {
1009 *set
= ~((sigset_t
) 0);
1013 int sigismember (const sigset_t
*set
, const int signum
) {
1014 if (signum
< 0 or signum
>= NSIG
) {
1018 return (*set
& SIGTOMASK(signum
)) ? 1 : 0;
1022 /* With a bit of work and a redirected signal() function, we could
1023 * probably emulate these methods properly. AtM blocking is a lie.
1025 static sigset_t signals_blocked
= 0;
1026 static sigset_t signals_pending
= 0;
1028 int sigpending (sigset_t
*set
) {
1029 *set
= signals_pending
;
1033 int sigprocmask (int how
, const sigset_t
*set
, sigset_t
*oldset
) {
1035 *oldset
= signals_blocked
;
1038 sigset_t newmask
= signals_blocked
;
1042 /* add set to current mask */
1046 /* remove set from current mask */
1057 signals_blocked
= newmask
;
1062 __attribute__ ((noreturn
))
1063 int sigsuspend (__attribute__ ((unused
)) const sigset_t
*mask
) {
1064 die("sigsuspend is unimplemented, but could be hacked in if needed");
1067 /* ------------------------------------------------- */
1069 /* ------------------------------------------------- */
1071 void Posix_IO_setbin (C_Fd_t fd
) {
1072 _setmode (fd
, _O_BINARY
);
1075 void Posix_IO_settext (C_Fd_t fd
) {
1076 _setmode (fd
, _O_TEXT
);
1079 /* ------------------------------------------------- */
1080 /* Posix.SysDB.Passwd */
1081 /* ------------------------------------------------- */
1083 #define INFO_LEVEL 3
1084 static LPUSER_INFO_3 usrData
= NULL
;
1086 static struct passwd passwd
;
1088 __attribute__ ((noreturn
))
1089 struct group
*getgrgid (__attribute__ ((unused
)) gid_t gid
) {
1090 die ("getgrgid not implemented");
1093 __attribute__ ((noreturn
))
1094 struct group
*getgrnam (__attribute__ ((unused
)) const char *name
) {
1095 die ("getgrnam not implemented");
1098 struct passwd
*getpwnam (__attribute__ ((unused
)) const char *name
) {
1100 // unless (NERR_Success ==
1101 // NetUserGetInfo (NULL, (LPCWSTR)name, INFO_LEVEL,
1102 // (LPBYTE*)&usrData))
1104 passwd
.pw_dir
= (char*)usrData
->usri3_home_dir
;
1105 passwd
.pw_gid
= usrData
->usri3_primary_group_id
;
1106 passwd
.pw_name
= (char*)usrData
->usri3_name
;
1107 passwd
.pw_shell
= (char*)usrData
->usri3_script_path
;
1108 passwd
.pw_uid
= usrData
->usri3_user_id
;
1112 __attribute__ ((noreturn
))
1113 struct passwd
*getpwuid (__attribute__ ((unused
)) uid_t uid
) {
1114 die ("getpwuid not implemented");
1117 /* ------------------------------------------------- */
1119 /* ------------------------------------------------- */
1121 __attribute__ ((noreturn
))
1122 speed_t
cfgetispeed (__attribute__ ((unused
)) struct termios
*termios_p
) {
1123 die ("cfgetispeed not implemented");
1126 __attribute__ ((noreturn
))
1127 speed_t
cfgetospeed (__attribute__ ((unused
)) struct termios
*termios_p
) {
1128 die ("cfgetospeed not implemented");
1131 __attribute__ ((noreturn
))
1132 int cfsetispeed (__attribute__ ((unused
)) struct termios
*termios_p
,
1133 __attribute__ ((unused
)) speed_t speed
) {
1134 die ("cfsetispeed not implemented");
1137 __attribute__ ((noreturn
))
1138 int cfsetospeed (__attribute__ ((unused
)) struct termios
*termios_p
,
1139 __attribute__ ((unused
)) speed_t speed
) {
1140 die ("cfsetospeed not implemented");
1143 __attribute__ ((noreturn
))
1144 int tcdrain (__attribute__ ((unused
)) int fd
) {
1145 die ("tcdrain not implemented");
1148 __attribute__ ((noreturn
))
1149 int tcflow (__attribute__ ((unused
)) int fd
,
1150 __attribute__ ((unused
)) int action
) {
1151 die ("tcflow not implemented");
1154 __attribute__ ((noreturn
))
1155 int tcflush (__attribute__ ((unused
)) int fd
,
1156 __attribute__ ((unused
)) int queue_selector
) {
1157 die ("tcflush not implemented");
1160 __attribute__ ((noreturn
))
1161 int tcgetattr (__attribute__ ((unused
)) int fd
,
1162 __attribute__ ((unused
)) struct termios
*termios_p
) {
1163 die ("tcgetattr not implemented");
1166 __attribute__ ((noreturn
))
1167 pid_t
tcgetpgrp (__attribute__ ((unused
)) int fd
) {
1168 die ("tcgetpgrp not implemented");
1171 __attribute__ ((noreturn
))
1172 int tcsendbreak (__attribute__ ((unused
)) int fd
,
1173 __attribute__ ((unused
)) int duration
) {
1174 die ("tcsendbreak not implemented");
1177 __attribute__ ((noreturn
))
1178 int tcsetattr (__attribute__ ((unused
)) int fd
,
1179 __attribute__ ((unused
)) int optional_actions
,
1180 __attribute__ ((unused
)) struct termios
*termios_p
) {
1181 die ("tcsetattr not implemented");
1184 __attribute__ ((noreturn
))
1185 int tcsetpgrp (__attribute__ ((unused
)) int fd
,
1186 __attribute__ ((unused
)) pid_t pgrpid
) {
1187 die ("tcsetpgrp not implemented");
1190 /* ------------------------------------------------- */
1192 /* ------------------------------------------------- */
1194 __attribute__ ((noreturn
))
1195 int ioctl (__attribute__ ((unused
)) int d
,
1196 __attribute__ ((unused
)) int request
,
1198 die ("ioctl not implemented");
1201 __attribute__ ((noreturn
))
1202 int socketpair (__attribute__ ((unused
)) int d
,
1203 __attribute__ ((unused
)) int type
,
1204 __attribute__ ((unused
)) int protocol
,
1205 __attribute__ ((unused
)) int sv
[2]) {
1206 die ("socketpair not implemented");
1209 void MLton_initSockets (void) {
1210 static Bool isInitialized
= FALSE
;
1214 unless (isInitialized
) {
1215 isInitialized
= TRUE
;
1216 version
= MAKEWORD (2,2);
1217 WSAStartup (version
, &wsaData
);
1221 /* This table was constructed with help of
1222 * http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx#winsock.wsaenotsock_2
1225 void MLton_fixSocketErrno (void) {
1226 int status
= WSAGetLastError ();
1229 case 0: errno
= 0; break;
1230 case WSAEINTR
: errno
= EINTR
; break;
1231 case WSAEBADF
: errno
= EBADF
; break;
1232 case WSAEACCES
: errno
= EACCES
; break;
1233 case WSAEFAULT
: errno
= EFAULT
; break;
1234 case WSAEINVAL
: errno
= EINVAL
; break;
1235 case WSAEMFILE
: errno
= EMFILE
; break;
1236 case WSAEWOULDBLOCK
: errno
= EWOULDBLOCK
; break;
1237 case WSAEINPROGRESS
: errno
= EINPROGRESS
; break;
1238 case WSAEALREADY
: errno
= EALREADY
; break;
1239 case WSAENOTSOCK
: errno
= ENOTSOCK
; break;
1240 case WSAEDESTADDRREQ
: errno
= EDESTADDRREQ
; break;
1241 case WSAEMSGSIZE
: errno
= EMSGSIZE
; break;
1242 case WSAEPROTOTYPE
: errno
= EPROTOTYPE
; break;
1243 case WSAENOPROTOOPT
: errno
= ENOPROTOOPT
; break;
1244 case WSAEPROTONOSUPPORT
: errno
= EPROTONOSUPPORT
; break;
1245 case WSAESOCKTNOSUPPORT
: errno
= ESOCKTNOSUPPORT
; break;
1246 case WSAEOPNOTSUPP
: errno
= EOPNOTSUPP
; break;
1247 case WSAEPFNOSUPPORT
: errno
= EPFNOSUPPORT
; break;
1248 case WSAEAFNOSUPPORT
: errno
= EAFNOSUPPORT
; break;
1249 case WSAEADDRINUSE
: errno
= EADDRINUSE
; break;
1250 case WSAEADDRNOTAVAIL
: errno
= EADDRNOTAVAIL
; break;
1251 case WSAENETDOWN
: errno
= ENETDOWN
; break;
1252 case WSAENETUNREACH
: errno
= ENETUNREACH
; break;
1253 case WSAENETRESET
: errno
= ENETRESET
; break;
1254 case WSAECONNABORTED
: errno
= ECONNABORTED
; break;
1255 case WSAECONNRESET
: errno
= ECONNRESET
; break;
1256 case WSAENOBUFS
: errno
= ENOBUFS
; break;
1257 case WSAEISCONN
: errno
= EISCONN
; break;
1258 case WSAENOTCONN
: errno
= ENOTCONN
; break;
1259 case WSAESHUTDOWN
: errno
= ESHUTDOWN
; break;
1260 case WSAETIMEDOUT
: errno
= ETIMEDOUT
; break;
1261 case WSAECONNREFUSED
: errno
= ECONNREFUSED
; break;
1262 case WSAELOOP
: errno
= ELOOP
; break;
1263 case WSAENAMETOOLONG
: errno
= ENAMETOOLONG
; break;
1264 case WSAEHOSTDOWN
: errno
= EHOSTDOWN
; break;
1265 case WSAEHOSTUNREACH
: errno
= EHOSTUNREACH
; break;
1266 case WSAENOTEMPTY
: errno
= ENOTEMPTY
; break;
1267 case WSAEDQUOT
: errno
= EDQUOT
; break;
1268 case WSAESTALE
: errno
= ESTALE
; break;
1269 case WSAEREMOTE
: errno
= EREMOTE
; break;
1270 /* These codes appear to have a matching name, but the manual
1271 * descriptions of what the error codes mean seem to differ
1273 case WSAEUSERS
: errno
= EUSERS
; break;
1274 case WSAECANCELLED
: errno
= ECANCELED
; break;
1275 case WSA_E_CANCELLED
: errno
= ECANCELED
; break;
1276 /* These codes have no matching code in the errno(3) man page. */
1277 case WSAEPROCLIM
: errno
= EBUSY
; break;
1278 case WSAETOOMANYREFS
: errno
= ENOMEM
; break;
1279 case WSAEDISCON
: errno
= ESHUTDOWN
; break;
1282 case WSASYSCALLFAILURE
: errno
= EIO
; break;
1283 /* These codes are returned from the OS and subject to chage */
1284 // WSA_INVALID_HANDLE
1285 // WSA_NOT_ENOUGH_MEMORY
1286 // WSA_INVALID_PARAMETER
1287 // WSA_OPERATION_ABORTED
1288 // WSA_IO_INCOMPLETE
1290 /* These codes mean some sort of windows specific fatal error */
1291 case WSASYSNOTREADY
:
1292 case WSAVERNOTSUPPORTED
:
1293 case WSANOTINITIALISED
:
1294 case WSAEINVALIDPROCTABLE
:
1295 case WSAEINVALIDPROVIDER
:
1296 case WSAEPROVIDERFAILEDINIT
:
1297 case WSASERVICE_NOT_FOUND
:
1298 case WSATYPE_NOT_FOUND
:
1299 die("Problem loading winsock");
1301 case WSAHOST_NOT_FOUND
:
1303 case WSANO_RECOVERY
:
1305 die("Strange winsock specific status code");
1307 die("Unknown winsock status code");
1311 static const char *MLton_strerrorExtension(int code
) {
1313 case EINTR
: return "Interrupted function call";
1314 case EBADF
: return "Bad file descriptor";
1315 case EACCES
: return "Permission denied";
1316 case EFAULT
: return "Bad address";
1317 case EINVAL
: return "Invalid argument";
1318 case EMFILE
: return "Too many open files";
1319 case EAGAIN
: return "Resource temporarily unavailable";
1320 case EINPROGRESS
: return "Operation in progress";
1321 case EALREADY
: return "Connection already in progress";
1322 case ENOTSOCK
: return "Not a socket";
1323 case EDESTADDRREQ
: return "Destination address required";
1324 case EMSGSIZE
: return "Message too long";
1325 case EPROTOTYPE
: return "Protocol wrong type for socket";
1326 case ENOPROTOOPT
: return "Protocol not available";
1327 case EPROTONOSUPPORT
: return "Protocol not supported";
1328 case ESOCKTNOSUPPORT
: return "Socket type not supported";
1329 case EOPNOTSUPP
: return "Operation not supported on socket";
1330 case EPFNOSUPPORT
: return "Protocol family not supported";
1331 case EAFNOSUPPORT
: return "Address family not supported";
1332 case EADDRINUSE
: return "Address already in use";
1333 case EADDRNOTAVAIL
: return "Address not available";
1334 case ENETDOWN
: return "Network is down";
1335 case ENETUNREACH
: return "Network unreachable";
1336 case ENETRESET
: return "Connection aborted by network";
1337 case ECONNABORTED
: return "Connection aborted";
1338 case ECONNRESET
: return "Connection reset";
1339 case ENOBUFS
: return "No buffer space available";
1340 case EISCONN
: return "Socket is connected";
1341 case ENOTCONN
: return "The socket is not connected";
1342 case ESHUTDOWN
: return "Cannot send after transport endpoint shutdown";
1343 case ETIMEDOUT
: return "Connection timed out";
1344 case ECONNREFUSED
: return "Connection refused";
1345 case ELOOP
: return "Too many levels of symbolic links";
1346 case ENAMETOOLONG
: return "Filename too long";
1347 case EHOSTDOWN
: return "Host is down";
1348 case EHOSTUNREACH
: return "Host is unreachable";
1349 case ENOTEMPTY
: return "Directory not empty";
1350 case EDQUOT
: return "Disk quota exceeded";
1351 case ESTALE
: return "Stale file handle";
1352 case EREMOTE
: return "Object is remote";
1353 case EUSERS
: return "Too many users";
1354 case ECANCELED
: return "Operation canceled";
1355 default: return "Unknown error";
1359 /* MinGW strerror works for all system-defined errno values.
1360 * However, platform/mingw.h adds some missing POSIX networking error codes.
1361 * It defines these codes as their closest-equivalent winsock error code.
1362 * To report network errors, MLton_fixSocketErrno maps winsock errors to
1363 * their closest POSIX errno value.
1365 * This function must handle the winsock errno values we have added.
1366 * FormatMessage doesn't return the POSIX string for errors, and it uses
1367 * the current locale's language. The MinGW strerror is always English.
1369 * Thus, we just make a big English table to augment strerror.
1370 * The descriptions are taken from man errno(3).
1372 char *MLton_strerror(int code
) {
1373 static char buffer
[80];
1376 if (code
< sys_nerr
) return strerror(code
);
1377 #define strerror MLton_strerror
1379 strcpy(buffer
, MLton_strerrorExtension(code
));
1383 int MLton_recv(int s
, void *buf
, int len
, int flags
) {
1384 int ret
, status
= 0;
1386 if (flags
& MSG_DONTWAIT
) MinGW_setNonBlock(s
);
1387 ret
= recv(s
, buf
, len
, flags
& ~MSG_DONTWAIT
);
1389 /* We need to preserve the error status across non-blocking call */
1390 if (ret
== -1) status
= WSAGetLastError();
1391 if (flags
& MSG_DONTWAIT
) MinGW_clearNonBlock(s
);
1392 if (ret
== -1) WSASetLastError(status
);
1397 int MLton_recvfrom(int s
, void *buf
, int len
, int flags
, void *from
,
1398 socklen_t
*fromlen
) {
1399 int ret
, status
= 0;
1401 if (flags
& MSG_DONTWAIT
) MinGW_setNonBlock(s
);
1402 ret
= recvfrom(s
, buf
, len
, flags
& ~MSG_DONTWAIT
, from
, fromlen
);
1404 /* We need to preserve the error status across non-blocking call */
1405 if (ret
== -1) status
= WSAGetLastError();
1406 if (flags
& MSG_DONTWAIT
) MinGW_clearNonBlock(s
);
1407 if (ret
== -1) WSASetLastError(status
);
1411 /* ------------------------------------------------- */
1413 /* ------------------------------------------------- */
1415 static const char* logident
= "<unknown>";
1416 static int logopt
= LOG_PERROR
;
1417 static int logfacility
= LOG_LOCAL0
;
1419 void openlog(const char* ident
, int opt
, int facility
) {
1422 logfacility
= facility
;
1425 void closelog(void) {
1428 void syslog(int priority
, __attribute__ ((unused
)) const char* fmt
, const char* msg
) {
1429 static const char* severity
[] = {
1440 if (priority
< 0) priority
= LOG_DEBUG
;
1441 if (priority
> LOG_EMERG
) priority
= LOG_EMERG
;
1444 /* !!! Use ReportEvent to log with windows */
1446 if ((logopt
& LOG_PERROR
) != 0) {
1447 if ((logopt
& LOG_PID
) != 0)
1448 fprintf(stderr
, "%s(%d): %s: %s\n", logident
, getpid(), severity
[priority
], msg
);
1450 fprintf(stderr
, "%s: %s: %s\n", logident
, severity
[priority
], msg
);
1454 /* ------------------------------------------------- */
1456 /* ------------------------------------------------- */
1458 C_Size_t
MinGW_getTempPath(C_Size_t buf_size
, Array(Char8_t
) buf
) {
1459 return GetTempPath(buf_size
, (char*)buf
);
1462 void MinGW_setNonBlock(C_Fd_t fd
) {
1463 unsigned long yes
= 1;
1464 ioctlsocket(fd
, FIONBIO
, &yes
);
1467 void MinGW_clearNonBlock(C_Fd_t fd
) {
1468 unsigned long no
= 0;
1469 ioctlsocket(fd
, FIONBIO
, &no
);