From a101a3852efe566a1879c9a7eb6ceff00bb8c6f7 Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 29 Nov 2011 21:58:48 +0000 Subject: [PATCH] runtime: If no sem_timedwait, use pthread_cond_timedwait. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@181821 138bc75d-0d04-0410-961f-82ee72b054a4 --- libgo/config.h.in | 3 ++ libgo/configure | 18 ++++++++++ libgo/configure.ac | 8 +++++ libgo/runtime/lock_sema.c | 9 ++++- libgo/runtime/thread-sema.c | 87 +++++++++++++++++++++++++++++++++++++++------ 5 files changed, 114 insertions(+), 11 deletions(-) diff --git a/libgo/config.h.in b/libgo/config.h.in index be4a13a8b52..0c1283cc574 100644 --- a/libgo/config.h.in +++ b/libgo/config.h.in @@ -36,6 +36,9 @@ /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM +/* Define to 1 if you have the `sem_timedwait' function. */ +#undef HAVE_SEM_TIMEDWAIT + /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV diff --git a/libgo/configure b/libgo/configure index 9c619bed47d..e9f536a5883 100755 --- a/libgo/configure +++ b/libgo/configure @@ -14559,6 +14559,24 @@ else fi +CFLAGS_hold="$CFLAGS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +LIBS_hold="$LIBS" +LIBS="$LIBS $PTHREAD_LIBS" +for ac_func in sem_timedwait +do : + ac_fn_c_check_func "$LINENO" "sem_timedwait" "ac_cv_func_sem_timedwait" +if test "x$ac_cv_func_sem_timedwait" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SEM_TIMEDWAIT 1 +_ACEOF + +fi +done + +CFLAGS="$CFLAGS_hold" +LIBS="$LIBS_hold" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __sync_bool_compare_and_swap_4" >&5 $as_echo_n "checking for __sync_bool_compare_and_swap_4... " >&6; } if test "${libgo_cv_func___sync_bool_compare_and_swap_4+set}" = set; then : diff --git a/libgo/configure.ac b/libgo/configure.ac index e19b5f37b70..576d1a64329 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -456,6 +456,14 @@ AC_CHECK_FUNCS(srandom random strerror_r strsignal wait4 mincore setenv) AM_CONDITIONAL(HAVE_STRERROR_R, test "$ac_cv_func_strerror_r" = yes) AM_CONDITIONAL(HAVE_WAIT4, test "$ac_cv_func_wait4" = yes) +CFLAGS_hold="$CFLAGS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +LIBS_hold="$LIBS" +LIBS="$LIBS $PTHREAD_LIBS" +AC_CHECK_FUNCS(sem_timedwait) +CFLAGS="$CFLAGS_hold" +LIBS="$LIBS_hold" + AC_CACHE_CHECK([for __sync_bool_compare_and_swap_4], [libgo_cv_func___sync_bool_compare_and_swap_4], [AC_LINK_IFELSE([ diff --git a/libgo/runtime/lock_sema.c b/libgo/runtime/lock_sema.c index 2fa837d8b0e..6b4fffbdcf8 100644 --- a/libgo/runtime/lock_sema.c +++ b/libgo/runtime/lock_sema.c @@ -32,9 +32,11 @@ enum void runtime_lock(Lock *l) { + M *m; uintptr v; uint32 i, spin; + m = runtime_m(); if(m->locks++ < 0) runtime_throw("runtime_lock: lock count"); @@ -91,7 +93,7 @@ runtime_unlock(Lock *l) uintptr v; M *mp; - if(--m->locks < 0) + if(--runtime_m()->locks < 0) runtime_throw("runtime_unlock: lock count"); for(;;) { @@ -144,6 +146,9 @@ runtime_notewakeup(Note *n) void runtime_notesleep(Note *n) { + M *m; + + m = runtime_m(); if(m->waitsema == 0) m->waitsema = runtime_semacreate(); if(!runtime_casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup) @@ -158,6 +163,7 @@ runtime_notesleep(Note *n) void runtime_notetsleep(Note *n, int64 ns) { + M *m; M *mp; int64 deadline, now; @@ -166,6 +172,7 @@ runtime_notetsleep(Note *n, int64 ns) return; } + m = runtime_m(); if(m->waitsema == 0) m->waitsema = runtime_semacreate(); diff --git a/libgo/runtime/thread-sema.c b/libgo/runtime/thread-sema.c index b0a6dc337fd..71555d09725 100644 --- a/libgo/runtime/thread-sema.c +++ b/libgo/runtime/thread-sema.c @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include "config.h" #include "runtime.h" #include @@ -9,19 +10,43 @@ #include #include +/* If we don't have sem_timedwait, use pthread_cond_timedwait instead. + We don't always use condition variables because on some systems + pthread_mutex_lock and pthread_mutex_unlock must be called by the + same thread. That is never true of semaphores. */ + +struct go_sem +{ + sem_t sem; + +#ifndef HAVE_SEM_TIMEDWAIT + int timedwait; + pthread_mutex_t mutex; + pthread_cond_t cond; +#endif +}; + /* Create a semaphore. */ uintptr runtime_semacreate(void) { - sem_t *p; + struct go_sem *p; /* Call malloc rather than runtime_malloc. This will allocate space on the C heap. We can't call runtime_malloc here because it could cause a deadlock. */ - p = malloc (sizeof (sem_t)); - if (sem_init (p, 0, 0) != 0) + p = malloc (sizeof (struct go_sem)); + if (sem_init (&p->sem, 0, 0) != 0) runtime_throw ("sem_init"); + +#ifndef HAVE_SEM_TIMEDWAIT + if (pthread_mutex_init (&p->mutex, NULL) != 0) + runtime_throw ("pthread_mutex_init"); + if (pthread_cond_init (&p->cond, NULL) != 0) + runtime_throw ("pthread_cond_init"); +#endif + return (uintptr) p; } @@ -30,26 +55,56 @@ runtime_semacreate(void) int32 runtime_semasleep (int64 ns) { + M *m; + struct go_sem *sem; int r; + m = runtime_m (); + sem = (struct go_sem *) m->waitsema; if (ns >= 0) { + int64 abs; struct timespec ts; + int err; + + abs = ns + runtime_nanotime (); + ts.tv_sec = abs / 1000000000LL; + ts.tv_nsec = abs % 1000000000LL; + + err = 0; - ns += runtime_nanotime (); - ts.tv_sec = ns / 1000000000LL; - ts.tv_nsec = ns % 1000000000LL; - r = sem_timedwait ((sem_t *) m->waitsema, &ts); +#ifdef HAVE_SEM_TIMEDWAIT + r = sem_timedwait (&sem->sem, &ts); if (r != 0) + err = errno; +#else + if (pthread_mutex_lock (&sem->mutex) != 0) + runtime_throw ("pthread_mutex_lock"); + + while ((r = sem_trywait (&sem->sem)) != 0) { - if (errno == ETIMEDOUT || errno == EINTR) + r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts); + if (r != 0) + { + err = r; + break; + } + } + + if (pthread_mutex_unlock (&sem->mutex) != 0) + runtime_throw ("pthread_mutex_unlock"); +#endif + + if (err != 0) + { + if (err == ETIMEDOUT || err == EAGAIN || err == EINTR) return -1; runtime_throw ("sema_timedwait"); } return 0; } - while (sem_wait ((sem_t *) m->waitsema) != 0) + while (sem_wait (&sem->sem) != 0) { if (errno == EINTR) continue; @@ -64,8 +119,20 @@ runtime_semasleep (int64 ns) void runtime_semawakeup (M *mp) { - if (sem_post ((sem_t *) mp->waitsema) != 0) + struct go_sem *sem; + + sem = (struct go_sem *) mp->waitsema; + if (sem_post (&sem->sem) != 0) runtime_throw ("sem_post"); + +#ifndef HAVE_SEM_TIMEDWAIT + if (pthread_mutex_lock (&sem->mutex) != 0) + runtime_throw ("pthread_mutex_lock"); + if (pthread_cond_broadcast (&sem->cond) != 0) + runtime_throw ("pthread_cond_broadcast"); + if (pthread_mutex_unlock (&sem->mutex) != 0) + runtime_throw ("pthread_mutex_unlock"); +#endif } void -- 2.11.0