1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 25 февр. 2019 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins 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 Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef INCLUDE_CORE_IPC_MUTEX_H_
23 #define INCLUDE_CORE_IPC_MUTEX_H_
24 
25 #include <core/types.h>
26 #include <dsp/atomic.h>
27 
28 #if defined(PLATFORM_WINDOWS)
29     #include <synchapi.h>
30 #elif defined(PLATFORM_LINUX)
31     #include <linux/futex.h>
32     #include <sys/syscall.h>
33     #include <unistd.h>
34     #include <pthread.h>
35     #include <sched.h>
36     #include <errno.h>
37 #else
38     #include <pthread.h>
39     #include <sched.h>
40     #include <errno.h>
41 #endif
42 
43 namespace lsp
44 {
45     namespace ipc
46     {
47 #if defined(PLATFORM_WINDOWS)
48         /**
49          * Recursive mutex for Windows platform
50          */
51         class Mutex
52         {
53             private:
54                 mutable HANDLE                  hMutex;     // Mutex object
55                 mutable DWORD                   nThreadId;  // Owner's thread identifier
56                 mutable atomic_t                nLocks;     // Number of locks by current thread
57 
58             private:
59                 Mutex & operator = (const Mutex & m);       // Deny copying
60 
61             public:
62                 explicit Mutex();
63                 ~Mutex();
64 
65                 /** Wait until mutex is unlocked and lock it
66                  *
67                  */
68                 bool lock() const;
69 
70                 /** Try to lock mutex and return status of operation
71                  *
72                  * @return non-zero value if mutex was locked
73                  */
74                 bool try_lock() const;
75 
76                 /** Unlock mutex
77                  *
78                  */
79                 bool unlock() const;
80         };
81 #elif defined(PLATFORM_LINUX)
82         /** Fast recursive mutex implementation for Linux
83          *
84          */
85         class Mutex
86         {
87             private:
88                 mutable volatile atomic_t       nLock;      // 1 = locked, 0 = locked
89                 mutable pthread_t               nThreadId;  // Locked thread identifier
90                 mutable atomic_t                nLocks;     // Number of locks by current thread
91 
92             private:
93                 Mutex & operator = (const Mutex & m);       // Deny copying
94 
95             public:
96                 explicit Mutex()
97                 {
98                     nLock       = 1;
99                     nThreadId   = -1;
100                     nLocks      = 0;
101                 }
102 
103                 /** Wait until mutex is unlocked and lock it
104                  *
105                  */
106                 bool lock() const;
107 
108                 /** Try to lock mutex and return status of operation
109                  *
110                  * @return non-zero value if mutex was locked
111                  */
112                 bool try_lock() const;
113 
114                 /** Unlock mutex
115                  *
116                  */
117                 bool unlock() const;
118         };
119 #else
120         /**
121          * Recursive mutex implementation using pthread
122          */
123         class Mutex
124         {
125             private:
126                 mutable pthread_mutex_t     sMutex;
127 
128             private:
129                 Mutex & operator = (const Mutex & m);       // Deny copying
130 
131             public:
132                 explicit Mutex();
133                 ~Mutex();
134 
135                 /** Wait until mutex is unlocked and lock it
136                  *
137                  */
138                 inline bool lock() const
139                 {
140                     while (true)
141                     {
142                         switch (pthread_mutex_lock(&sMutex))
143                         {
144                             case 0: return true;
145                             case EBUSY:
146                                 #ifdef PLATFORM_SOLARIS
147                                     sched_yield();
148                                 #else
149                                     pthread_yield();
150                                 #endif /* PLATFORM_SOLARIS */
151                                 break;
152                             default: return false;
153                         }
154                     }
155                 }
156 
157                 /** Try to lock mutex and return status of operation
158                  *
159                  * @return non-zero value if mutex was locked
160                  */
161                 inline bool try_lock() const
162                 {
163                     return pthread_mutex_trylock(&sMutex) == 0;
164                 }
165 
166                 /** Unlock mutex
167                  *
168                  */
169                 inline bool unlock() const
170                 {
171                     return pthread_mutex_unlock(&sMutex) == 0;
172                 }
173         };
174 #endif
175 
176     } /* namespace ipc */
177 } /* namespace lsp */
178 
179 #endif /* INCLUDE_CORE_IPC_MUTEX_H_ */
180