Import Upstream version 20180207
[hcoop/debian/mlton.git] / runtime / platform / mingw.c
1 #define _GNU_SOURCE
2
3 #include "platform.h"
4
5 #include "windows.c"
6 #include "mremap.c"
7
8 void *GC_mmapAnon (void *start, size_t length) {
9 return Windows_mmapAnon (start, length);
10 }
11
12 void GC_release (void *base, size_t length) {
13 Windows_release (base, length);
14 }
15
16 void *GC_extendHead (void *base, size_t length) {
17 return Windows_mmapAnon (base, length);
18 }
19
20 void *GC_extendTail (void *base, size_t length) {
21 return Windows_extend (base, length);
22 }
23
24 uintmax_t GC_physMem (void) {
25 #ifdef _WIN64
26 MEMORYSTATUSEX memstat;
27 memstat.dwLength = sizeof(memstat);
28 GlobalMemoryStatusEx(&memstat);
29 return (uintmax_t)memstat.ullTotalPhys;
30 #else
31 MEMORYSTATUS memstat;
32 memstat.dwLength = sizeof(memstat);
33 GlobalMemoryStatus(&memstat);
34 return (uintmax_t)memstat.dwTotalPhys;
35 #endif
36 }
37
38 size_t GC_pageSize (void) {
39 SYSTEM_INFO sysinfo;
40 GetSystemInfo(&sysinfo);
41 return (size_t)sysinfo.dwAllocationGranularity;
42 }
43
44 HANDLE fileDesHandle (int fd) {
45 // The temporary prevents a "cast does not match function type" warning.
46 intptr_t t;
47
48 t = _get_osfhandle (fd);
49 return (HANDLE)t;
50 }
51
52 int mkstemp (char *template) {
53 char file_path[255];
54 char file_name[255];
55 char templ[4];
56
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);
64 }
65
66 /* ------------------------------------------------- */
67 /* Date */
68 /* ------------------------------------------------- */
69
70 #ifndef __GNUC__
71 #define EPOCHFILETIME (116444736000000000i64)
72 #else
73 #define EPOCHFILETIME (116444736000000000LL)
74 #endif
75
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.
82 *
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.
86 *
87 * This function only strives to allow a program to run for
88 * 100 years without being restarted.
89 */
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 */
95
96 LARGE_INTEGER nowCounter;
97 LARGE_INTEGER deltaCounter;
98 LARGE_INTEGER nowMicroSeconds;
99 double deltaMicroseconds;
100
101 /* This code is run the first time gettimeofday is called. */
102 if (frequency.QuadPart == 0) {
103 FILETIME ft;
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.
108 */
109 tzset();
110
111 QueryPerformanceCounter(&baseCounter);
112 QueryPerformanceFrequency(&frequency);
113 if (frequency.QuadPart == 0)
114 die("no high resolution clock");
115
116 GetSystemTimeAsFileTime (&ft);
117 baseMicroSeconds.LowPart = ft.dwLowDateTime;
118 baseMicroSeconds.HighPart = ft.dwHighDateTime;
119 baseMicroSeconds.QuadPart -= EPOCHFILETIME;
120 baseMicroSeconds.QuadPart /= 10; /* 100ns -> 1ms */
121 }
122
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.
127 */
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;
135
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.
139 */
140 if (frequency.HighPart != 0) {
141 LARGE_INTEGER nowLowResMicroSeconds;
142 FILETIME ft;
143
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;
150
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.
155 */
156 if (nowMicroSeconds.QuadPart + 1000000 < nowLowResMicroSeconds.QuadPart) {
157 baseCounter = nowCounter;
158 baseMicroSeconds = nowLowResMicroSeconds;
159 nowMicroSeconds = nowLowResMicroSeconds;
160 }
161
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.
167 */
168 if ((deltaCounter.HighPart & 0xffff0000UL) != 0) {
169 baseCounter = nowCounter;
170 baseMicroSeconds = nowMicroSeconds;
171 }
172 }
173
174 tv->tv_sec = (long)(nowMicroSeconds.QuadPart / 1000000);
175 tv->tv_usec = (long)(nowMicroSeconds.QuadPart % 1000000);
176
177 return 0;
178 }
179
180 /* ------------------------------------------------- */
181 /* MLton.Itimer */
182 /* ------------------------------------------------- */
183
184 /* We use the kernel's TimerQueues -- see:
185 * http://msdn.microsoft.com/en-us/library/ms686796(VS.85).aspx
186 */
187
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;
197
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.
205 */
206
207 static VOID CALLBACK MLton_SIGALRM(__attribute__ ((unused)) PVOID myArg,
208 __attribute__ ((unused)) BOOLEAN timeout) {
209 SuspendThread(MainThread);
210 if (SIGALRM_handler == SIG_IGN) {
211 /* noop */
212 } else if (SIGALRM_handler == SIG_DFL) {
213 die("alarm");
214 } else {
215 (*SIGALRM_handler)(SIGALRM);
216 }
217 ResumeThread(MainThread);
218 }
219 static VOID CALLBACK MLton_SIGVTAM(__attribute__ ((unused)) PVOID myArg,
220 __attribute__ ((unused)) BOOLEAN timeout) {
221 SuspendThread(MainThread);
222 if (SIGVTAM_handler == SIG_IGN) {
223 /* noop */
224 } else if (SIGVTAM_handler == SIG_DFL) {
225 die("vtalarm");
226 } else {
227 (*SIGVTAM_handler)(SIGVTALRM);
228 }
229 ResumeThread(MainThread);
230 }
231 static VOID CALLBACK MLton_SIGPROF(__attribute__ ((unused)) PVOID myArg,
232 __attribute__ ((unused)) BOOLEAN timeout) {
233 SuspendThread(MainThread);
234 if (SIGPROF_handler == SIG_IGN) {
235 /* noop */
236 } else if (SIGPROF_handler == SIG_DFL) {
237 die("sigprof");
238 } else {
239 (*SIGPROF_handler)(SIGPROF);
240 }
241 ResumeThread(MainThread);
242 }
243
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);
248 }
249
250 static int MLTimer(HANDLE *timer,
251 const struct itimerval *value,
252 WAITORTIMERCALLBACK callback) {
253 DWORD DueTime, Period;
254
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.
259 */
260 timeBeginPeriod(1);
261
262 TimerQueue = CreateTimerQueue();
263 if (TimerQueue == NULL) { errno = ENOMEM; return -1; }
264
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.
270 */
271 CreateTimerQueueTimer(&PrioTimer, TimerQueue, fixPriority,
272 0, 1, 0, WT_EXECUTEINTIMERTHREAD);
273
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.
277 */
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);
285
286 if (MainThread == 0) die("Cannot get handle to initial thread");
287 }
288
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;
294
295 if (timer != NULL) {
296 DeleteTimerQueueTimer(TimerQueue, *timer, NULL);
297 *timer = NULL;
298 }
299
300 if (DueTime == 0) {
301 return 0;
302 }
303
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 */
312 errno = ENOMEM;
313 return -1;
314 }
315
316 return 0;
317 }
318
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");
323
324 switch (which) {
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;
329 }
330
331 }
332
333 static void catcher(__attribute__ ((unused)) int signo) {
334 CONTEXT context;
335 context.ContextFlags = CONTEXT_CONTROL;
336
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);
342 #elif defined(_PPC_)
343 GC_handleSigProf((code_pointer) context.Iar);
344 #elif defined(_ALPHA_)
345 GC_handleSigProf((code_pointer) context.Fir);
346 #elif defined(MIPS)
347 GC_handleSigProf((code_pointer) context.Fir);
348 #elif defined(ARM)
349 GC_handleSigProf((code_pointer) context.Pc);
350 #else
351 #error Profiling handler is missing for this architecture
352 #endif
353 }
354
355 void GC_setSigProfHandler (struct sigaction *sa) {
356 sa->sa_flags = 0;
357 sa->sa_handler = (_sig_func_ptr)&catcher;
358 }
359
360 /* ------------------------------------------------- */
361 /* MLton.Rlimit */
362 /* ------------------------------------------------- */
363
364 static struct rlimit rlimits[RLIM_NLIMITS];
365
366 static void initRlimits (void) {
367 static int done = FALSE;
368 int lim;
369
370 if (done)
371 return;
372 done = TRUE;
373 for (lim = 0; lim < RLIM_NLIMITS; ++lim ) {
374 rlimits[lim].rlim_cur = 0;
375 rlimits[lim].rlim_max = UINT_MAX;
376 }
377 }
378
379 int getrlimit (int resource, struct rlimit *rlp) {
380 initRlimits ();
381 if (resource < 0 or resource >= RLIM_NLIMITS) {
382 errno = EINVAL;
383 return -1;
384 }
385 *rlp = rlimits[resource];
386 return 0;
387 }
388
389 int setrlimit (int resource, const struct rlimit *rlp) {
390 initRlimits ();
391 if (resource < 0 or resource >= RLIM_NLIMITS) {
392 errno = EINVAL;
393 return -1;
394 }
395 if (rlp->rlim_cur < rlimits[resource].rlim_max)
396 rlimits[resource].rlim_cur = rlp->rlim_cur;
397 else {
398 errno = EPERM;
399 return -1;
400 }
401 rlimits[resource].rlim_max = rlp->rlim_max;
402 return 0;
403 }
404
405 /* ------------------------------------------------- */
406 /* MLton.Rusage */
407 /* ------------------------------------------------- */
408
409 /* GetProcessTimes and GetSystemTimeAsFileTime are documented at:
410 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocesstimes.asp
411 */
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
415 */
416 FILETIME creation_time;
417 FILETIME exit_time;
418 FILETIME kernel_time;
419 FILETIME user_time;
420
421 uint64_t user_usecs, kernel_usecs;
422
423 if (who == RUSAGE_CHILDREN) {
424 // !!! could use exit_time - creation_time from cwait
425 memset(usage, 0, sizeof(struct rusage));
426 return 0;
427 }
428
429 if (who != RUSAGE_SELF) {
430 errno = EINVAL;
431 return -1;
432 }
433
434 if (GetProcessTimes(GetCurrentProcess(),
435 &creation_time, &exit_time,
436 &kernel_time, &user_time) == 0) {
437 errno = EFAULT;
438 return -1;
439 }
440
441 kernel_usecs = kernel_time.dwHighDateTime;
442 kernel_usecs <<= sizeof(kernel_time.dwHighDateTime)*8;
443 kernel_usecs |= kernel_time.dwLowDateTime;
444 kernel_usecs /= 10;
445
446 user_usecs = user_time.dwHighDateTime;
447 user_usecs <<= sizeof(user_time.dwHighDateTime)*8;
448 user_usecs |= user_time.dwLowDateTime;
449 user_usecs /= 10;
450
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;
455 return 0;
456 }
457
458 /* ------------------------------------------------- */
459 /* OS.IO */
460 /* ------------------------------------------------- */
461
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");
467 }
468
469 /* ------------------------------------------------- */
470 /* Posix.FileSys */
471 /* ------------------------------------------------- */
472
473 static void GetWin32FileName (int fd, char* fname) {
474 HANDLE fh, fhmap;
475 DWORD fileSize, fileSizeHi;
476 void* pMem = NULL;
477 intptr_t tmp;
478
479 tmp = _get_osfhandle (fd);
480 fh = (HANDLE)tmp;
481 fileSize = GetFileSize (fh, &fileSizeHi);
482 fhmap = CreateFileMapping (fh, NULL, PAGE_READONLY, 0, fileSize, NULL);
483 if (fhmap) {
484 pMem = MapViewOfFile (fhmap, FILE_MAP_READ, 0, 0, 1);
485 if (pMem) {
486 GetMappedFileNameA (GetCurrentProcess(),
487 pMem, fname, MAX_PATH);
488 UnmapViewOfFile (pMem);
489 }
490 CloseHandle (fhmap);
491 }
492 }
493
494 int fchmod (int filedes, mode_t mode) {
495 char fname[MAX_PATH + 1];
496
497 GetWin32FileName (filedes, fname);
498 return _chmod (fname, mode);
499 }
500
501 int fchdir (int filedes) {
502 char fname[MAX_PATH + 1];
503
504 GetWin32FileName (filedes, fname);
505 return chdir (fname);
506 }
507
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");
513 }
514
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");
520 }
521
522 __attribute__ ((noreturn))
523 long fpathconf (__attribute__ ((unused)) int filedes,
524 __attribute__ ((unused)) int name) {
525 die ("fpathconf not implemented");
526 }
527
528 __attribute__ ((noreturn))
529 int link (__attribute__ ((unused)) const char *oldpath,
530 __attribute__ ((unused)) const char *newpath) {
531 die ("link not implemented");
532 }
533
534 int lstat (const char *file_name, struct stat *buf) {
535 /* Win32 doesn't really have links. */
536 return stat (file_name, buf);
537 }
538
539 __attribute__ ((noreturn))
540 int mkfifo (__attribute__ ((unused)) const char *pathname,
541 __attribute__ ((unused)) mode_t mode) {
542 die ("mkfifo not implemented");
543 }
544
545 __attribute__ ((noreturn))
546 long pathconf (__attribute__ ((unused)) const char *path,
547 __attribute__ ((unused)) int name) {
548 die ("pathconf not implemented");
549 }
550
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");
556 }
557
558 __attribute__ ((noreturn))
559 int symlink (__attribute__ ((unused)) const char *oldpath,
560 __attribute__ ((unused)) const char *newpath) {
561 die ("symlink not implemented");
562 }
563
564 int truncate (const char *path, off_t len) {
565 int fd;
566
567 if ((fd = open(path, O_RDWR)) == -1)
568 return -1;
569 if (ftruncate(fd, len) < 0) {
570 close(fd);
571 return -1;
572 }
573 close(fd);
574 return 0;
575 }
576
577
578 /* ------------------------------------------------- */
579 /* Posix.IO */
580 /* ------------------------------------------------- */
581
582 __attribute__ ((noreturn))
583 int fcntl (__attribute__ ((unused)) int fd,
584 __attribute__ ((unused)) int cmd,
585 ...) {
586 die ("fcntl not implemented");
587 }
588
589 int fsync (int fd) {
590 return _commit (fd);
591 }
592
593 int pipe (int filedes[2]) {
594 HANDLE read_h;
595 HANDLE write_h;
596
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.
601 */
602 if (!CreatePipe(&read_h, &write_h, 0, 4096)) {
603 errno = ENOMEM; /* fake errno: out of resources */
604 return -1;
605 }
606 /* This requires Win98+
607 * Choosing text/binary mode is defered till a later setbin/text call
608 */
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)
613 CloseHandle(read_h);
614 else close(filedes[0]);
615 if (filedes[1] == -1)
616 CloseHandle(write_h);
617 else close(filedes[1]);
618
619 errno = ENFILE;
620 return -1;
621 }
622 return 0;
623 }
624
625 /* ------------------------------------------------- */
626 /* Posix.ProcEnv */
627 /* ------------------------------------------------- */
628
629 __attribute__ ((noreturn))
630 char *ctermid (__attribute__ ((unused)) char* s) {
631 die ("*ctermid not implemented");
632 }
633
634 __attribute__ ((noreturn))
635 gid_t getegid (void) {
636 die ("getegid not implemented");
637 }
638
639 __attribute__ ((noreturn))
640 uid_t geteuid (void) {
641 die ("geteuid not implemented");
642 }
643
644 __attribute__ ((noreturn))
645 gid_t getgid (void) {
646 die ("getgid not implemented");
647 }
648
649 __attribute__ ((noreturn))
650 int getgroups (__attribute__ ((unused)) int size,
651 __attribute__ ((unused)) gid_t list[]) {
652 die ("getgroups not implemented");
653 }
654
655 __attribute__ ((noreturn))
656 char *getlogin (void) {
657 die ("getlogin not implemented");
658 }
659
660 __attribute__ ((noreturn))
661 pid_t getpgid(__attribute__ ((unused)) pid_t pid) {
662 die ("getpgid not implemented");
663 }
664
665 __attribute__ ((noreturn))
666 pid_t getpgrp(void) {
667 die ("getpgrp not implemented");
668 }
669
670 __attribute__ ((noreturn))
671 pid_t getppid (void) {
672 die ("getppid not implemented");
673 }
674
675 __attribute__ ((noreturn))
676 uid_t getuid (void) {
677 die ("getuid not implemented");
678 }
679
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.
683 */
684 if (not overwrite and getenv (name)) {
685 errno = EEXIST;
686 return -1; /* previous mingw setenv was buggy and returned 0 */
687 }
688
689 if (SetEnvironmentVariable (name, value)) {
690 errno = ENOMEM; /* this happens often in Windows.. */
691 return -1;
692 }
693
694 return 0;
695 }
696
697 __attribute__ ((noreturn))
698 int setgid (__attribute__ ((unused)) gid_t gid) {
699 die ("setgid not implemented");
700 }
701
702 __attribute__ ((noreturn))
703 int setgroups (__attribute__ ((unused)) size_t size,
704 __attribute__ ((unused)) const gid_t *list) {
705 die ("setgroups not implemented");
706 }
707
708 __attribute__ ((noreturn))
709 int setpgid (__attribute__ ((unused)) pid_t pid,
710 __attribute__ ((unused)) pid_t pgid) {
711 die ("setpgid not implemented");
712 }
713
714 __attribute__ ((noreturn))
715 pid_t setsid (void) {
716 die ("setsid not implemented");
717 }
718
719 __attribute__ ((noreturn))
720 int setuid (__attribute__ ((unused)) uid_t uid) {
721 die ("setuid not implemented");
722 }
723
724 __attribute__ ((noreturn))
725 long sysconf (__attribute__ ((unused)) int name) {
726 die ("sysconf not implemented");
727 }
728
729 __attribute__ ((noreturn))
730 clock_t times (__attribute__ ((unused)) struct tms *buf) {
731 die ("times not implemented");
732 }
733
734 __attribute__ ((noreturn))
735 char *ttyname (__attribute__ ((unused)) int desc) {
736 die ("*ttyname not implemented");
737 }
738
739 static void setMachine (struct utsname *buf) {
740 int level;
741 const char* platform = "unknown";
742 SYSTEM_INFO si;
743
744 GetSystemInfo (&si);
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;
750 platform = "i%d86";
751 break;
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;
761 }
762 sprintf (buf->machine, platform, level);
763 }
764
765 static void setSysname (struct utsname *buf) {
766 OSVERSIONINFOEX osv;
767 const char* os = "??";
768
769 #ifndef _WIN64
770 /* Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. */
771 SYSTEM_INFO si;
772 void (WINAPI *pGNSI)(LPSYSTEM_INFO);
773 pGNSI = (void(WINAPI *)(LPSYSTEM_INFO))
774 GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
775 "GetNativeSystemInfo");
776 if (NULL != pGNSI)
777 pGNSI(&si);
778 else
779 GetSystemInfo(&si);
780 #endif
781
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);
789 }
790 switch (osv.dwPlatformId) {
791 case VER_PLATFORM_WIN32_NT:
792 #ifdef _WIN64
793 if (osv.dwMinorVersion == 0) {
794 if (osv.dwMajorVersion <= 6) {
795 if (osv.wProductType == VER_NT_WORKSTATION)
796 os = "Vista_64";
797 else
798 os = "2008_64";
799 } else os = "NTx_64";
800 } else if (osv.dwMinorVersion <= 2) os = "XP_64";
801 else os = "NTx_64";
802 #else
803 if (osv.dwMinorVersion == 0) {
804 if (osv.dwMajorVersion <= 4) os = "NT";
805 else if (osv.dwMajorVersion <= 5) os = "2000";
806 else {
807 if (osv.wProductType == VER_NT_WORKSTATION) {
808 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
809 os = "Vista_WOW64";
810 else
811 os = "Vista";
812 } else {
813 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
814 os = "2008";
815 else
816 os = "2008_WOW64";
817 }
818 }
819 } else if (osv.dwMinorVersion <= 1) os = "XP";
820 else if (osv.dwMinorVersion <= 2) {
821 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
822 os = "XP_WOW64";
823 else
824 os = "2003";
825 } else os = "NTx";
826 #endif
827 break;
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";
832 else os = "9X";
833 break;
834 case VER_PLATFORM_WIN32s:
835 os = "31"; /* aka DOS + Windows 3.1 */
836 break;
837 default:
838 os = "unknown";
839 break;
840 }
841 #ifdef _WIN64
842 #define mingw_name "MINGW64"
843 #else
844 #define mingw_name "MINGW32"
845 #endif
846 sprintf (buf->sysname, "%s_%s-%d.%d", mingw_name,
847 os, (int)osv.dwMajorVersion, (int)osv.dwMinorVersion);
848 }
849
850 int uname (struct utsname *buf) {
851 MLton_initSockets(); /* needed for gethostname */
852 setMachine (buf);
853 setSysname (buf);
854 unless (0 == gethostname (buf->nodename, sizeof (buf->nodename))) {
855 strcpy (buf->nodename, "unknown");
856 }
857 #ifdef _WIN64
858 sprintf (buf->release, "%d", __MINGW64_VERSION_MINOR);
859 sprintf (buf->version, "%d", __MINGW64_VERSION_MAJOR);
860 #else
861 sprintf (buf->release, "%d", __MINGW32_MINOR_VERSION);
862 sprintf (buf->version, "%d", __MINGW32_MAJOR_VERSION);
863 #endif
864 return 0;
865 }
866
867 /* ------------------------------------------------- */
868 /* Posix.Process */
869 /* ------------------------------------------------- */
870
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);
878 }
879
880 __attribute__ ((noreturn))
881 int fork (void) {
882 die ("fork not implemented");
883 }
884
885 int kill (pid_t pid, int sig) {
886 HANDLE h = (HANDLE)pid;
887 unless (TerminateProcess (h, SIGNALLED_BIT | sig)) {
888 errno = ECHILD;
889 return -1;
890 }
891 return 0;
892 }
893
894 int nanosleep (const struct timespec *req, struct timespec *rem) {
895 Sleep (req->tv_sec * 1000 + (req->tv_nsec + 999999) / 1000000);
896 rem->tv_nsec = 0;
897 rem->tv_sec = 0;
898 return 0;
899 }
900
901 __attribute__ ((noreturn))
902 int pause (void) {
903 die ("pause not implemented");
904 }
905
906 unsigned int sleep (unsigned int seconds) {
907 Sleep (seconds * 1000);
908 return 0;
909 }
910
911 __attribute__ ((noreturn))
912 pid_t wait (__attribute__ ((unused)) int *status) {
913 die ("wait not implemented");
914 }
915
916 pid_t waitpid (pid_t pid, int *status, int options) {
917 HANDLE h;
918 DWORD delay;
919
920 /* pid <= 0 is handled in stub-mingw.sml */
921 h = (HANDLE)pid;
922
923 delay = ((options & WNOHANG) != 0) ? 0 : INFINITE;
924
925 switch (WaitForSingleObject (h, delay)) {
926 case WAIT_OBJECT_0: /* process has exited */
927 break;
928 case WAIT_TIMEOUT: /* process has not exited */
929 return 0;
930 default: /* some sort of error */
931 errno = ECHILD;
932 return -1;
933 }
934
935 unless (GetExitCodeProcess (h, (DWORD*)status)) {
936 errno = ECHILD;
937 return -1;
938 }
939
940 return pid;
941 }
942
943 /* ------------------------------------------------- */
944 /* Signals */
945 /* ------------------------------------------------- */
946
947 int sigaction (int signum,
948 const struct sigaction *newact,
949 struct sigaction *oldact) {
950 _sig_func_ptr old;
951
952 if (signum < 0 or signum >= NSIG) {
953 errno = EINVAL;
954 return -1;
955 }
956
957 switch (signum) {
958 case SIGKILL:
959 case SIGSTOP:
960 errno = EINVAL;
961 return -1;
962 case SIGALRM:
963 old = SIGALRM_handler;
964 if (newact) SIGALRM_handler = newact->sa_handler;
965 break;
966 case SIGVTALRM:
967 old = SIGVTAM_handler;
968 if (newact) SIGVTAM_handler = newact->sa_handler;
969 break;
970 case SIGPROF:
971 old = SIGPROF_handler;
972 if (newact) SIGPROF_handler = newact->sa_handler;
973 break;
974 default:
975 old = signal (signum, newact?newact->sa_handler:0);
976 if (!newact) signal (signum, old);
977 break;
978 }
979
980 if (oldact)
981 oldact->sa_handler = old;
982 return 0;
983 }
984
985 int sigaddset (sigset_t *set, const int signum) {
986 if (signum < 0 or signum >= NSIG) {
987 errno = EINVAL;
988 return -1;
989 }
990 *set |= SIGTOMASK (signum);
991 return 0;
992 }
993
994 int sigdelset (sigset_t *set, const int signum) {
995 if (signum < 0 or signum >= NSIG) {
996 errno = EINVAL;
997 return -1;
998 }
999 *set &= ~SIGTOMASK (signum);
1000 return 0;
1001 }
1002
1003 int sigemptyset (sigset_t *set) {
1004 *set = (sigset_t) 0;
1005 return 0;
1006 }
1007
1008 int sigfillset (sigset_t *set) {
1009 *set = ~((sigset_t) 0);
1010 return 0;
1011 }
1012
1013 int sigismember (const sigset_t *set, const int signum) {
1014 if (signum < 0 or signum >= NSIG) {
1015 errno = EINVAL;
1016 return -1;
1017 }
1018 return (*set & SIGTOMASK(signum)) ? 1 : 0;
1019 }
1020
1021
1022 /* With a bit of work and a redirected signal() function, we could
1023 * probably emulate these methods properly. AtM blocking is a lie.
1024 */
1025 static sigset_t signals_blocked = 0;
1026 static sigset_t signals_pending = 0;
1027
1028 int sigpending (sigset_t *set) {
1029 *set = signals_pending;
1030 return 0;
1031 }
1032
1033 int sigprocmask (int how, const sigset_t *set, sigset_t *oldset) {
1034 if (oldset) {
1035 *oldset = signals_blocked;
1036 }
1037 if (set) {
1038 sigset_t newmask = signals_blocked;
1039
1040 switch (how) {
1041 case SIG_BLOCK:
1042 /* add set to current mask */
1043 newmask |= *set;
1044 break;
1045 case SIG_UNBLOCK:
1046 /* remove set from current mask */
1047 newmask &= ~*set;
1048 break;
1049 case SIG_SETMASK:
1050 /* just set it */
1051 newmask = *set;
1052 break;
1053 default:
1054 return -1;
1055 }
1056
1057 signals_blocked = newmask;
1058 }
1059 return 0;
1060 }
1061
1062 __attribute__ ((noreturn))
1063 int sigsuspend (__attribute__ ((unused)) const sigset_t *mask) {
1064 die("sigsuspend is unimplemented, but could be hacked in if needed");
1065 }
1066
1067 /* ------------------------------------------------- */
1068 /* Posix.IO */
1069 /* ------------------------------------------------- */
1070
1071 void Posix_IO_setbin (C_Fd_t fd) {
1072 _setmode (fd, _O_BINARY);
1073 }
1074
1075 void Posix_IO_settext (C_Fd_t fd) {
1076 _setmode (fd, _O_TEXT);
1077 }
1078
1079 /* ------------------------------------------------- */
1080 /* Posix.SysDB.Passwd */
1081 /* ------------------------------------------------- */
1082
1083 #define INFO_LEVEL 3
1084 static LPUSER_INFO_3 usrData = NULL;
1085
1086 static struct passwd passwd;
1087
1088 __attribute__ ((noreturn))
1089 struct group *getgrgid (__attribute__ ((unused)) gid_t gid) {
1090 die ("getgrgid not implemented");
1091 }
1092
1093 __attribute__ ((noreturn))
1094 struct group *getgrnam (__attribute__ ((unused)) const char *name) {
1095 die ("getgrnam not implemented");
1096 }
1097
1098 struct passwd *getpwnam (__attribute__ ((unused)) const char *name) {
1099 return NULL;
1100 // unless (NERR_Success ==
1101 // NetUserGetInfo (NULL, (LPCWSTR)name, INFO_LEVEL,
1102 // (LPBYTE*)&usrData))
1103 // return NULL;
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;
1109 return &passwd;
1110 }
1111
1112 __attribute__ ((noreturn))
1113 struct passwd *getpwuid (__attribute__ ((unused)) uid_t uid) {
1114 die ("getpwuid not implemented");
1115 }
1116
1117 /* ------------------------------------------------- */
1118 /* Posix.TTY */
1119 /* ------------------------------------------------- */
1120
1121 __attribute__ ((noreturn))
1122 speed_t cfgetispeed (__attribute__ ((unused)) struct termios *termios_p) {
1123 die ("cfgetispeed not implemented");
1124 }
1125
1126 __attribute__ ((noreturn))
1127 speed_t cfgetospeed (__attribute__ ((unused)) struct termios *termios_p) {
1128 die ("cfgetospeed not implemented");
1129 }
1130
1131 __attribute__ ((noreturn))
1132 int cfsetispeed (__attribute__ ((unused)) struct termios *termios_p,
1133 __attribute__ ((unused)) speed_t speed) {
1134 die ("cfsetispeed not implemented");
1135 }
1136
1137 __attribute__ ((noreturn))
1138 int cfsetospeed (__attribute__ ((unused)) struct termios *termios_p,
1139 __attribute__ ((unused)) speed_t speed) {
1140 die ("cfsetospeed not implemented");
1141 }
1142
1143 __attribute__ ((noreturn))
1144 int tcdrain (__attribute__ ((unused)) int fd) {
1145 die ("tcdrain not implemented");
1146 }
1147
1148 __attribute__ ((noreturn))
1149 int tcflow (__attribute__ ((unused)) int fd,
1150 __attribute__ ((unused)) int action) {
1151 die ("tcflow not implemented");
1152 }
1153
1154 __attribute__ ((noreturn))
1155 int tcflush (__attribute__ ((unused)) int fd,
1156 __attribute__ ((unused)) int queue_selector) {
1157 die ("tcflush not implemented");
1158 }
1159
1160 __attribute__ ((noreturn))
1161 int tcgetattr (__attribute__ ((unused)) int fd,
1162 __attribute__ ((unused)) struct termios *termios_p) {
1163 die ("tcgetattr not implemented");
1164 }
1165
1166 __attribute__ ((noreturn))
1167 pid_t tcgetpgrp (__attribute__ ((unused)) int fd) {
1168 die ("tcgetpgrp not implemented");
1169 }
1170
1171 __attribute__ ((noreturn))
1172 int tcsendbreak (__attribute__ ((unused)) int fd,
1173 __attribute__ ((unused)) int duration) {
1174 die ("tcsendbreak not implemented");
1175 }
1176
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");
1182 }
1183
1184 __attribute__ ((noreturn))
1185 int tcsetpgrp (__attribute__ ((unused)) int fd,
1186 __attribute__ ((unused)) pid_t pgrpid) {
1187 die ("tcsetpgrp not implemented");
1188 }
1189
1190 /* ------------------------------------------------- */
1191 /* Socket */
1192 /* ------------------------------------------------- */
1193
1194 __attribute__ ((noreturn))
1195 int ioctl (__attribute__ ((unused)) int d,
1196 __attribute__ ((unused)) int request,
1197 ...) {
1198 die ("ioctl not implemented");
1199 }
1200
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");
1207 }
1208
1209 void MLton_initSockets (void) {
1210 static Bool isInitialized = FALSE;
1211 WORD version;
1212 WSADATA wsaData;
1213
1214 unless (isInitialized) {
1215 isInitialized = TRUE;
1216 version = MAKEWORD (2,2);
1217 WSAStartup (version, &wsaData);
1218 }
1219 }
1220
1221 /* This table was constructed with help of
1222 * http://msdn.microsoft.com/en-us/library/ms740668(VS.85).aspx#winsock.wsaenotsock_2
1223 * man errno(3)
1224 */
1225 void MLton_fixSocketErrno (void) {
1226 int status = WSAGetLastError ();
1227
1228 switch (status) {
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
1272 */
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;
1280 case WSA_E_NO_MORE:
1281 case WSAENOMORE:
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
1289 // WSA_IO_PENDING
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");
1300 case WSAEREFUSED:
1301 case WSAHOST_NOT_FOUND:
1302 case WSATRY_AGAIN:
1303 case WSANO_RECOVERY:
1304 case WSANO_DATA:
1305 die("Strange winsock specific status code");
1306 default:
1307 die("Unknown winsock status code");
1308 }
1309 }
1310
1311 static const char *MLton_strerrorExtension(int code) {
1312 switch (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";
1356 }
1357 }
1358
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.
1364 *
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.
1368 *
1369 * Thus, we just make a big English table to augment strerror.
1370 * The descriptions are taken from man errno(3).
1371 */
1372 char *MLton_strerror(int code) {
1373 static char buffer[80];
1374
1375 #undef strerror
1376 if (code < sys_nerr) return strerror(code);
1377 #define strerror MLton_strerror
1378
1379 strcpy(buffer, MLton_strerrorExtension(code));
1380 return buffer;
1381 }
1382
1383 int MLton_recv(int s, void *buf, int len, int flags) {
1384 int ret, status = 0;
1385
1386 if (flags & MSG_DONTWAIT) MinGW_setNonBlock(s);
1387 ret = recv(s, buf, len, flags & ~MSG_DONTWAIT);
1388
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);
1393
1394 return ret;
1395 }
1396
1397 int MLton_recvfrom(int s, void *buf, int len, int flags, void *from,
1398 socklen_t *fromlen) {
1399 int ret, status = 0;
1400
1401 if (flags & MSG_DONTWAIT) MinGW_setNonBlock(s);
1402 ret = recvfrom(s, buf, len, flags & ~MSG_DONTWAIT, from, fromlen);
1403
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);
1408
1409 return ret;
1410 }
1411 /* ------------------------------------------------- */
1412 /* Syslog */
1413 /* ------------------------------------------------- */
1414
1415 static const char* logident = "<unknown>";
1416 static int logopt = LOG_PERROR;
1417 static int logfacility = LOG_LOCAL0;
1418
1419 void openlog(const char* ident, int opt, int facility) {
1420 logident = ident;
1421 logopt = opt;
1422 logfacility = facility;
1423 }
1424
1425 void closelog(void) {
1426 }
1427
1428 void syslog(int priority, __attribute__ ((unused)) const char* fmt, const char* msg) {
1429 static const char* severity[] = {
1430 "debug",
1431 "informational",
1432 "notice",
1433 "warning",
1434 "error",
1435 "CRITICAL",
1436 "ALERT",
1437 "EMERGENCY"
1438 };
1439
1440 if (priority < 0) priority = LOG_DEBUG;
1441 if (priority > LOG_EMERG) priority = LOG_EMERG;
1442
1443
1444 /* !!! Use ReportEvent to log with windows */
1445
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);
1449 else
1450 fprintf(stderr, "%s: %s: %s\n", logident, severity[priority], msg);
1451 }
1452 }
1453
1454 /* ------------------------------------------------- */
1455 /* MinGW */
1456 /* ------------------------------------------------- */
1457
1458 C_Size_t MinGW_getTempPath(C_Size_t buf_size, Array(Char8_t) buf) {
1459 return GetTempPath(buf_size, (char*)buf);
1460 }
1461
1462 void MinGW_setNonBlock(C_Fd_t fd) {
1463 unsigned long yes = 1;
1464 ioctlsocket(fd, FIONBIO, &yes);
1465 }
1466
1467 void MinGW_clearNonBlock(C_Fd_t fd) {
1468 unsigned long no = 0;
1469 ioctlsocket(fd, FIONBIO, &no);
1470 }