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