head	1.2;
access;
symbols;
locks; strict;
comment	@# @;


1.2
date	2006.12.27.15.17.05;	author miwi;	state dead;
branches;
next	1.1;

1.1
date	2006.12.09.09.31.29;	author miwi;	state Exp;
branches;
next	;


desc
@@


1.2
log
@- Update to 1.0.1

PR:             ports/107223
Submitted by:   NIIMI Satoshi <sa2c@@sa2c.net> (maintainer)
@
text
@--- make-config.sh	Thu Nov 30 02:36:43 2006 +0000
+++ make-config.sh	Sat Dec 09 13:57:31 2006 +0900
@@@@ -191,8 +191,9 @@@@ case "$sbcl_os" in
             freebsd)
                 printf ' :elf' >> $ltf
                 printf ' :freebsd' >> $ltf
+                printf ' :sb-pthread-futex' >> $ltf
                 if [ $sbcl_arch = "x86" ]; then
-                    printf ' :sb-lutex :restore-tls-segment-register-from-tls' >> $ltf
+                    printf ' :restore-tls-segment-register-from-tls' >> $ltf
                 fi
                 link_or_copy Config.$sbcl_arch-freebsd Config
                 ;;
--- src/runtime/GNUmakefile	Thu Nov 30 02:36:43 2006 +0000
+++ src/runtime/GNUmakefile	Sat Dec 09 13:58:56 2006 +0900
@@@@ -40,7 +40,8 @@@@ include Config
 
 COMMON_SRC = alloc.c backtrace.c breakpoint.c coreparse.c \
 	dynbind.c gc-common.c globals.c interr.c interrupt.c largefile.c \
-	monitor.c os-common.c parse.c print.c purify.c pthread-lutex.c \
+	monitor.c os-common.c parse.c print.c purify.c \
+	pthread-futex.c pthread-lutex.c \
 	regnames.c run-program.c runtime.c save.c search.c \
 	thread.c time.c util.c validate.c vars.c wrap.c	
 
--- src/runtime/linux-os.c	Thu Nov 30 02:36:43 2006 +0000
+++ src/runtime/linux-os.c	Sat Dec 09 13:56:27 2006 +0900
@@@@ -62,7 +62,7 @@@@ int personality (unsigned long);
 
 size_t os_vm_page_size;
 
-#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX)
+#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
 #include <sys/syscall.h>
 #include <unistd.h>
 #include <errno.h>
@@@@ -145,7 +145,7 @@@@ os_init(char *argv[], char *envp[])
 {
     /* Conduct various version checks: do we have enough mmap(), is
      * this a sparc running 2.2, can we do threads? */
-#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX)
+#if defined(LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
     int *futex=0;
 #endif
     struct utsname name;
@@@@ -171,7 +171,7 @@@@ os_init(char *argv[], char *envp[])
 #endif
     }
 #ifdef LISP_FEATURE_SB_THREAD
