[MLton-commit] r6837

Wesley Terpstra wesley at mlton.org
Sat Sep 6 08:00:15 PDT 2008


Added setitimer support to MinGW using win32 TimerQueues. Switched the alarm implementation to use the new setitimer. Hooked itimer signals in sigaction. While rewriting sigaction, fixed a latent bug wrt. fetching the old signal handler w/o setting a new one.

Three new regressions pass: thread2, prodcons, and timeout. mutex still fails (probably because the itimer signals are not maskable).

Also fixed the indentation of several methods in mingw.c.

----------------------------------------------------------------------

U   mlton/trunk/basis-library/posix/stub-mingw.sml
U   mlton/trunk/bin/regression
U   mlton/trunk/runtime/platform/mingw.c
U   mlton/trunk/runtime/platform/mingw.h

----------------------------------------------------------------------

Modified: mlton/trunk/basis-library/posix/stub-mingw.sml
===================================================================
--- mlton/trunk/basis-library/posix/stub-mingw.sml	2008-09-06 10:46:47 UTC (rev 6836)
+++ mlton/trunk/basis-library/posix/stub-mingw.sml	2008-09-06 15:00:13 UTC (rev 6837)
@@ -22,18 +22,6 @@
       struct
          open PrimitiveFFI
 
-         structure MLton =
-            struct
-               open MLton
-
-               structure Itimer =
-                  struct
-                     open Itimer
-
-                     val set = stub ("set", set)
-                  end
-            end
-
          structure OS =
             struct
                open OS

Modified: mlton/trunk/bin/regression
===================================================================
--- mlton/trunk/bin/regression	2008-09-06 10:46:47 UTC (rev 6836)
+++ mlton/trunk/bin/regression	2008-09-06 15:00:13 UTC (rev 6837)
@@ -151,7 +151,7 @@
         case `host-os` in
         cygwin|mingw)
                 case "$f" in
-                echo|signals|socket|suspend|textio.2|thread2|world*)
+                echo|signals|socket|suspend|textio.2|world*)
                         continue
                 ;;
                 esac
@@ -160,7 +160,7 @@
         case `host-os` in
         mingw)
                 case "$f" in
-                cmdline|command-line|filesys|mutex|posix-exit|prodcons|signals2|timeout|unixpath)
+                cmdline|command-line|filesys|mutex|posix-exit|signals2|unixpath)
                         continue
                 ;;
                 esac

