1 /* os_mutex-unix.c                  -*-C-*-
2  *
3  *************************************************************************
4  *
5  *  @copyright
6  *  Copyright (C) 2009-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:
13  *
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.
23  *
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.
37  **************************************************************************/
38 
39 #include "os_mutex.h"
40 #include "bug.h"
41 
42 #include <stdlib.h>
43 #include <errno.h>
44 #include <pthread.h>
45 
46 // contains notification macros for VTune.
47 #include "cilk-ittnotify.h"
48 
49 /*
50  * OS Mutex functions.
51  *
52  * Not to be confused with the spinlock mutexes implemented in cilk_mutex.c
53  */
54 
55 struct os_mutex {
56     pthread_mutex_t mutex;  ///< On Linux, os_mutex is implemented with a pthreads mutex
57 };
58 
59 // Unix implementation of the global OS mutex.  This will be created by the
60 // first call to global_os_mutex_lock() and *NEVER* destroyed.  On gcc-based
61 // systems there's no way to guarantee the ordering of constructors and
62 // destructors, so we can't be guaranteed that our destructor for a static
63 // object will be called *after* any static destructors that may use Cilk
64 // in the user's application
65 static struct os_mutex *global_os_mutex = NULL;
66 
67 /* Sometimes during shared library load malloc doesn't work.
68    To handle that case, preallocate space for one mutex. */
69 static struct os_mutex static_mutex;
70 static int static_mutex_used;
71 
__cilkrts_os_mutex_create(void)72 struct os_mutex *__cilkrts_os_mutex_create(void)
73 {
74     int status;
75     struct os_mutex *mutex = (struct os_mutex *)malloc(sizeof(struct os_mutex));
76     pthread_mutexattr_t attr;
77 
78     ITT_SYNC_CREATE(mutex, "OS Mutex");
79 
80     if (!mutex) {
81         if (static_mutex_used) {
82             __cilkrts_bug("Cilk RTS library initialization failed");
83         } else {
84             static_mutex_used = 1;
85             mutex = &static_mutex;
86         }
87     }
88 
89     status = pthread_mutexattr_init(&attr);
90     CILK_ASSERT (status == 0);
91 #if defined DEBUG || CILK_LIB_DEBUG
92 #ifdef PTHREAD_MUTEX_ERRORCHECK
93     status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
94 #else
95     status = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
96 #endif
97     CILK_ASSERT (status == 0);
98 #endif
99     status = pthread_mutex_init (&mutex->mutex, &attr);
100     CILK_ASSERT (status == 0);
101     pthread_mutexattr_destroy(&attr);
102 
103     return mutex;
104 }
105 
__cilkrts_os_mutex_lock(struct os_mutex * p)106 void __cilkrts_os_mutex_lock(struct os_mutex *p)
107 {
108     int status;
109     status = pthread_mutex_lock (&p->mutex);
110     ITT_SYNC_ACQUIRED(p);
111     if (__builtin_expect(status, 0) == 0)
112         return;
113     if (status == EDEADLK)
114         __cilkrts_bug("Cilk runtime error: deadlock acquiring mutex %p\n",
115                       p);
116     else
117         __cilkrts_bug("Cilk runtime error %d acquiring mutex %p\n",
118                       status, p);
119 }
120 
__cilkrts_os_mutex_trylock(struct os_mutex * p)121 int __cilkrts_os_mutex_trylock(struct os_mutex *p)
122 {
123     int status;
124     status = pthread_mutex_trylock (&p->mutex);
125     return (status == 0);
126 }
127 
__cilkrts_os_mutex_unlock(struct os_mutex * p)128 void __cilkrts_os_mutex_unlock(struct os_mutex *p)
129 {
130     int status;
131     ITT_SYNC_RELEASING(p);
132     status = pthread_mutex_unlock (&p->mutex);
133     CILK_ASSERT(status == 0);
134 }
135 
__cilkrts_os_mutex_destroy(struct os_mutex * p)136 void __cilkrts_os_mutex_destroy(struct os_mutex *p)
137 {
138     pthread_mutex_destroy (&p->mutex);
139     if (p == &static_mutex) {
140         static_mutex_used = 0;
141     } else {
142         free(p);
143     }
144 }
145 
146 /*
147  * create_global_os_mutex
148  *
149  * Function used with pthread_once to initialize the global OS mutex.  Since
150  * pthread_once requires a function which takes no parameters and has no
151  * return value, the global OS mutex will be stored in the static (global
152  * to the compilation unit) variable "global_os_mutex."
153  *
154  *
155  * global_os_mutex will never be destroyed.
156  */
create_global_os_mutex(void)157 static void create_global_os_mutex(void)
158 {
159     CILK_ASSERT(NULL == global_os_mutex);
160     global_os_mutex = __cilkrts_os_mutex_create();
161 }
162 
global_os_mutex_lock(void)163 void global_os_mutex_lock(void)
164 {
165     // pthread_once_t used with pthread_once to guarantee that
166     // create_global_os_mutex() is only called once
167     static pthread_once_t global_os_mutex_is_initialized = PTHREAD_ONCE_INIT;
168 
169     // Execute create_global_os_mutex once in a thread-safe manner
170     // Note that create_global_os_mutex returns the mutex in the static
171     // (global to the module) variable "global_os_mutex"
172     pthread_once(&global_os_mutex_is_initialized,
173 		 create_global_os_mutex);
174 
175     // We'd better have allocated a global_os_mutex
176     CILK_ASSERT(NULL != global_os_mutex);
177 
178     // Acquire the global OS mutex
179     __cilkrts_os_mutex_lock(global_os_mutex);
180 }
181 
global_os_mutex_unlock(void)182 void global_os_mutex_unlock(void)
183 {
184     // We'd better have allocated a global_os_mutex.  This means you should
185     // have called global_os_mutex_lock() before calling
186     // global_os_mutex_unlock(), but this is the only check for it.
187     CILK_ASSERT(NULL != global_os_mutex);
188 
189     // Release the global OS mutex
190     __cilkrts_os_mutex_unlock(global_os_mutex);
191 }
192 
193 /* End os_mutex-unix.c */
194