1 /**
2 * Mutex.cpp
3 * This file is part of the YATE Project http://YATE.null.ro
4 *
5 * Yet Another Telephony Engine - a fully featured software PBX and IVR
6 * Copyright (C) 2004-2014 Null Team
7 *
8 * This software is distributed under multiple licenses;
9 * see the COPYING file in the main directory for licensing
10 * information for this specific distribution.
11 *
12 * This use of this software may be subject to additional restrictions.
13 * See the LEGAL file in the main directory for details.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20 #include "yateclass.h"
21
22 #ifdef _WINDOWS
23
24 typedef HANDLE HMUTEX;
25 typedef HANDLE HSEMAPHORE;
26
27 #else
28
29 #include <pthread.h>
30 #include <semaphore.h>
31 #include <time.h>
32
33 #ifdef MUTEX_HACK
34 extern "C" {
35 #if (defined(__FreeBSD__)||defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
36 extern int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind);
37 #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
38 #else
39 extern int pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind) __THROW;
40 #endif
41 }
42 #endif
43
44 typedef pthread_mutex_t HMUTEX;
45 typedef sem_t HSEMAPHORE;
46
47 #endif /* ! _WINDOWS */
48
49 #ifdef MUTEX_STATIC_UNSAFE
50 #undef MUTEX_STATIC_UNSAFE
51 #define MUTEX_STATIC_UNSAFE true
52 #else
53 #define MUTEX_STATIC_UNSAFE false
54 #endif
55
56 namespace TelEngine {
57
58 class MutexPrivate {
59 public:
60 MutexPrivate(bool recursive, const char* name);
61 ~MutexPrivate();
ref()62 inline void ref()
63 { ++m_refcount; }
deref()64 inline void deref()
65 { if (!--m_refcount) delete this; }
recursive() const66 inline bool recursive() const
67 { return m_recursive; }
name() const68 inline const char* name() const
69 { return m_name; }
owner() const70 inline const char* owner() const
71 { return m_owner; }
locked() const72 bool locked() const
73 { return (m_locked > 0); }
74 bool lock(long maxwait);
75 bool unlock();
76 static volatile int s_count;
77 static volatile int s_locks;
78 private:
79 HMUTEX m_mutex;
80 int m_refcount;
81 volatile unsigned int m_locked;
82 volatile unsigned int m_waiting;
83 bool m_recursive;
84 const char* m_name;
85 const char* m_owner;
86 };
87
88 class SemaphorePrivate {
89 public:
90 SemaphorePrivate(unsigned int maxcount, const char* name, unsigned int initialCount);
91 ~SemaphorePrivate();
ref()92 inline void ref()
93 { ++m_refcount; }
deref()94 inline void deref()
95 { if (!--m_refcount) delete this; }
name() const96 inline const char* name() const
97 { return m_name; }
locked() const98 bool locked() const
99 { return (m_waiting > 0); }
100 bool lock(long maxwait);
101 bool unlock();
102 static volatile int s_count;
103 static volatile int s_locks;
104 private:
105 HSEMAPHORE m_semaphore;
106 int m_refcount;
107 volatile unsigned int m_waiting;
108 unsigned int m_maxcount;
109 const char* m_name;
110 };
111
112 class GlobalMutex {
113 public:
114 GlobalMutex();
115 static void init();
116 static void lock();
117 static void unlock();
118 private:
119 static bool s_init;
120 static HMUTEX s_mutex;
121 };
122
123 };
124
125 using namespace TelEngine;
126
127 HMUTEX GlobalMutex::s_mutex;
128 static GlobalMutex s_global;
129 static unsigned long s_maxwait = 0;
130 static bool s_unsafe = MUTEX_STATIC_UNSAFE;
131 static bool s_safety = false;
132
133 volatile int MutexPrivate::s_count = 0;
134 volatile int MutexPrivate::s_locks = 0;
135 volatile int SemaphorePrivate::s_count = 0;
136 volatile int SemaphorePrivate::s_locks = 0;
137 bool GlobalMutex::s_init = true;
138
139 // WARNING!!!
140 // No debug messages are allowed in mutexes since the debug output itself
141 // is serialized using a mutex!
142
init()143 void GlobalMutex::init()
144 {
145 if (s_init) {
146 s_init = false;
147 #ifdef _WINDOWS
148 s_mutex = ::CreateMutex(NULL,FALSE,NULL);
149 #else
150 pthread_mutexattr_t attr;
151 ::pthread_mutexattr_init(&attr);
152 ::pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);
153 ::pthread_mutex_init(&s_mutex,&attr);
154 ::pthread_mutexattr_destroy(&attr);
155 #endif
156 }
157 }
158
GlobalMutex()159 GlobalMutex::GlobalMutex()
160 {
161 init();
162 }
163
lock()164 void GlobalMutex::lock()
165 {
166 init();
167 if (s_unsafe)
168 return;
169 #ifdef _WINDOWS
170 ::WaitForSingleObject(s_mutex,INFINITE);
171 #else
172 ::pthread_mutex_lock(&s_mutex);
173 #endif
174 }
175
unlock()176 void GlobalMutex::unlock()
177 {
178 if (s_unsafe)
179 return;
180 #ifdef _WINDOWS
181 ::ReleaseMutex(s_mutex);
182 #else
183 ::pthread_mutex_unlock(&s_mutex);
184 #endif
185 }
186
187
MutexPrivate(bool recursive,const char * name)188 MutexPrivate::MutexPrivate(bool recursive, const char* name)
189 : m_refcount(1), m_locked(0), m_waiting(0), m_recursive(recursive),
190 m_name(name), m_owner(0)
191 {
192 GlobalMutex::lock();
193 s_count++;
194 #ifdef _WINDOWS
195 // All mutexes are recursive in Windows
196 m_mutex = ::CreateMutex(NULL,FALSE,NULL);
197 #else
198 if (recursive) {
199 pthread_mutexattr_t attr;
200 ::pthread_mutexattr_init(&attr);
201 ::pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE_NP);
202 ::pthread_mutex_init(&m_mutex,&attr);
203 ::pthread_mutexattr_destroy(&attr);
204 }
205 else
206 ::pthread_mutex_init(&m_mutex,0);
207 #endif
208 GlobalMutex::unlock();
209 }
210
~MutexPrivate()211 MutexPrivate::~MutexPrivate()
212 {
213 bool warn = false;
214 GlobalMutex::lock();
215 if (m_locked) {
216 warn = true;
217 m_locked--;
218 if (s_safety)
219 s_locks--;
220 #ifdef _WINDOWS
221 ::ReleaseMutex(m_mutex);
222 #else
223 ::pthread_mutex_unlock(&m_mutex);
224 #endif
225 }
226 s_count--;
227 #ifdef _WINDOWS
228 ::CloseHandle(m_mutex);
229 m_mutex = 0;
230 #else
231 ::pthread_mutex_destroy(&m_mutex);
232 #endif
233 GlobalMutex::unlock();
234 if (m_locked || m_waiting)
235 Debug(DebugFail,"MutexPrivate '%s' owned by '%s' destroyed with %u locks, %u waiting [%p]",
236 m_name,m_owner,m_locked,m_waiting,this);
237 else if (warn)
238 Debug(DebugCrit,"MutexPrivate '%s' owned by '%s' unlocked in destructor [%p]",
239 m_name,m_owner,this);
240 }
241
lock(long maxwait)242 bool MutexPrivate::lock(long maxwait)
243 {
244 bool rval = false;
245 bool warn = false;
246 if (s_maxwait && (maxwait < 0)) {
247 maxwait = (long)s_maxwait;
248 warn = true;
249 }
250 bool safety = s_safety;
251 if (safety)
252 GlobalMutex::lock();
253 Thread* thr = Thread::current();
254 if (thr)
255 thr->m_locking = true;
256 if (safety) {
257 m_waiting++;
258 GlobalMutex::unlock();
259 }
260 #ifdef _WINDOWS
261 DWORD ms = 0;
262 if (maxwait < 0)
263 ms = INFINITE;
264 else if (maxwait > 0)
265 ms = (DWORD)(maxwait / 1000);
266 rval = s_unsafe || (::WaitForSingleObject(m_mutex,ms) == WAIT_OBJECT_0);
267 #else
268 if (s_unsafe)
269 rval = true;
270 else if (maxwait < 0)
271 rval = !::pthread_mutex_lock(&m_mutex);
272 else if (!maxwait)
273 rval = !::pthread_mutex_trylock(&m_mutex);
274 else {
275 u_int64_t t = Time::now() + maxwait;
276 #ifdef HAVE_TIMEDLOCK
277 struct timeval tv;
278 struct timespec ts;
279 Time::toTimeval(&tv,t);
280 ts.tv_sec = tv.tv_sec;
281 ts.tv_nsec = 1000 * tv.tv_usec;
282 rval = !::pthread_mutex_timedlock(&m_mutex,&ts);
283 #else
284 bool dead = false;
285 do {
286 if (!dead) {
287 dead = Thread::check(false);
288 // give up only if caller asked for a limited wait
289 if (dead && !warn)
290 break;
291 }
292 rval = !::pthread_mutex_trylock(&m_mutex);
293 if (rval)
294 break;
295 Thread::yield();
296 } while (t > Time::now());
297 #endif // HAVE_TIMEDLOCK
298 }
299 #endif // _WINDOWS
300 if (safety) {
301 GlobalMutex::lock();
302 m_waiting--;
303 }
304 if (thr)
305 thr->m_locking = false;
306 if (rval) {
307 if (safety)
308 s_locks++;
309 m_locked++;
310 if (thr) {
311 thr->m_locks++;
312 m_owner = thr->name();
313 }
314 else
315 m_owner = 0;
316 }
317 if (safety)
318 GlobalMutex::unlock();
319 if (warn && !rval)
320 Debug(DebugFail,"Thread '%s' could not lock mutex '%s' owned by '%s' waited by %u others for %lu usec!",
321 Thread::currentName(),m_name,m_owner,m_waiting,maxwait);
322 return rval;
323 }
324
unlock()325 bool MutexPrivate::unlock()
326 {
327 bool ok = false;
328 // Hope we don't hit a bug related to the debug mutex!
329 bool safety = s_safety;
330 if (safety)
331 GlobalMutex::lock();
332 if (m_locked) {
333 Thread* thr = Thread::current();
334 if (thr)
335 thr->m_locks--;
336 if (!--m_locked) {
337 const char* tname = thr ? thr->name() : 0;
338 if (tname != m_owner)
339 Debug(DebugFail,"MutexPrivate '%s' unlocked by '%s' but owned by '%s' [%p]",
340 m_name,tname,m_owner,this);
341 m_owner = 0;
342 }
343 if (safety) {
344 int locks = --s_locks;
345 if (locks < 0) {
346 // this is very very bad - abort right now
347 abortOnBug(true);
348 s_locks = 0;
349 Debug(DebugFail,"MutexPrivate::locks() is %d [%p]",locks,this);
350 }
351 }
352 #ifdef _WINDOWS
353 ok = s_unsafe || ::ReleaseMutex(m_mutex);
354 #else
355 ok = s_unsafe || !::pthread_mutex_unlock(&m_mutex);
356 #endif
357 if (!ok)
358 Debug(DebugFail,"Failed to unlock mutex '%s' [%p]",m_name,this);
359 }
360 else
361 Debug(DebugFail,"MutexPrivate::unlock called on unlocked '%s' [%p]",m_name,this);
362 if (safety)
363 GlobalMutex::unlock();
364 return ok;
365 }
366
367
SemaphorePrivate(unsigned int maxcount,const char * name,unsigned int initialCount)368 SemaphorePrivate::SemaphorePrivate(unsigned int maxcount, const char* name,
369 unsigned int initialCount)
370 : m_refcount(1), m_waiting(0), m_maxcount(maxcount),
371 m_name(name)
372 {
373 if (initialCount > m_maxcount)
374 initialCount = m_maxcount;
375 GlobalMutex::lock();
376 s_count++;
377 #ifdef _WINDOWS
378 m_semaphore = ::CreateSemaphore(NULL,initialCount,maxcount,NULL);
379 #else
380 ::sem_init(&m_semaphore,0,initialCount);
381 #endif
382 GlobalMutex::unlock();
383 }
384
~SemaphorePrivate()385 SemaphorePrivate::~SemaphorePrivate()
386 {
387 GlobalMutex::lock();
388 s_count--;
389 #ifdef _WINDOWS
390 ::CloseHandle(m_semaphore);
391 m_semaphore = 0;
392 #else
393 ::sem_destroy(&m_semaphore);
394 #endif
395 GlobalMutex::unlock();
396 if (m_waiting)
397 Debug(DebugFail,"SemaphorePrivate '%s' destroyed with %u locks [%p]",
398 m_name,m_waiting,this);
399 }
400
lock(long maxwait)401 bool SemaphorePrivate::lock(long maxwait)
402 {
403 bool rval = false;
404 bool warn = false;
405 if (s_maxwait && (maxwait < 0)) {
406 maxwait = (long)s_maxwait;
407 warn = true;
408 }
409 bool safety = s_safety;
410 if (safety)
411 GlobalMutex::lock();
412 Thread* thr = Thread::current();
413 if (thr)
414 thr->m_locking = true;
415 if (safety) {
416 s_locks++;
417 m_waiting++;
418 GlobalMutex::unlock();
419 }
420 #ifdef _WINDOWS
421 DWORD ms = 0;
422 if (maxwait < 0)
423 ms = INFINITE;
424 else if (maxwait > 0)
425 ms = (DWORD)(maxwait / 1000);
426 rval = s_unsafe || (::WaitForSingleObject(m_semaphore,ms) == WAIT_OBJECT_0);
427 #else
428 if (s_unsafe)
429 rval = true;
430 else if (maxwait < 0)
431 rval = !::sem_wait(&m_semaphore);
432 else if (!maxwait)
433 rval = !::sem_trywait(&m_semaphore);
434 else {
435 u_int64_t t = Time::now() + maxwait;
436 #ifdef HAVE_TIMEDWAIT
437 struct timeval tv;
438 struct timespec ts;
439 Time::toTimeval(&tv,t);
440 ts.tv_sec = tv.tv_sec;
441 ts.tv_nsec = 1000 * tv.tv_usec;
442 rval = !::sem_timedwait(&m_semaphore,&ts);
443 #else
444 bool dead = false;
445 do {
446 if (!dead) {
447 dead = Thread::check(false);
448 // give up only if caller asked for a limited wait
449 if (dead && !warn)
450 break;
451 }
452 rval = !::sem_trywait(&m_semaphore);
453 if (rval)
454 break;
455 Thread::yield();
456 } while (t > Time::now());
457 #endif // HAVE_TIMEDWAIT
458 }
459 #endif // _WINDOWS
460 if (safety) {
461 GlobalMutex::lock();
462 int locks = --s_locks;
463 if (locks < 0) {
464 // this is very very bad - abort right now
465 abortOnBug(true);
466 s_locks = 0;
467 Debug(DebugFail,"SemaphorePrivate::locks() is %d [%p]",locks,this);
468 }
469 m_waiting--;
470 }
471 if (thr)
472 thr->m_locking = false;
473 if (safety)
474 GlobalMutex::unlock();
475 if (warn && !rval)
476 Debug(DebugFail,"Thread '%s' could not lock semaphore '%s' waited by %u others for %lu usec!",
477 Thread::currentName(),m_name,m_waiting,maxwait);
478 return rval;
479 }
480
unlock()481 bool SemaphorePrivate::unlock()
482 {
483 if (!s_unsafe) {
484 bool safety = s_safety;
485 if (safety)
486 GlobalMutex::lock();
487 #ifdef _WINDOWS
488 ::ReleaseSemaphore(m_semaphore,1,NULL);
489 #else
490 int val = 0;
491 if (!::sem_getvalue(&m_semaphore,&val) && (val < (int)m_maxcount))
492 ::sem_post(&m_semaphore);
493 #endif
494 if (safety)
495 GlobalMutex::unlock();
496 }
497 return true;
498 }
499
500
~Lockable()501 Lockable::~Lockable()
502 {
503 }
504
check(long maxwait)505 bool Lockable::check(long maxwait)
506 {
507 bool ret = lock(maxwait);
508 if (ret)
509 unlock();
510 return ret;
511 }
512
unlockAll()513 bool Lockable::unlockAll()
514 {
515 while (locked()) {
516 if (!unlock())
517 return false;
518 Thread::yield();
519 }
520 return true;
521 }
522
startUsingNow()523 void Lockable::startUsingNow()
524 {
525 s_unsafe = false;
526 }
527
enableSafety(bool safe)528 void Lockable::enableSafety(bool safe)
529 {
530 s_safety = safe;
531 }
532
safety()533 bool Lockable::safety()
534 {
535 return s_safety;
536 }
537
wait(unsigned long maxwait)538 void Lockable::wait(unsigned long maxwait)
539 {
540 s_maxwait = maxwait;
541 }
542
wait()543 unsigned long Lockable::wait()
544 {
545 return s_maxwait;
546 }
547
548
Mutex(bool recursive,const char * name)549 Mutex::Mutex(bool recursive, const char* name)
550 : m_private(0)
551 {
552 if (!name)
553 name = "?";
554 m_private = new MutexPrivate(recursive,name);
555 }
556
Mutex(const Mutex & original)557 Mutex::Mutex(const Mutex &original)
558 : Lockable(),
559 m_private(original.privDataCopy())
560 {
561 }
562
~Mutex()563 Mutex::~Mutex()
564 {
565 MutexPrivate* priv = m_private;
566 m_private = 0;
567 if (priv)
568 priv->deref();
569 }
570
operator =(const Mutex & original)571 Mutex& Mutex::operator=(const Mutex& original)
572 {
573 MutexPrivate* priv = m_private;
574 m_private = original.privDataCopy();
575 if (priv)
576 priv->deref();
577 return *this;
578 }
579
privDataCopy() const580 MutexPrivate* Mutex::privDataCopy() const
581 {
582 if (m_private)
583 m_private->ref();
584 return m_private;
585 }
586
lock(long maxwait)587 bool Mutex::lock(long maxwait)
588 {
589 return m_private && m_private->lock(maxwait);
590 }
591
unlock()592 bool Mutex::unlock()
593 {
594 return m_private && m_private->unlock();
595 }
596
recursive() const597 bool Mutex::recursive() const
598 {
599 return m_private && m_private->recursive();
600 }
601
locked() const602 bool Mutex::locked() const
603 {
604 return m_private && m_private->locked();
605 }
606
owner() const607 const char* Mutex::owner() const
608 {
609 return m_private ? m_private->owner() : static_cast<const char*>(0);
610 }
611
count()612 int Mutex::count()
613 {
614 return MutexPrivate::s_count;
615 }
616
locks()617 int Mutex::locks()
618 {
619 return s_safety ? MutexPrivate::s_locks : -1;
620 }
621
efficientTimedLock()622 bool Mutex::efficientTimedLock()
623 {
624 #if defined(_WINDOWS) || defined(HAVE_TIMEDLOCK)
625 return true;
626 #else
627 return false;
628 #endif
629 }
630
631
MutexPool(unsigned int len,bool recursive,const char * name)632 MutexPool::MutexPool(unsigned int len, bool recursive, const char* name)
633 : m_name(0), m_data(0), m_length(len ? len : 1)
634 {
635 if (TelEngine::null(name))
636 name = "Pool";
637 m_name = new String[m_length];
638 for (unsigned int i = 0; i < m_length; i++)
639 m_name[i] << name << "::" << (i + 1);
640 m_data = new Mutex*[m_length];
641 for (unsigned int i = 0; i < m_length; i++)
642 m_data[i] = new Mutex(recursive,m_name[i]);
643 }
644
~MutexPool()645 MutexPool::~MutexPool()
646 {
647 if (m_data) {
648 for (unsigned int i = 0; i < m_length; i++)
649 delete m_data[i];
650 delete[] m_data;
651 }
652 if (m_name)
653 delete[] m_name;
654 }
655
656
Semaphore(unsigned int maxcount,const char * name,unsigned int initialCount)657 Semaphore::Semaphore(unsigned int maxcount, const char* name, unsigned int initialCount)
658 : m_private(0)
659 {
660 if (!name)
661 name = "?";
662 if (maxcount)
663 m_private = new SemaphorePrivate(maxcount,name,initialCount);
664 }
665
Semaphore(const Semaphore & original)666 Semaphore::Semaphore(const Semaphore &original)
667 : Lockable(),
668 m_private(original.privDataCopy())
669 {
670 }
671
~Semaphore()672 Semaphore::~Semaphore()
673 {
674 SemaphorePrivate* priv = m_private;
675 m_private = 0;
676 if (priv)
677 priv->deref();
678 }
679
operator =(const Semaphore & original)680 Semaphore& Semaphore::operator=(const Semaphore& original)
681 {
682 SemaphorePrivate* priv = m_private;
683 m_private = original.privDataCopy();
684 if (priv)
685 priv->deref();
686 return *this;
687 }
688
privDataCopy() const689 SemaphorePrivate* Semaphore::privDataCopy() const
690 {
691 if (m_private)
692 m_private->ref();
693 return m_private;
694 }
695
lock(long maxwait)696 bool Semaphore::lock(long maxwait)
697 {
698 return m_private && m_private->lock(maxwait);
699 }
700
unlock()701 bool Semaphore::unlock()
702 {
703 return m_private && m_private->unlock();
704 }
705
locked() const706 bool Semaphore::locked() const
707 {
708 return m_private && m_private->locked();
709 }
710
count()711 int Semaphore::count()
712 {
713 return SemaphorePrivate::s_count;
714 }
715
locks()716 int Semaphore::locks()
717 {
718 return s_safety ? SemaphorePrivate::s_locks : -1;
719 }
720
efficientTimedLock()721 bool Semaphore::efficientTimedLock()
722 {
723 #if defined(_WINDOWS) || defined(HAVE_TIMEDWAIT)
724 return true;
725 #else
726 return false;
727 #endif
728 }
729
730
lock(Mutex * mx1,Mutex * mx2,long maxwait)731 bool Lock2::lock(Mutex* mx1, Mutex* mx2, long maxwait)
732 {
733 // if we got only one mutex it must be mx1
734 if (!mx1) {
735 mx1 = mx2;
736 mx2 = 0;
737 }
738 // enforce a fixed locking order - lowest address first
739 else if (mx1 && mx2 && (mx1 > mx2)) {
740 Mutex* tmp = mx1;
741 mx1 = mx2;
742 mx2 = tmp;
743 }
744 drop();
745 if (!mx1)
746 return false;
747 if (!mx1->lock(maxwait))
748 return false;
749 if (mx2) {
750 if (!mx2->lock(maxwait)) {
751 mx1->unlock();
752 return false;
753 }
754 }
755 m_mx1 = mx1;
756 m_mx2 = mx2;
757 return true;
758 }
759
drop()760 void Lock2::drop()
761 {
762 Mutex* mx1 = m_mx1;
763 Mutex* mx2 = m_mx2;
764 m_mx1 = m_mx2 = 0;
765 // unlock in reverse order for performance reason
766 if (mx2)
767 mx2->unlock();
768 if (mx1)
769 mx1->unlock();
770 }
771
772 /* vi: set ts=8 sw=4 sts=4 noet: */
773