| /* os_mutex-unix.c -*-C-*- |
| * |
| ************************************************************************* |
| * |
| * @copyright |
| * Copyright (C) 2009-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 "os_mutex.h" |
| #include "bug.h" |
| |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <pthread.h> |
| |
| // contains notification macros for VTune. |
| #include "cilk-ittnotify.h" |
| |
| /* |
| * OS Mutex functions. |
| * |
| * Not to be confused with the spinlock mutexes implemented in cilk_mutex.c |
| */ |
| |
| struct os_mutex { |
| pthread_mutex_t mutex; ///< On Linux, os_mutex is implemented with a pthreads mutex |
| }; |
| |
| // Unix implementation of the global OS mutex. This will be created by the |
| // first call to global_os_mutex_lock() and *NEVER* destroyed. On gcc-based |
| // systems there's no way to guarantee the ordering of constructors and |
| // destructors, so we can't be guaranteed that our destructor for a static |
| // object will be called *after* any static destructors that may use Cilk |
| // in the user's application |
| static struct os_mutex *global_os_mutex = NULL; |
| |
| /* Sometimes during shared library load malloc doesn't work. |
| To handle that case, preallocate space for one mutex. */ |
| static struct os_mutex static_mutex; |
| static int static_mutex_used; |
| |
| struct os_mutex *__cilkrts_os_mutex_create(void) |
| { |
| int status; |
| struct os_mutex *mutex = (struct os_mutex *)malloc(sizeof(struct os_mutex)); |
| pthread_mutexattr_t attr; |
| |
| ITT_SYNC_CREATE(mutex, "OS Mutex"); |
| |
| if (!mutex) { |
| if (static_mutex_used) { |
| __cilkrts_bug("Cilk RTS library initialization failed"); |
| } else { |
| static_mutex_used = 1; |
| mutex = &static_mutex; |
| } |
| } |
| |
| status = pthread_mutexattr_init(&attr); |
| CILK_ASSERT (status == 0); |
| #if defined DEBUG || CILK_LIB_DEBUG |
| #ifdef PTHREAD_MUTEX_ERRORCHECK |
| status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); |
| #else |
| status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); |
| #endif |
| CILK_ASSERT (status == 0); |
| #endif |
| status = pthread_mutex_init (&mutex->mutex, &attr); |
| CILK_ASSERT (status == 0); |
| pthread_mutexattr_destroy(&attr); |
| |
| return mutex; |
| } |
| |
| void __cilkrts_os_mutex_lock(struct os_mutex *p) |
| { |
| int status; |
| status = pthread_mutex_lock (&p->mutex); |
| ITT_SYNC_ACQUIRED(p); |
| if (__builtin_expect(status, 0) == 0) |
| return; |
| if (status == EDEADLK) |
| __cilkrts_bug("Cilk runtime error: deadlock acquiring mutex %p\n", |
| p); |
| else |
| __cilkrts_bug("Cilk runtime error %d acquiring mutex %p\n", |
| status, p); |
| } |
| |
| int __cilkrts_os_mutex_trylock(struct os_mutex *p) |
| { |
| int status; |
| status = pthread_mutex_trylock (&p->mutex); |
| return (status == 0); |
| } |
| |
| void __cilkrts_os_mutex_unlock(struct os_mutex *p) |
| { |
| int status; |
| ITT_SYNC_RELEASING(p); |
| status = pthread_mutex_unlock (&p->mutex); |
| CILK_ASSERT(status == 0); |
| } |
| |
| void __cilkrts_os_mutex_destroy(struct os_mutex *p) |
| { |
| pthread_mutex_destroy (&p->mutex); |
| if (p == &static_mutex) { |
| static_mutex_used = 0; |
| } else { |
| free(p); |
| } |
| } |
| |
| /* |
| * create_global_os_mutex |
| * |
| * Function used with pthread_once to initialize the global OS mutex. Since |
| * pthread_once requires a function which takes no parameters and has no |
| * return value, the global OS mutex will be stored in the static (global |
| * to the compilation unit) variable "global_os_mutex." |
| * |
| * |
| * global_os_mutex will never be destroyed. |
| */ |
| static void create_global_os_mutex(void) |
| { |
| CILK_ASSERT(NULL == global_os_mutex); |
| global_os_mutex = __cilkrts_os_mutex_create(); |
| } |
| |
| void global_os_mutex_lock(void) |
| { |
| // pthread_once_t used with pthread_once to guarantee that |
| // create_global_os_mutex() is only called once |
| static pthread_once_t global_os_mutex_is_initialized = PTHREAD_ONCE_INIT; |
| |
| // Execute create_global_os_mutex once in a thread-safe manner |
| // Note that create_global_os_mutex returns the mutex in the static |
| // (global to the module) variable "global_os_mutex" |
| pthread_once(&global_os_mutex_is_initialized, |
| create_global_os_mutex); |
| |
| // We'd better have allocated a global_os_mutex |
| CILK_ASSERT(NULL != global_os_mutex); |
| |
| // Acquire the global OS mutex |
| __cilkrts_os_mutex_lock(global_os_mutex); |
| } |
| |
| void global_os_mutex_unlock(void) |
| { |
| // We'd better have allocated a global_os_mutex. This means you should |
| // have called global_os_mutex_lock() before calling |
| // global_os_mutex_unlock(), but this is the only check for it. |
| CILK_ASSERT(NULL != global_os_mutex); |
| |
| // Release the global OS mutex |
| __cilkrts_os_mutex_unlock(global_os_mutex); |
| } |
| |
| /* End os_mutex-unix.c */ |