-#if !defined(LISP_FEATURE_SB_LUTEX)
+#if !defined(LISP_FEATURE_SB_LUTEX) && !defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
     futex_wait(futex,-1);
     if(errno==ENOSYS) {
        lose("This version of SBCL is compiled with threading support, but your kernel\n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ src/runtime/pthread-futex.c	Sat Dec 09 13:56:27 2006 +0900
@@@@ -0,0 +1,313 @@@@
+/* An approximation of Linux futexes implemented using pthread mutexes
+ * and pthread condition variables.
+ */
+
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * The software is in the public domain and is provided with
+ * absolutely no warranty. See the COPYING and CREDITS files for more
+ * information.
+ */
+
+#include "sbcl.h"
+
+#if defined(LISP_FEATURE_SB_THREAD) && defined(LISP_FEATURE_SB_PTHREAD_FUTEX)
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "runtime.h"
+#include "arch.h"
+#include "target-arch-os.h"
+#include "os.h"
+
+#define FUTEX_WAIT_NSEC (10000000) /* 10 msec */
+
+#if 1
+# define futex_assert(ex)                                              \
+do {                                                                   \
+    if (!(ex)) futex_abort();                                          \
+} while (0)
+# define futex_assert_verbose(ex, fmt, ...)                            \
+do {                                                                   \
+    if (!(ex)) {                                                       \
+        fprintf(stderr, fmt, ## __VA_ARGS__);                          \
+        futex_abort();                                                 \
+    }                                                                  \
+} while (0)
+#else
+# define futex_assert(ex)
+# define futex_assert_verbose(ex, fmt, ...)
+#endif
+
+#define futex_abort()                                                  \
+  lose("Futex assertion failure, file \"%s\", line %d\n", __FILE__, __LINE__)
+
+struct futex {
+    struct futex *prev;
+    struct futex *next;
+    int *lock_word;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int count;
+};
+
+static pthread_mutex_t futex_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static struct futex *futex_head = NULL;
+static struct futex *futex_free_head = NULL;
+
+static struct futex *
+futex_add(struct futex *head, struct futex *futex)
+{
+    futex->prev = NULL;
+    futex->next = head;
+    if (head != NULL)
+        head->prev = futex;
+    head = futex;
+
+    return head;
+}
+
+static struct futex *
+futex_delete(struct futex *head, struct futex *futex)
+{
+    if (head == futex)
+        head = futex->next;
+    if (futex->prev != NULL)
+        futex->prev->next = futex->next;
+    if (futex->next != NULL)
+        futex->next->prev = futex->prev;
+
+    return head;
+}
+
+static struct futex *
+futex_find(struct futex *head, int *lock_word)
+{
+    struct futex *futex;
+
+    for (futex = head; futex != NULL; futex = futex->next) {
+        if (futex->lock_word == lock_word)
+            break;
+    }
+
+    return futex;
+}
+
+static struct futex *
+futex_get(int *lock_word)
+{
+    int ret;
+    struct futex *futex;
+
+    ret = pthread_mutex_lock(&futex_lock);
+    futex_assert(ret == 0);
+
+    futex = futex_find(futex_head, lock_word);
+
+    if (futex != NULL)
+        futex->count++;
+
+    ret = pthread_mutex_unlock(&futex_lock);
+    futex_assert(ret == 0);
+
+    if (futex != NULL) {
+        ret = pthread_mutex_lock(&futex->mutex);
+        futex_assert(ret == 0);
+    }
+
+    return futex;
+}
+
+static struct futex *
+futex_allocate(int *lock_word)
+{
+    int ret;
+    struct futex *futex;
+
+    ret = pthread_mutex_lock(&futex_lock);
+    futex_assert(ret == 0);
+
+    futex = futex_free_head;
+
+    if (futex != NULL)
+        futex_free_head = futex_delete(futex_free_head, futex);
+
+    ret = pthread_mutex_unlock(&futex_lock);
+    futex_assert(ret == 0);
+
+    if (futex == NULL) {
+        futex = malloc(sizeof(struct futex));
+        futex_assert(futex != NULL);
+
+        ret = pthread_mutex_init(&futex->mutex, NULL);
+        futex_assert(ret == 0);
+
+        ret = pthread_cond_init(&futex->cond, NULL);
+        futex_assert(ret == 0);
+    }
+
+    futex->lock_word = lock_word;
+    futex->count = 1;
+
+    /* Lock mutex before register to avoid race conditions. */
+    ret = pthread_mutex_lock(&futex->mutex);
+    futex_assert(ret == 0);
+
+    ret = pthread_mutex_lock(&futex_lock);
+    futex_assert(ret == 0);
+
+    futex_head = futex_add(futex_head, futex);
+
+    ret = pthread_mutex_unlock(&futex_lock);
+    futex_assert(ret == 0);
+
+    return futex;
+}
+
+static void
+futex_cleanup(void *p)
+{
+    struct futex *futex = (struct futex *)p;
+    int ret, count;
+ 
+    ret = pthread_mutex_lock(&futex_lock);
+    futex_assert(ret == 0);
+
+    count = --futex->count;
+    if (count <= 0) {
+        futex_head = futex_delete(futex_head, futex);
+        futex_free_head = futex_add(futex_free_head, futex);
+    }
+
+    ret = pthread_mutex_unlock(&futex_lock);
+    futex_assert(ret == 0);
+
+    ret = pthread_mutex_unlock(&futex->mutex);
+    futex_assert(ret == 0);
+}
+
+static int
+futex_relative_to_abs(struct timespec *tp, int relative)
+{
+    int ret;
+    struct timeval tv;
+
+    ret = gettimeofday(&tv, NULL);
+    if (ret != 0)
+        return ret;
+    tp->tv_sec = tv.tv_sec + (tv.tv_usec * 1000 + relative) / 1000000000;
+    tp->tv_nsec = (tv.tv_usec * 1000 + relative) % 1000000000;
+    return 0;
+}
+
+int
+futex_wait(int *lock_word, int oldval)
+{
+    int ret, result;
+    struct futex *futex;
+    sigset_t oldset, newset;
+
+    sigemptyset(&newset);
+    sigaddset_deferrable(&newset);
+
+again:
+    pthread_sigmask(SIG_BLOCK, &newset, &oldset);
+
+    futex = futex_get(lock_word);
+
+    if (futex == NULL)
+        futex = futex_allocate(lock_word);
+
+    pthread_cleanup_push(futex_cleanup, futex);
+
+    /* Compare lock_word after the lock is aquired to avoid race
+     * conditions. */
+    if (*(volatile int *)lock_word != oldval) {
+        result = EWOULDBLOCK;
+        goto done;
+    }
+
+    /* It's not possible to unwind frames across pthread_cond_wait(3). */
+    for (;;) {
+        int i;
+        sigset_t pendset;
+        struct timespec abstime;
+
+        ret = futex_relative_to_abs(&abstime, FUTEX_WAIT_NSEC);
+        futex_assert(ret == 0);
+
+        result = pthread_cond_timedwait(&futex->cond, &futex->mutex,
+                                        &abstime);
+        futex_assert(result == 0 || result == ETIMEDOUT);
+
+        if (result != ETIMEDOUT)
+            break;
+
+        /* futex system call of Linux returns with EINTR errno when
+         * it's interrupted by signals.  Check pending signals here to
+         * emulate this behaviour. */
+        sigpending(&pendset);
+        for (i = 1; i < NSIG; i++) {
+            if (sigismember(&pendset, i) && sigismember(&newset, i)) {
+                result = EINTR;
+                goto done;
+            }
+        }
+    }
+done:
+    ; /* Null statement is required between label and pthread_cleanup_pop. */
+    pthread_cleanup_pop(1);
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+
+    /* futex_wake() in linux-os.c loops when futex system call returns
+     * EINTR.  */
+    if (result == EINTR) {
+        sched_yield();
+        goto again;
+    }
+
+    return result;
+}
+
+int
+futex_wake(int *lock_word, int n)
+{
+    int ret;
+    struct futex *futex;
+    sigset_t newset, oldset;
+
+    sigemptyset(&newset);
+    sigaddset_deferrable(&newset);
+
+    pthread_sigmask(SIG_BLOCK, &newset, &oldset);
+
+    futex = futex_get(lock_word);
+
+    if (futex != NULL) {
+        pthread_cleanup_push(futex_cleanup, futex);
+
+        /* The lisp-side code passes N=2**29-1 for a broadcast. */
+        if (n >= ((1 << 29) - 1)) {
+            /* CONDITION-BROADCAST */
+            ret = pthread_cond_broadcast(&futex->cond);
+            futex_assert(ret == 0);
+        } else {
+            while (n-- > 0) {
+                ret = pthread_cond_signal(&futex->cond);
+                futex_assert(ret == 0);
+            }
+        }
+
+        pthread_cleanup_pop(1);
+    }
+
+    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+
+    return 0;
+}
+#endif
@


1.1
log
@- Fix handling of floating point exception on AMD64.
- Support build on AMD64 with threading.

PR:             ports/106506
Submitted  by:  NIIMI Satoshi <sa2c@@sa2c.net>
@
text
@@