Modified: mlton/trunk/runtime/platform/mingw.c
===================================================================
--- mlton/trunk/runtime/platform/mingw.c	2008-09-06 10:46:47 UTC (rev 6836)
+++ mlton/trunk/runtime/platform/mingw.c	2008-09-06 15:00:13 UTC (rev 6837)
@@ -42,11 +42,11 @@
 }
 
 HANDLE fileDesHandle (int fd) {
-  // The temporary prevents a "cast does not match function type" warning.
-  intptr_t t;
+        // The temporary prevents a "cast does not match function type" warning.
+        intptr_t t;
 
-  t = _get_osfhandle (fd);
-  return (HANDLE)t;
+        t = _get_osfhandle (fd);
+        return (HANDLE)t;
 }
 
 int mkstemp (char *template) {
@@ -102,14 +102,155 @@
 /*                   MLton.Itimer                    */
 /* ------------------------------------------------- */
 
-__attribute__ ((noreturn))
-int setitimer (__attribute__ ((unused)) int which, 
-               __attribute__ ((unused)) const struct itimerval *value, 
-               __attribute__ ((unused)) struct itimerval *ovalue) {
-        // !!! perhaps use code from alarm?
-        die ("setitimer not implemented");
+/* We use the kernel's TimerQueues -- see:
+ *  http://msdn.microsoft.com/en-us/library/ms686796(VS.85).aspx
+ */
+
+static HANDLE MainThread = NULL;
+static HANDLE TimerQueue = NULL;
+static HANDLE RealTimer = NULL;
+static HANDLE VirtTimer = NULL;
+static HANDLE ProfTimer = NULL;
+static void (*SIGALRM_handler)(int sig) = SIG_DFL;
+static void (*SIGVTAM_handler)(int sig) = SIG_DFL;
+static void (*SIGPROF_handler)(int sig) = SIG_DFL;
+
+/* The timer handler is fired in another thread.
+ * The idea is to suspend the main thread and resume it once we're done.
+ * This will appear more-or-less the same as if a Unix system had received
+ * the signal. We will also be firing the handler in the timer thread itself
+ * for performance reasons (MLton uses this mechanism to do multi-threading).
+ * This means the signal handlers must be fast, which they are since they
+ * just mark the signal to be processed later.
+ */
+
+static VOID CALLBACK MLton_SIGALRM(__attribute__ ((unused)) PVOID myArg,
+                                   __attribute__ ((unused)) BOOLEAN timeout) {
+        SuspendThread(MainThread);
+        if (SIGALRM_handler == SIG_IGN) {
+                /* noop */
+        } else if (SIGALRM_handler == SIG_DFL) {
+                die("alarm");
+        } else {
+                (*SIGALRM_handler)(SIGALRM);
+        }
+        ResumeThread(MainThread);
 }
+static VOID CALLBACK MLton_SIGVTAM(__attribute__ ((unused)) PVOID myArg,
+                                   __attribute__ ((unused)) BOOLEAN timeout) {
+        SuspendThread(MainThread);
+        if (SIGVTAM_handler == SIG_IGN) {
+                /* noop */
+        } else if (SIGVTAM_handler == SIG_DFL) {
+                die("vtalarm");
+        } else {
+                (*SIGVTAM_handler)(SIGVTALRM);
+        }
+        ResumeThread(MainThread);
+}
+static VOID CALLBACK MLton_SIGPROF(__attribute__ ((unused)) PVOID myArg,
+                                   __attribute__ ((unused)) BOOLEAN timeout) {
+        SuspendThread(MainThread);
+        if (SIGPROF_handler == SIG_IGN) {
+                /* noop */
+        } else if (SIGPROF_handler == SIG_DFL) {
+                die("sigprof");
+        } else {
+                (*SIGPROF_handler)(SIGPROF);
+        }
+        ResumeThread(MainThread);
+}
 
+static int MLTimer(HANDLE *timer, 
+                   const struct itimerval *value, 
+                   WAITORTIMERCALLBACK callback) {
+        DWORD DueTime, Period;
+
+        /* Initialize the TimerQueue */
+        if (MainThread == 0) {
+                TimerQueue = CreateTimerQueue();
+                if (TimerQueue == NULL) { errno = ENOMEM; return -1; }
+                DuplicateHandle(GetCurrentProcess(), /* source process */
+                                GetCurrentThread(),  /* source handle  */
+                                GetCurrentProcess(), /* target process */
+                                &MainThread,         /* target handle  */
+                                0,                   /* access (ignored) */
+                                FALSE,               /* not inheritable */
+                                DUPLICATE_SAME_ACCESS);
+                if (MainThread == 0) die("Cannot get handle to initial thread");
+        }
+
+        /* Windows uses ms accuracy for TimerQueues */
+        DueTime = value->it_value.tv_sec * 1000
+                + (value->it_value.tv_usec + 999) / 1000;
+        Period  = value->it_interval.tv_sec * 1000
+                + (value->it_interval.tv_usec + 999) / 1000;
+
+        if (timer != NULL) {
+                DeleteTimerQueueTimer(TimerQueue, *timer, NULL);
+                *timer = NULL;
+        }
+        
+        if (DueTime == 0) {
+                return 0;
+        } 
+
+        if (!CreateTimerQueueTimer(
+                timer,       /* output: created timer */
+                TimerQueue,  /* The queue which holds the timers */
+                callback,    /* Invoked on timer events */
+                0,           /* myArg for the callback */
+                DueTime,     /* Must be non-zero => time till first event */
+                Period,      /* Time till the event repeats (forever) */
+                WT_EXECUTEINTIMERTHREAD)) { /* Don't use a thread pool */
+                 errno = ENOMEM;
+                 return -1;
+        }
+
+        return 0;
+}
+
+int setitimer (int which, 
+               const struct itimerval *value, 
+               struct itimerval *ovalue) {
+        if (ovalue != 0) die("setitimer doesn't support retrieving old state");
+
+        switch (which) {
+        case ITIMER_REAL: return MLTimer(&RealTimer, value, &MLton_SIGALRM);
+        case ITIMER_VIRT: return MLTimer(&VirtTimer, value, &MLton_SIGVTAM);
+        case ITIMER_PROF: return MLTimer(&ProfTimer, value, &MLton_SIGPROF);
+        default:          errno = EINVAL; return -1;
+        }
+
+}
+/*
+static void catcher(__attribute__ ((unused)) int sig) {
+        CONTEXT context;
+
+        GetThreadContext(MainThread, &context);
+#if defined(__i386__)
+        GC_handleSigProf((code_pointer) context.Eip);
+#elif defined(__x86_64__)
+        GC_handleSigProf((code_pointer) context.Rip);
+#elif defined(_PPC_)
+        GC_handleSigProf((code_pointer) context.Iar);
+#elif defined(_ALPHA_)
+        GC_handleSigProf((code_pointer) context.Fir);
+#elif defined(MIPS)
+        GC_handleSigProf((code_pointer) context.Fir);
+#elif defined(ARM)
+        GC_handleSigProf((code_pointer) context.Pc);
+#else
+#error Profiling handler is missing for this architecture
+#endif
+} 
+
+void GC_setSigProfHandler (struct sigaction *sa) {
+        sa->sa_flags = 0;
+        sa->sa_handler = (_sig_func_ptr)&catcher;
+}
+*/
+
 /* ------------------------------------------------- */
 /*                   MLton.Rlimit                    */
 /* ------------------------------------------------- */
@@ -163,49 +304,49 @@
  *   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocesstimes.asp
  */
 int getrusage (int who, struct rusage *usage) {
-  /* FILETIME has dw{High,Low}DateTime which store the number of
-   * 100-nanoseconds since January 1, 1601
-   */
-  FILETIME creation_time;
-  FILETIME exit_time;
-  FILETIME kernel_time;
-  FILETIME user_time;
+        /* FILETIME has dw{High,Low}DateTime which store the number of
+         * 100-nanoseconds since January 1, 1601
+         */
+        FILETIME creation_time;
+        FILETIME exit_time;
+        FILETIME kernel_time;
+        FILETIME user_time;
 
-  uint64_t user_usecs, kernel_usecs;
+        uint64_t user_usecs, kernel_usecs;
 
-  if (who == RUSAGE_CHILDREN) {
-    // !!! could use exit_time - creation_time from cwait 
-    memset(usage, 0, sizeof(struct rusage));
-    return 0;
-  }
+        if (who == RUSAGE_CHILDREN) {
+                // !!! could use exit_time - creation_time from cwait 
+                memset(usage, 0, sizeof(struct rusage));
+                return 0;
+        }
   
-  if (who != RUSAGE_SELF) {
-    errno = EINVAL;
-    return -1;
-  }
+        if (who != RUSAGE_SELF) {
+                errno = EINVAL;
+                return -1;
+        }
 
-  if (GetProcessTimes(GetCurrentProcess(), 
-                      &creation_time, &exit_time,
-                      &kernel_time, &user_time) == 0) {
-    errno = EFAULT;
-    return -1;
-  }
+        if (GetProcessTimes(GetCurrentProcess(), 
+                            &creation_time, &exit_time,
+                            &kernel_time, &user_time) == 0) {
+                errno = EFAULT;
+                return -1;
+        }
   
-  kernel_usecs = kernel_time.dwHighDateTime;
-  kernel_usecs <<= sizeof(kernel_time.dwHighDateTime)*8;
-  kernel_usecs |= kernel_time.dwLowDateTime;
-  kernel_usecs /= 10;
+        kernel_usecs = kernel_time.dwHighDateTime;
+        kernel_usecs <<= sizeof(kernel_time.dwHighDateTime)*8;
+        kernel_usecs |= kernel_time.dwLowDateTime;
+        kernel_usecs /= 10;
 
-  user_usecs = user_time.dwHighDateTime;
-  user_usecs <<= sizeof(user_time.dwHighDateTime)*8;
-  user_usecs |= user_time.dwLowDateTime;
-  user_usecs /= 10;
+        user_usecs = user_time.dwHighDateTime;
+        user_usecs <<= sizeof(user_time.dwHighDateTime)*8;
+        user_usecs |= user_time.dwLowDateTime;
+        user_usecs /= 10;
 
-  usage->ru_utime.tv_sec  = user_usecs / 1000000;
-  usage->ru_utime.tv_usec = user_usecs % 1000000;
-  usage->ru_stime.tv_sec  = kernel_usecs / 1000000;
-  usage->ru_stime.tv_usec = kernel_usecs % 1000000;
-  return 0;
+        usage->ru_utime.tv_sec  = user_usecs / 1000000;
+        usage->ru_utime.tv_usec = user_usecs % 1000000;
+        usage->ru_stime.tv_sec  = kernel_usecs / 1000000;
+        usage->ru_stime.tv_usec = kernel_usecs % 1000000;
+        return 0;
 }
 
 /* ------------------------------------------------- */
@@ -234,28 +375,28 @@
         fileSize = GetFileSize (fh, &fileSizeHi);
         fhmap = CreateFileMapping (fh, NULL, PAGE_READONLY, 0, fileSize, NULL);
         if (fhmap) {
-            pMem = MapViewOfFile (fhmap, FILE_MAP_READ, 0, 0, 1);
-            if (pMem) {
-                GetMappedFileNameA (GetCurrentProcess(), pMem, fname, MAX_PATH);
-                UnmapViewOfFile (pMem);
-            }
-            CloseHandle (fhmap);
+                pMem = MapViewOfFile (fhmap, FILE_MAP_READ, 0, 0, 1);
+                if (pMem) {
+                        GetMappedFileNameA (GetCurrentProcess(),
+                                            pMem, fname, MAX_PATH);
+                        UnmapViewOfFile (pMem);
+                }
+                CloseHandle (fhmap);
         }
-        return; 
 }
 
 int fchmod (int filedes, mode_t mode) {
-      char fname[MAX_PATH + 1];
+        char fname[MAX_PATH + 1];
 
-      GetWin32FileName (filedes, fname);
-      return _chmod (fname, mode);
+        GetWin32FileName (filedes, fname);
+        return _chmod (fname, mode);
 }
 
 int fchdir (int filedes) {
-      char fname[MAX_PATH + 1];
+        char fname[MAX_PATH + 1];
 
-      GetWin32FileName (filedes, fname);
-      return chdir (fname);
+        GetWin32FileName (filedes, fname);
+        return chdir (fname);
 }
 
 __attribute__ ((noreturn))
@@ -319,16 +460,16 @@
 }
 
 int truncate (const char *path, off_t len) {
-  int fd;
+        int fd;
 
-  if ((fd = open(path, O_RDWR)) == -1)
-    return -1;
-  if (ftruncate(fd, len) < 0) {
-    close(fd);
-    return -1;
-  }
-  close(fd);
-  return 0;
+        if ((fd = open(path, O_RDWR)) == -1)
+                return -1;
+        if (ftruncate(fd, len) < 0) {
+                close(fd);
+                return -1;
+        }
+        close(fd);
+        return 0;
 }
 
 
