1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "config.h" 6 #include "runtime.h" 7 8 #include <errno.h> 9 #include <stdlib.h> 10 #include <time.h> 11 #include <semaphore.h> 12 13 /* If we don't have sem_timedwait, use pthread_cond_timedwait instead. 14 We don't always use condition variables because on some systems 15 pthread_mutex_lock and pthread_mutex_unlock must be called by the 16 same thread. That is never true of semaphores. */ 17 18 struct go_sem 19 { 20 sem_t sem; 21 22 #ifndef HAVE_SEM_TIMEDWAIT 23 int timedwait; 24 pthread_mutex_t mutex; 25 pthread_cond_t cond; 26 #endif 27 }; 28 29 /* Create a semaphore. */ 30 31 uintptr runtime_semacreate(void)32runtime_semacreate(void) 33 { 34 struct go_sem *p; 35 36 /* Call malloc rather than runtime_malloc. This will allocate space 37 on the C heap. We can't call runtime_malloc here because it 38 could cause a deadlock. */ 39 p = malloc (sizeof (struct go_sem)); 40 if (sem_init (&p->sem, 0, 0) != 0) 41 runtime_throw ("sem_init"); 42 43 #ifndef HAVE_SEM_TIMEDWAIT 44 if (pthread_mutex_init (&p->mutex, NULL) != 0) 45 runtime_throw ("pthread_mutex_init"); 46 if (pthread_cond_init (&p->cond, NULL) != 0) 47 runtime_throw ("pthread_cond_init"); 48 #endif 49 50 return (uintptr) p; 51 } 52 53 /* Acquire m->waitsema. */ 54 55 int32 runtime_semasleep(int64 ns)56runtime_semasleep (int64 ns) 57 { 58 M *m; 59 struct go_sem *sem; 60 int r; 61 62 m = runtime_m (); 63 sem = (struct go_sem *) m->waitsema; 64 if (ns >= 0) 65 { 66 int64 abs; 67 struct timespec ts; 68 int err; 69 70 abs = ns + runtime_nanotime (); 71 ts.tv_sec = abs / 1000000000LL; 72 ts.tv_nsec = abs % 1000000000LL; 73 74 err = 0; 75 76 #ifdef HAVE_SEM_TIMEDWAIT 77 r = sem_timedwait (&sem->sem, &ts); 78 if (r != 0) 79 err = errno; 80 #else 81 if (pthread_mutex_lock (&sem->mutex) != 0) 82 runtime_throw ("pthread_mutex_lock"); 83 84 while ((r = sem_trywait (&sem->sem)) != 0) 85 { 86 r = pthread_cond_timedwait (&sem->cond, &sem->mutex, &ts); 87 if (r != 0) 88 { 89 err = r; 90 break; 91 } 92 } 93 94 if (pthread_mutex_unlock (&sem->mutex) != 0) 95 runtime_throw ("pthread_mutex_unlock"); 96 #endif 97 98 if (err != 0) 99 { 100 if (err == ETIMEDOUT || err == EAGAIN || err == EINTR) 101 return -1; 102 runtime_throw ("sema_timedwait"); 103 } 104 return 0; 105 } 106 107 while (sem_wait (&sem->sem) != 0) 108 { 109 if (errno == EINTR) 110 continue; 111 runtime_throw ("sem_wait"); 112 } 113 114 return 0; 115 } 116 117 /* Wake up mp->waitsema. */ 118 119 void runtime_semawakeup(M * mp)120runtime_semawakeup (M *mp) 121 { 122 struct go_sem *sem; 123 124 sem = (struct go_sem *) mp->waitsema; 125 if (sem_post (&sem->sem) != 0) 126 runtime_throw ("sem_post"); 127 128 #ifndef HAVE_SEM_TIMEDWAIT 129 if (pthread_mutex_lock (&sem->mutex) != 0) 130 runtime_throw ("pthread_mutex_lock"); 131 if (pthread_cond_broadcast (&sem->cond) != 0) 132 runtime_throw ("pthread_cond_broadcast"); 133 if (pthread_mutex_unlock (&sem->mutex) != 0) 134 runtime_throw ("pthread_mutex_unlock"); 135 #endif 136 } 137 138 void runtime_osinit(void)139runtime_osinit (void) 140 { 141 runtime_ncpu = getproccount(); 142 } 143 144 void runtime_goenvs(void)145runtime_goenvs (void) 146 { 147 runtime_goenvs_unix (); 148 } 149