ports/106506: [maintainer update] lang/sbcl: amd64 and threading update

NIIMI Satoshi sa2c at sa2c.net
Sat Dec 9 08:00:26 UTC 2006


>Number:         106506
>Category:       ports
>Synopsis:       [maintainer update] lang/sbcl: amd64 and threading update
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          maintainer-update
>Submitter-Id:   current-users
>Arrival-Date:   Sat Dec 09 08:00:24 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     NIIMI Satoshi
>Release:        FreeBSD 6.2-RC1 i386
>Organization:
>Environment:
System: FreeBSD berkeley.l.sa2c.net 6.2-RC1 FreeBSD 6.2-RC1 #0: Thu Dec 7 13:37:07 JST 2006 root at berkeley.l.sa2c.net:/usr/obj/usr/src/sys/GENERIC i386


	
>Description:
Stabilize threading.
Fix handling of floating point exception on AMD64.
Support build on AMD64 with threading.
	
>How-To-Repeat:
	
>Fix:
Please note to run "cvs add files/patch-futex" before commit.
	

--- sbcl.diff begins here ---
--- Makefile	Fri Dec 08 12:03:37 2006 +0900
+++ Makefile	Sat Dec 09 16:41:33 2006 +0900
@@ -7,6 +7,7 @@
 
 PORTNAME=	sbcl
 PORTVERSION=	1.0
+PORTREVISION=	1
 CATEGORIES=	lang lisp
 MASTER_SITES=	${MASTER_SITE_SOURCEFORGE}
 MASTER_SITE_SUBDIR=	sbcl
@@ -23,7 +24,7 @@ USE_GMAKE=	yes
 
 EXTRACT_AFTER_ARGS=	| ${TAR} -xf - --exclude */CVS/*
 
-# Can currently only bootstrap using cmucl, which is i386-only
+# SBCL is a native code compiler: it must be ported per architecture.
 ONLY_FOR_ARCHS=	i386 amd64
 
 MAN1=		sbcl.1
@@ -54,10 +55,6 @@ BUILD_DEPENDS+=	${LOCALBASE}/lib32/compa
 
 .if defined(WITH_THREADS) && ${OSVERSION} < 500000
 BROKEN=		Does not compile on 4.x with threading
-.endif
-
-.if defined(WITH_THREADS) && ${ARCH} == amd64
-BROKEN=		Does not compile on AMD64 with threading
 .endif
 
 .if ${ARCH} == i386
@@ -93,11 +90,6 @@ test:	build
 	(cd ${WRKSRC}/tests && ${SH} run-tests.sh)
 
 pre-everything::
-.if ${ARCH} == amd64
-	@${ECHO_MSG} "====>"
-	@${ECHO_MSG} "====> WARNING: AMD64 support is experimental."
-	@${ECHO_MSG} "====>"
-.else
 .if !defined(WITH_THREADS) && ${OSVERSION} >= 600000
 	@${ECHO_MSG} "====>"
 	@${ECHO_MSG} "====> To enable experimental threading support, define WITH_THREADS."
@@ -107,6 +99,5 @@ pre-everything::
 	@${ECHO_MSG} "====> WARNING: Current threading support is very unstable on FreeBSD 5.x."
 	@${ECHO_MSG} "====>"
 .endif
-.endif
 
 .include <bsd.port.post.mk>
--- files/patch-freebsd-amd64	Fri Dec 08 12:03:37 2006 +0900
+++ files/patch-freebsd-amd64	Sat Dec 09 16:41:33 2006 +0900
@@ -557,3 +557,101 @@
 +#endif
 +
 +#endif /* _X86_64_BSD_OS_H */
