123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /* 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);
- }
- }
|