signal_node.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* signal_node.c -*-C-*-
  2. *
  3. *************************************************************************
  4. *
  5. * @copyright
  6. * Copyright (C) 2011-2013, Intel Corporation
  7. * All rights reserved.
  8. *
  9. * @copyright
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. * * Redistributions in binary form must reproduce the above copyright
  17. * notice, this list of conditions and the following disclaimer in
  18. * the documentation and/or other materials provided with the
  19. * distribution.
  20. * * Neither the name of Intel Corporation nor the names of its
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * @copyright
  25. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  26. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  27. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  28. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  29. * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  30. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  31. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  32. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  33. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  35. * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. **************************************************************************/
  39. #include "signal_node.h"
  40. #include <stdlib.h>
  41. /* Define cilk_semaphore_t for all of the respective systems. */
  42. #if defined __APPLE__
  43. # include <mach/mach_init.h>
  44. # include <mach/semaphore.h>
  45. # include <mach/task.h>
  46. typedef semaphore_t cilk_semaphore_t;
  47. #elif defined _WIN32
  48. # include "windows-clean.h"
  49. typedef HANDLE cilk_semaphore_t;
  50. #else // Linux/MIC
  51. # include <errno.h>
  52. # include <semaphore.h>
  53. # include <stdio.h>
  54. typedef sem_t cilk_semaphore_t;
  55. #endif // Linux/MIC
  56. #include "bug.h"
  57. #include "cilk_malloc.h"
  58. #include "signal_node.h"
  59. /**
  60. * Interface within the tree to notify workers to wait without consuming cycles
  61. * to expend cycles trying to steal.
  62. *
  63. * cilk_semaphore_t is implemented as an auto-reset event on Windows, and
  64. * as a semaphore_t on Linux and MacOS.
  65. */
  66. struct signal_node_t
  67. {
  68. /** 0 if the worker should wait, 1 if it should be running. */
  69. volatile unsigned int run;
  70. /** OS-specific semaphore on which the worker can wait. */
  71. cilk_semaphore_t sem;
  72. };
  73. /******************************************************************************/
  74. /* Semaphore-abstraction functions */
  75. /******************************************************************************/
  76. /*
  77. * All of these functions are simple wrappers for the system-specific semaphore
  78. * functions. This keeps the rest of the code reasonably clean and readable.
  79. */
  80. #if defined __APPLE__
  81. static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
  82. {
  83. kern_return_t kstatus
  84. = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, 0);
  85. assert(kstatus == KERN_SUCCESS);
  86. }
  87. static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
  88. {
  89. kern_return_t kstatus = semaphore_destroy(mach_task_self(), *sem);
  90. assert(kstatus == KERN_SUCCESS);
  91. }
  92. static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
  93. {
  94. kern_return_t kstatus = semaphore_wait(*sem);
  95. assert(kstatus == KERN_SUCCESS);
  96. }
  97. static void signal_cilk_semaphore (cilk_semaphore_t *sem)
  98. {
  99. kern_return_t kstatus = semaphore_signal(*sem);
  100. assert(kstatus == KERN_SUCCESS);
  101. }
  102. #elif defined _WIN32
  103. // Note: Windows only provides counting semaphores, and we don't really
  104. // care about the count. So this is implemented using an auto-reset
  105. // event which will automatically reset after the WaitForSingleObject
  106. // call
  107. static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
  108. {
  109. // Create an auto-reset event
  110. *sem = CreateEvent(NULL, // Security attributes
  111. FALSE, // Manual reset
  112. FALSE, // Initial state (initially reset)
  113. NULL); // Name (anonymous)
  114. CILK_ASSERT (NULL != *sem);
  115. }
  116. static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
  117. {
  118. BOOL result = CloseHandle(*sem);
  119. CILK_ASSERT (0 != result);
  120. }
  121. static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
  122. {
  123. // WaitForSingleObject will reset the event
  124. DWORD result = WaitForSingleObject (*sem, INFINITE);
  125. CILK_ASSERT (WAIT_OBJECT_0 == result);
  126. }
  127. static void signal_cilk_semaphore (cilk_semaphore_t *sem)
  128. {
  129. BOOL result = SetEvent (*sem);
  130. CILK_ASSERT (0 != result);
  131. }
  132. #else // Linux/MIC
  133. static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
  134. {
  135. int status = sem_init(sem, 0, 0);
  136. assert(0 == status);
  137. }
  138. static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
  139. {
  140. int status = sem_destroy(sem);
  141. assert(0 == status);
  142. }
  143. static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
  144. {
  145. int status;
  146. do {
  147. status = sem_wait(sem);
  148. } while (status != 0 && errno == EINTR);
  149. if (status != 0) {
  150. perror("sem_wait");
  151. abort();
  152. }
  153. }
  154. static void signal_cilk_semaphore (cilk_semaphore_t *sem)
  155. {
  156. sem_post(sem);
  157. }
  158. #endif // Linux/MIC
  159. /******************************************************************************/
  160. /* Runtime interface functions */
  161. /******************************************************************************/
  162. /*
  163. * Return a newly malloc'd and initialized signal_node_t.
  164. */
  165. COMMON_SYSDEP
  166. signal_node_t *signal_node_create(void)
  167. {
  168. signal_node_t *node;
  169. node = ( signal_node_t*)
  170. __cilkrts_malloc(sizeof( signal_node_t));
  171. node->run = 0;
  172. initialize_cilk_semaphore(&node->sem);
  173. return node;
  174. }
  175. /*
  176. * Clean and free a signal_node_t.
  177. */
  178. void signal_node_destroy(signal_node_t *node)
  179. {
  180. CILK_ASSERT(node);
  181. deinitialize_cilk_semaphore(&node->sem);
  182. __cilkrts_free(node);
  183. }
  184. /*
  185. * Return 1 if the node thinks the worker should go to sleep, 0 otherwise.
  186. */
  187. unsigned int signal_node_should_wait(signal_node_t *node)
  188. {
  189. CILK_ASSERT(node);
  190. return !node->run;
  191. }
  192. /*
  193. * Send a message to the node that the worker will eventually read.
  194. */
  195. void signal_node_msg(signal_node_t *node, unsigned int msg)
  196. {
  197. CILK_ASSERT(node);
  198. switch (msg) {
  199. case 0: // worker should go to sleep.
  200. node->run = msg;
  201. break;
  202. case 1: // worker should be awake.
  203. node->run = msg;
  204. signal_cilk_semaphore(&node->sem);
  205. break;
  206. default: // error.
  207. CILK_ASSERT(0 == "Bad signal_node_t message.");
  208. }
  209. }
  210. /*
  211. * The current worker will wait on the semaphore.
  212. */
  213. void signal_node_wait(signal_node_t *node)
  214. {
  215. CILK_ASSERT(node);
  216. while (signal_node_should_wait(node)) {
  217. // The loop is here to consume extra semaphore signals that might have
  218. // accumulated. No point in passing on the accumulation.
  219. wait_on_cilk_semaphore(&node->sem);
  220. }
  221. }