thread-sema.c 3.0 KB

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