// Copyright 2009 The Go Authors. All rights reserved. // 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 #include #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) { 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 (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; } /* Acquire m->waitsema. */ 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; #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) { 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->sem) != 0) { if (errno == EINTR) continue; runtime_throw ("sem_wait"); } return 0; } /* Wake up mp->waitsema. */ void runtime_semawakeup (M *mp) { 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 runtime_osinit (void) { runtime_ncpu = getproccount(); } void runtime_goenvs (void) { runtime_goenvs_unix (); }