@@ -557,6 +698,7 @@
 }
 
 int uname (struct utsname *buf) {
+        MLton_initSockets(); /* needed for gethostname */
         setMachine (buf);
         setSysname (buf);
         unless (0 == gethostname (buf->nodename, sizeof (buf->nodename))) {
@@ -576,53 +718,13 @@
 /*                   Posix.Process                   */
 /* ------------------------------------------------- */
 
-static UINT_PTR curr_timer = 0;
-static int curr_timer_dur = 0;
-static LARGE_INTEGER timer_start_val;
-
-
-static VOID CALLBACK alarm_signalled(__attribute__ ((unused)) HWND window,
-                                     __attribute__ ((unused)) UINT message,
-                                     __attribute__ ((unused)) UINT_PTR timer_id,
-                                     __attribute__ ((unused)) DWORD timestamp) {
-    printf("Timer fired\n");
-}
-
-/*
- * Win32 alarm implementation
- */
 int alarm (int secs) {
-        LARGE_INTEGER timer_end_val, frequency;
-        int remaining = 0;
-        long elapse = secs * 1000;      /* win32 uses usecs */
-
-        /* Unsetting the alarm */
-        if (secs == 0 && curr_timer == 0) {
-            return 0;
-        }
-        if (curr_timer != 0) {
-                KillTimer(0, curr_timer);
-                QueryPerformanceCounter(&timer_end_val);
-                QueryPerformanceFrequency(&frequency);
-                if (frequency.QuadPart != 0) {
-                        remaining = curr_timer_dur - ((int)(timer_end_val.QuadPart
-                                - timer_start_val.QuadPart)/frequency.QuadPart);
-                        if (remaining < 0) {
-                                remaining = 0;
-                        }
-                }
-
-                timer_start_val.QuadPart = 0;
-                curr_timer_dur = 0;
-                curr_timer = 0;
-        }
-        if (secs != 0) {
-                /* Otherwise, set a timer */
-                curr_timer = SetTimer(0, 0, elapse, alarm_signalled);
-                QueryPerformanceCounter(&timer_start_val);
-                curr_timer_dur = secs;
-        }
-        return remaining;
+        struct itimerval new;
+        new.it_interval.tv_usec = 0;
+        new.it_interval.tv_sec = 0;
+        new.it_value.tv_usec = 0;
+        new.it_value.tv_sec = secs;
+        return setitimer(ITIMER_REAL, &new, 0);
 }
 
 __attribute__ ((noreturn))
@@ -671,24 +773,40 @@
 /* ------------------------------------------------- */
 
 int sigaction (int signum, 
-                        const struct sigaction *newact,
-                        struct sigaction *oldact) {
+               const struct sigaction *newact,
+               struct sigaction *oldact) {
+        _sig_func_ptr old;
 
-        struct sigaction oa;
-
         if (signum < 0 or signum >= NSIG) {
                 errno = EINVAL;
                 return -1;
         }
-        if (newact) {
-                if (signum == SIGKILL or signum == SIGSTOP) {
-                        errno = EINVAL;
-                        return -1;
-                }
-                oa.sa_handler = signal (signum, newact->sa_handler);
+
+        switch (signum) {
+        case SIGKILL:
+        case SIGSTOP:
+                errno = EINVAL;
+                return -1;
+        case SIGALRM:
+                old = SIGALRM_handler;
+                if (newact) SIGALRM_handler = newact->sa_handler;
+                break;
+        case SIGVTALRM:
+                old = SIGVTAM_handler;
+                if (newact) SIGVTAM_handler = newact->sa_handler;
+                break;
+        case SIGPROF:
+                old = SIGPROF_handler;
+                if (newact) SIGPROF_handler = newact->sa_handler;
+                break;
+        default:
+                old = signal (signum, newact?newact->sa_handler:0);
+                if (!newact) signal (signum, old);
+                break;
         }
+
         if (oldact)
-                oldact->sa_handler = oa.sa_handler;
+                oldact->sa_handler = old;
         return 0;
 }
 

Modified: mlton/trunk/runtime/platform/mingw.h
===================================================================
--- mlton/trunk/runtime/platform/mingw.h	2008-09-06 10:46:47 UTC (rev 6836)
+++ mlton/trunk/runtime/platform/mingw.h	2008-09-06 15:00:13 UTC (rev 6837)
@@ -1,3 +1,6 @@
+/* Many of the functions used in mingw.c are Win2000+ */
+#define _WIN32_WINNT 0x0500
+
 #include <inttypes.h>
 #include <stdint.h>
 




More information about the MLton-commit mailing list