2015-05-22 Pascal Obry <obry@adacore.com>
[official-gcc.git] / libcilkrts / runtime / signal_node.c
blob92c404b482c5bc8800674ef362a02dd73b4051e3
1 /* signal_node.c -*-C-*-
3 *************************************************************************
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:
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.
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.
38 **************************************************************************/
40 #include "signal_node.h"
41 #include <stdlib.h>
43 /* Define cilk_semaphore_t for all of the respective systems. */
44 #if defined __APPLE__
45 # include <mach/mach_init.h>
46 # include <mach/semaphore.h>
47 # include <mach/task.h>
48 typedef semaphore_t cilk_semaphore_t;
49 #elif defined _WIN32
50 # include "windows-clean.h"
51 typedef HANDLE cilk_semaphore_t;
52 #else // Linux/MIC
53 # include <errno.h>
54 # include <semaphore.h>
55 # include <stdio.h>
56 typedef sem_t cilk_semaphore_t;
57 #endif // Linux/MIC
59 #include "bug.h"
60 #include "cilk_malloc.h"
61 #include "signal_node.h"
63 /**
64 * Interface within the tree to notify workers to wait without consuming cycles
65 * to expend cycles trying to steal.
67 * cilk_semaphore_t is implemented as an auto-reset event on Windows, and
68 * as a semaphore_t on Linux and MacOS.
70 struct signal_node_t
72 /** 0 if the worker should wait, 1 if it should be running. */
73 volatile unsigned int run;
75 /** OS-specific semaphore on which the worker can wait. */
76 cilk_semaphore_t sem;
79 /******************************************************************************/
80 /* Semaphore-abstraction functions */
81 /******************************************************************************/
84 * All of these functions are simple wrappers for the system-specific semaphore
85 * functions. This keeps the rest of the code reasonably clean and readable.
88 #if defined __APPLE__
89 static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
91 kern_return_t kstatus
92 = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, 0);
93 assert(kstatus == KERN_SUCCESS);
95 static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
97 kern_return_t kstatus = semaphore_destroy(mach_task_self(), *sem);
98 assert(kstatus == KERN_SUCCESS);
100 static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
102 kern_return_t kstatus = semaphore_wait(*sem);
103 assert(kstatus == KERN_SUCCESS);
105 static void signal_cilk_semaphore (cilk_semaphore_t *sem)
107 kern_return_t kstatus = semaphore_signal(*sem);
108 assert(kstatus == KERN_SUCCESS);
110 #elif defined _WIN32
111 // Note: Windows only provides counting semaphores, and we don't really
112 // care about the count. So this is implemented using an auto-reset
113 // event which will automatically reset after the WaitForSingleObject
114 // call
115 static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
117 // Create an auto-reset event
118 *sem = CreateEvent(NULL, // Security attributes
119 FALSE, // Manual reset
120 FALSE, // Initial state (initially reset)
121 NULL); // Name (anonymous)
122 CILK_ASSERT (NULL != *sem);
125 static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
127 BOOL result = CloseHandle(*sem);
128 CILK_ASSERT (0 != result);
131 static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
133 // WaitForSingleObject will reset the event
134 DWORD result = WaitForSingleObject (*sem, INFINITE);
135 CILK_ASSERT (WAIT_OBJECT_0 == result);
137 static void signal_cilk_semaphore (cilk_semaphore_t *sem)
139 BOOL result = SetEvent (*sem);
140 CILK_ASSERT (0 != result);
142 #else // Linux/MIC
143 static void initialize_cilk_semaphore (cilk_semaphore_t *sem)
145 int status = sem_init(sem, 0, 0);
146 assert(0 == status);
148 static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem)
150 int status = sem_destroy(sem);
151 assert(0 == status);
153 static void wait_on_cilk_semaphore (cilk_semaphore_t *sem)
155 int status;
157 do {
158 status = sem_wait(sem);
159 } while (status != 0 && errno == EINTR);
161 if (status != 0) {
162 perror("sem_wait");
163 abort();
166 static void signal_cilk_semaphore (cilk_semaphore_t *sem)
168 sem_post(sem);
170 #endif // Linux/MIC
172 /******************************************************************************/
173 /* Runtime interface functions */
174 /******************************************************************************/
177 * Return a newly malloc'd and initialized signal_node_t.
179 COMMON_SYSDEP
180 signal_node_t *signal_node_create(void)
182 signal_node_t *node;
184 node = ( signal_node_t*)
185 __cilkrts_malloc(sizeof( signal_node_t));
186 node->run = 0;
187 initialize_cilk_semaphore(&node->sem);
189 return node;
193 * Clean and free a signal_node_t.
195 void signal_node_destroy(signal_node_t *node)
197 CILK_ASSERT(node);
198 deinitialize_cilk_semaphore(&node->sem);
199 __cilkrts_free(node);
203 * Return 1 if the node thinks the worker should go to sleep, 0 otherwise.
205 unsigned int signal_node_should_wait(signal_node_t *node)
207 CILK_ASSERT(node);
208 return !node->run;
212 * Send a message to the node that the worker will eventually read.
214 void signal_node_msg(signal_node_t *node, unsigned int msg)
216 CILK_ASSERT(node);
217 switch (msg) {
218 case 0: // worker should go to sleep.
219 node->run = msg;
220 break;
221 case 1: // worker should be awake.
222 node->run = msg;
223 signal_cilk_semaphore(&node->sem);
224 break;
225 default: // error.
226 CILK_ASSERT(0 == "Bad signal_node_t message.");
231 * The current worker will wait on the semaphore.
233 void signal_node_wait(signal_node_t *node)
235 CILK_ASSERT(node);
236 while (signal_node_should_wait(node)) {
237 // The loop is here to consume extra semaphore signals that might have
238 // accumulated. No point in passing on the accumulation.
239 wait_on_cilk_semaphore(&node->sem);