+--- src/runtime/x86-64-arch.c	Thu Nov 30 19:20:11 2006 +0900
++++ src/runtime/x86-64-arch.c	Sun Dec 03 02:26:51 2006 +0900
+@@ -308,6 +308,56 @@ sigill_handler(int signal, siginfo_t *si
+     lose("fake_foreign_function_call fell through");
+ }
+ 
++#ifdef X86_64_SIGFPE_FIXUP
++#define MXCSR_IE (0x01)         /* Invalid Operation */
++#define MXCSR_DE (0x02)         /* Denormal */
++#define MXCSR_ZE (0x04)         /* Devide-by-Zero */
++#define MXCSR_OE (0x08)         /* Overflow */
++#define MXCSR_UE (0x10)         /* Underflow */
++#define MXCSR_PE (0x20)         /* Precision */
++
++static inline int
++mxcsr_to_code(unsigned int mxcsr)
++{
++    /* Extract unmasked exception bits. */
++    mxcsr &= ~(mxcsr >> 7) & 0x3F;
++
++    /* This order is defined at "Intel 64 and IA-32 Architectures
++     * Software Developerfs Manual" Volume 1: "Basic Architecture",
++     * 4.9.2 "Floating-Point Exception Priority". */
++    if (mxcsr & MXCSR_IE)
++        return FPE_FLTINV;
++    else if (mxcsr & MXCSR_ZE)
++        return FPE_FLTDIV;
++    else if (mxcsr & MXCSR_DE)
++        return FPE_FLTUND;
++    else if (mxcsr & MXCSR_OE)
++        return FPE_FLTOVF;
++    else if (mxcsr & MXCSR_UE)
++        return FPE_FLTUND;
++    else if (mxcsr & MXCSR_PE)
++        return FPE_FLTRES;
++
++    return 0;
++}
++
++static void
++sigfpe_handler(int signal, siginfo_t *siginfo, void *void_context)
++{
++    os_context_t *context = arch_os_get_context(&void_context);
++    unsigned int *mxcsr = arch_os_context_mxcsr_addr(context);
++
++    if (siginfo->si_code == 0) { /* XMM exception */
++        siginfo->si_code = mxcsr_to_code(*mxcsr);
++
++        /* Clear sticky exception flag. */
++        *mxcsr &= ~0x3F;
++    }
++
++    interrupt_handle_now(signal, siginfo, context);
++}
++#endif
++
+ void
+ arch_install_interrupt_handlers()
+ {
+@@ -325,6 +375,9 @@ arch_install_interrupt_handlers()
+      * why.. -- WHN 2001-06-07 */
+     undoably_install_low_level_interrupt_handler(SIGILL , sigill_handler);
+     undoably_install_low_level_interrupt_handler(SIGTRAP, sigtrap_handler);
++#ifdef X86_64_SIGFPE_FIXUP
++    undoably_install_low_level_interrupt_handler(SIGFPE, sigfpe_handler);
++#endif
+ 
+     SHOW("returning from arch_install_interrupt_handlers()");
+ }
+--- src/runtime/x86-64-bsd-os.h	Thu Nov 30 19:20:11 2006 +0900
++++ src/runtime/x86-64-bsd-os.h	Sun Dec 03 02:26:51 2006 +0900
+@@ -2,8 +2,7 @@
+ #define _X86_64_BSD_OS_H
+ 
+ #ifdef LISP_FEATURE_FREEBSD
+-#include <machine/segments.h>
+-#include <machine/cpufunc.h>
++#include <machine/fpu.h>
+ #endif
+ 
+ typedef register_t os_context_register_t;
+@@ -29,6 +28,16 @@ static inline os_context_t *arch_os_get_
+ #if defined LISP_FEATURE_FREEBSD
+ #define RESTORE_FP_CONTROL_FROM_CONTEXT
+ void os_restore_fp_control(os_context_t *context);
++
++/* FreeBSD does not setup si_code on XMM exception. */
++#define X86_64_SIGFPE_FIXUP
++
++static inline unsigned int *
++arch_os_context_mxcsr_addr(os_context_t *context)
++{
++    struct envxmm *ex = (struct envxmm *)(&context->uc_mcontext.mc_fpstate);
++    return &ex->en_mxcsr;
++}
+ #endif
+ 
+ #endif /* _X86_64_BSD_OS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ files/patch-futex	Sat Dec 09 16:41:33 2006 +0900
@@ -0,0 +1,370 @@
+--- 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
--- sbcl.diff ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



More information about the freebsd-ports-bugs mailing list