Add a safepoint-based mechanism to avoid SIGALRM for the TIMER facility
[sbcl.git] / src / runtime / sunos-os.c
index cab00ba..eb84223 100644 (file)
 #include "gencgc-internal.h"
 #endif
 
+#ifdef LISP_FEATURE_SB_WTIMER
+# include <port.h>
+# include <time.h>
+# include <errno.h>
+#endif
+
 os_vm_size_t os_vm_page_size=0;
 
 void
@@ -200,3 +206,98 @@ os_get_runtime_executable_path(int external)
     return copied_string(path);
 }
 
+#ifdef LISP_FEATURE_SB_WTIMER
+/*
+ * Waitable timer implementation for the safepoint-based (SIGALRM-free)
+ * timer facility using SunOS completion ports.
+ */
+
+struct os_wtimer {
+    int port;
+    int timer;
+};
+
+struct os_wtimer *
+os_create_wtimer()
+{
+    int port = port_create();
+    if (port == -1) {
+        perror("port_create");
+        lose("os_create_wtimer");
+    }
+
+    port_notify_t pn;
+    pn.portnfy_port = port;
+    pn.portnfy_user = 0;
+
+    struct sigevent ev;
+    memset(&ev, 0, sizeof(ev));
+    ev.sigev_notify = SIGEV_PORT;
+    ev.sigev_value.sival_ptr = &pn;
+
+    timer_t timer;
+    if (timer_create(CLOCK_HIGHRES, &ev, &timer) == -1
+        && (errno != EPERM || timer_create(CLOCK_REALTIME, &ev, &timer) == -1))
+    {
+        perror("timer_create");
+        lose("os_create_wtimer");
+    }
+
+    struct os_wtimer *wt = malloc(sizeof(struct os_wtimer));
+    if (!wt)
+        lose("os_create_wtimer: malloc");
+
+    wt->port = port;
+    wt->timer = timer;
+    return wt;
+}
+
+int
+os_wait_for_wtimer(struct os_wtimer *wt)
+{
+    port_event_t pe;
+    if (port_get(wt->port, &pe, 0) == -1) {
+        if (errno == EINTR)
+            return 1;
+        perror("port_get");
+        lose("os_wtimer_listen failed");
+    }
+    return 0;
+}
+
+void
+os_close_wtimer(struct os_wtimer *wt)
+{
+    if (close(wt->port) == -1) {
+        perror("close");
+        lose("os_close_wtimer");
+    }
+    if (timer_delete(wt->timer) == -1) {
+        perror("timer_delete");
+        lose("os_close_wtimer");
+    }
+    free(wt);
+}
+
+void
+os_set_wtimer(struct os_wtimer *wt, int sec, int nsec)
+{
+    struct itimerspec spec;
+    spec.it_value.tv_sec = sec;
+    spec.it_value.tv_nsec = nsec;
+    spec.it_interval.tv_sec = 0;
+    spec.it_interval.tv_nsec = 0;
+    if (timer_settime(wt->timer, 0, &spec, 0) == -1) {
+        int x = errno;
+        perror("timer_settime");
+        if (x != EINVAL)
+            lose("os_set_wtimer");
+    }
+}
+
+void
+os_cancel_wtimer(struct os_wtimer *wt)
+{
+    os_set_wtimer(wt, 0, 0);
+}
+#endif