/* 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 #include #include // 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 */