1 /***************************************************************************
2  *                                                                         *
3  *   LinuxSampler - modular, streaming capable sampler                     *
4  *                                                                         *
5  *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6  *   Copyright (C) 2005 - 2020 Christian Schoenebeck                       *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  *   This program is distributed in the hope that it will be useful,       *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
16  *   GNU General Public License for more details.                          *
17  *                                                                         *
18  *   You should have received a copy of the GNU General Public License     *
19  *   along with this program; if not, write to the Free Software           *
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
21  *   MA  02111-1307  USA                                                   *
22  ***************************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27 
28 #if defined(__APPLE__)
29 # include <sys/cdefs.h> // defines the system macros checked below
30 #endif
31 
32 #ifndef _GNU_SOURCE
33 # define _GNU_SOURCE 1 /* so _XOPEN_SOURCE will be defined by features.h */
34 #endif
35 
36 #ifdef HAVE_FEATURES_H
37 # include <features.h>
38 #endif
39 
40 #if !defined(WIN32)
41 # if !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 500
42 #  undef _XOPEN_SOURCE
43 #  if (!defined(POSIX_C_SOURCE) || POSIX_C_SOURCE < 199801L) && !__DARWIN_UNIX03
44 #   warning "Seems you don't have a UNIX98 compatible system."
45 #   warning "Please run LinuxSampler's selftest to make sure this won't be a problem!"
46 #   warning "(compile tests with 'make tests', run them with 'src/testcases/linuxsamplertest')"
47 #  endif
48 # endif
49 #endif
50 
51 #include <iostream>
52 #include <errno.h>
53 #include <stdlib.h> /* for exit(int) */
54 
55 #include "Mutex.h"
56 
57 #if DEBUG_MUTEX
58 # include "Thread.h"
59 # include <assert.h>
60 # include "global_private.h"
61 #endif
62 
63 namespace LinuxSampler {
64 
Mutex(type_t type)65 Mutex::Mutex(type_t type) {
66 #if defined(WIN32)
67     hMutex = CreateMutex( NULL, FALSE, NULL);
68     if (hMutex == NULL) {
69         std::cerr << "Mutex Constructor: Fatal error - CreateMutex error " << GetLastError() << "\n";
70         exit(1);
71     }
72 #else
73     pthread_mutexattr_init(&__posix_mutexattr);
74     // pthread_mutexattr_settype() only works on UNIX98 compatible systems
75     switch (type) {
76     case RECURSIVE:
77         if (pthread_mutexattr_settype(&__posix_mutexattr, PTHREAD_MUTEX_RECURSIVE)) {
78             std::cerr << "Mutex Constructor: Fatal error - unable to pthread_mutexattr_settype(PTHREAD_MUTEX_RECURSIVE)\n" << std::flush;
79             exit(-1);
80         }
81         break;
82     case NON_RECURSIVE:
83         if (pthread_mutexattr_settype(&__posix_mutexattr, PTHREAD_MUTEX_ERRORCHECK)) {
84             std::cerr << "Mutex Constructor: Fatal error - unable to pthread_mutexattr_settype(PTHREAD_MUTEX_ERRORCHECK)\n" << std::flush;
85             exit(-1);
86         }
87         break;
88     default:
89         std::cerr << "Mutex Constructor: Fatal error - Unknown mutex type requested\n" << std::flush;
90         exit(-1);
91         break;
92     }
93     pthread_mutex_init(&__posix_mutex, &__posix_mutexattr);
94 #endif
95 #if DEBUG_MUTEX
96     debugSelf = false;
97     count = 0;
98 #endif
99 }
100 
~Mutex()101 Mutex::~Mutex() {
102 #if defined(WIN32)
103     CloseHandle(hMutex);
104 #else
105     pthread_mutex_destroy(&__posix_mutex);
106     pthread_mutexattr_destroy(&__posix_mutexattr);
107 #endif
108 }
109 
Lock()110 void Mutex::Lock() {
111 #if defined(WIN32)
112     WaitForSingleObject(hMutex, INFINITE);
113 #else
114     pthread_mutex_lock(&__posix_mutex);
115 #endif
116 #if DEBUG_MUTEX
117     if (debugSelf) {
118         std::string caller = Thread::nameOfCaller();
119         ++count;
120         assert(count > 0);
121         if (type != RECURSIVE)
122             assert(count == 1);
123         if (!owner.empty())
124             assert(owner == caller);
125         owner = caller;
126         backtrace = backtraceAsString();
127     }
128 #endif
129 }
130 
Trylock()131 bool Mutex::Trylock() {
132 #if defined(WIN32)
133     if( WaitForSingleObject(hMutex, 0) == WAIT_TIMEOUT) return false;
134 #else
135     if (pthread_mutex_trylock(&__posix_mutex) == EBUSY)
136         return false;
137 #endif
138 #if DEBUG_MUTEX
139     if (debugSelf) {
140         std::string caller = Thread::nameOfCaller();
141         ++count;
142         assert(count > 0);
143         if (type != RECURSIVE)
144             assert(count == 1);
145         if (!owner.empty())
146             assert(owner == caller);
147         owner = caller;
148         backtrace = backtraceAsString();
149     }
150 #endif
151     return true;
152 }
153 
Unlock()154 void Mutex::Unlock() {
155 #if DEBUG_MUTEX
156     if (debugSelf) {
157         std::string caller = Thread::nameOfCaller();
158         assert(count > 0);
159         --count;
160         assert(count >= 0);
161         assert(owner == caller);
162         if (!count)
163             owner.clear();
164     }
165 #endif
166 #if defined(WIN32)
167     ReleaseMutex(hMutex);
168 #else
169     pthread_mutex_unlock(&__posix_mutex);
170 #endif
171 }
172 
173 } // namespace LinuxSampler
174