diff options
Diffstat (limited to 'gcc-4.9/libcilkrts/runtime/signal_node.c')
-rw-r--r-- | gcc-4.9/libcilkrts/runtime/signal_node.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/gcc-4.9/libcilkrts/runtime/signal_node.c b/gcc-4.9/libcilkrts/runtime/signal_node.c new file mode 100644 index 000000000..92c404b48 --- /dev/null +++ b/gcc-4.9/libcilkrts/runtime/signal_node.c @@ -0,0 +1,241 @@ +/* signal_node.c -*-C-*- + * + ************************************************************************* + * + * @copyright + * Copyright (C) 2011-2013, Intel Corporation + * All rights reserved. + * + * @copyright + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * @copyright + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************/ + +#include "signal_node.h" +#include <stdlib.h> + +/* Define cilk_semaphore_t for all of the respective systems. */ +#if defined __APPLE__ +# include <mach/mach_init.h> +# include <mach/semaphore.h> +# include <mach/task.h> + typedef semaphore_t cilk_semaphore_t; +#elif defined _WIN32 +# include "windows-clean.h" + typedef HANDLE cilk_semaphore_t; +#else // Linux/MIC +# include <errno.h> +# include <semaphore.h> +# include <stdio.h> + typedef sem_t cilk_semaphore_t; +#endif // Linux/MIC + +#include "bug.h" +#include "cilk_malloc.h" +#include "signal_node.h" + +/** + * Interface within the tree to notify workers to wait without consuming cycles + * to expend cycles trying to steal. + * + * cilk_semaphore_t is implemented as an auto-reset event on Windows, and + * as a semaphore_t on Linux and MacOS. + */ +struct signal_node_t +{ + /** 0 if the worker should wait, 1 if it should be running. */ + volatile unsigned int run; + + /** OS-specific semaphore on which the worker can wait. */ + cilk_semaphore_t sem; +}; + +/******************************************************************************/ +/* Semaphore-abstraction functions */ +/******************************************************************************/ + +/* + * All of these functions are simple wrappers for the system-specific semaphore + * functions. This keeps the rest of the code reasonably clean and readable. + */ + +#if defined __APPLE__ +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus + = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, 0); + assert(kstatus == KERN_SUCCESS); +} +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_destroy(mach_task_self(), *sem); + assert(kstatus == KERN_SUCCESS); +} +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_wait(*sem); + assert(kstatus == KERN_SUCCESS); +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + kern_return_t kstatus = semaphore_signal(*sem); + assert(kstatus == KERN_SUCCESS); +} +#elif defined _WIN32 +// Note: Windows only provides counting semaphores, and we don't really +// care about the count. So this is implemented using an auto-reset +// event which will automatically reset after the WaitForSingleObject +// call +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + // Create an auto-reset event + *sem = CreateEvent(NULL, // Security attributes + FALSE, // Manual reset + FALSE, // Initial state (initially reset) + NULL); // Name (anonymous) + CILK_ASSERT (NULL != *sem); +} + +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + BOOL result = CloseHandle(*sem); + CILK_ASSERT (0 != result); +} + +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + // WaitForSingleObject will reset the event + DWORD result = WaitForSingleObject (*sem, INFINITE); + CILK_ASSERT (WAIT_OBJECT_0 == result); +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + BOOL result = SetEvent (*sem); + CILK_ASSERT (0 != result); +} +#else // Linux/MIC +static void initialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status = sem_init(sem, 0, 0); + assert(0 == status); +} +static void deinitialize_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status = sem_destroy(sem); + assert(0 == status); +} +static void wait_on_cilk_semaphore (cilk_semaphore_t *sem) +{ + int status; + + do { + status = sem_wait(sem); + } while (status != 0 && errno == EINTR); + + if (status != 0) { + perror("sem_wait"); + abort(); + } +} +static void signal_cilk_semaphore (cilk_semaphore_t *sem) +{ + sem_post(sem); +} +#endif // Linux/MIC + +/******************************************************************************/ +/* Runtime interface functions */ +/******************************************************************************/ + +/* + * Return a newly malloc'd and initialized signal_node_t. + */ +COMMON_SYSDEP +signal_node_t *signal_node_create(void) +{ + signal_node_t *node; + + node = ( signal_node_t*) + __cilkrts_malloc(sizeof( signal_node_t)); + node->run = 0; + initialize_cilk_semaphore(&node->sem); + + return node; +} + +/* + * Clean and free a signal_node_t. + */ +void signal_node_destroy(signal_node_t *node) +{ + CILK_ASSERT(node); + deinitialize_cilk_semaphore(&node->sem); + __cilkrts_free(node); +} + +/* + * Return 1 if the node thinks the worker should go to sleep, 0 otherwise. + */ +unsigned int signal_node_should_wait(signal_node_t *node) +{ + CILK_ASSERT(node); + return !node->run; +} + +/* + * Send a message to the node that the worker will eventually read. + */ +void signal_node_msg(signal_node_t *node, unsigned int msg) +{ + CILK_ASSERT(node); + switch (msg) { + case 0: // worker should go to sleep. + node->run = msg; + break; + case 1: // worker should be awake. + node->run = msg; + signal_cilk_semaphore(&node->sem); + break; + default: // error. + CILK_ASSERT(0 == "Bad signal_node_t message."); + } +} + +/* + * The current worker will wait on the semaphore. + */ +void signal_node_wait(signal_node_t *node) +{ + CILK_ASSERT(node); + while (signal_node_should_wait(node)) { + // The loop is here to consume extra semaphore signals that might have + // accumulated. No point in passing on the accumulation. + wait_on_cilk_semaphore(&node->sem); + } +} |