1 /***************************************************************************
2  *  include/stxxl/bits/common/mutex.h
3  *
4  *  Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  *  Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de>
7  *  Copyright (C) 2008 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
8  *  Copyright (C) 2013 Timo Bingmann <tb@panthema.net>
9  *
10  *  Distributed under the Boost Software License, Version 1.0.
11  *  (See accompanying file LICENSE_1_0.txt or copy at
12  *  http://www.boost.org/LICENSE_1_0.txt)
13  **************************************************************************/
14 
15 #ifndef STXXL_COMMON_MUTEX_HEADER
16 #define STXXL_COMMON_MUTEX_HEADER
17 
18 #include <stxxl/bits/config.h>
19 #include <stxxl/bits/namespace.h>
20 
21 #if STXXL_STD_THREADS
22  #include <mutex>
23 #elif STXXL_BOOST_THREADS
24  #include <boost/thread/mutex.hpp>
25 #elif STXXL_POSIX_THREADS
26  #include <pthread.h>
27 
28  #include <stxxl/bits/noncopyable.h>
29  #include <stxxl/bits/common/error_handling.h>
30 #else
31  #error "Thread implementation not detected."
32 #endif
33 
34 STXXL_BEGIN_NAMESPACE
35 
36 #if STXXL_STD_THREADS
37 
38 typedef std::mutex mutex;
39 
40 #elif STXXL_BOOST_THREADS
41 
42 typedef boost::mutex mutex;
43 
44 #elif STXXL_POSIX_THREADS
45 
46 class mutex : private noncopyable
47 {
48     //! mutex handle
49     pthread_mutex_t m_mutex;
50 
51 public:
52     //! construct unlocked mutex
53     mutex()
54     {
55         STXXL_CHECK_PTHREAD_CALL(pthread_mutex_init(&m_mutex, NULL));
56     }
57     //! destroy mutex handle
58     ~mutex()
59     {
60         // try simple delete first
61         int res = pthread_mutex_destroy(&m_mutex);
62         if (res == 0) return;
63 
64         // try to lock and unlock mutex
65         res = pthread_mutex_trylock(&m_mutex);
66 
67         if (res == 0 || res == EBUSY) {
68             STXXL_CHECK_PTHREAD_CALL(pthread_mutex_unlock(&m_mutex));
69         } else {
70             STXXL_THROW_ERRNO2(resource_error, "pthread_mutex_trylock() failed", res);
71         }
72 
73         STXXL_CHECK_PTHREAD_CALL(pthread_mutex_destroy(&m_mutex));
74     }
75     //! lock mutex, may block
76     void lock()
77     {
78         STXXL_CHECK_PTHREAD_CALL(pthread_mutex_lock(&m_mutex));
79     }
80     //! unlock mutex
81     void unlock()
82     {
83         STXXL_CHECK_PTHREAD_CALL(pthread_mutex_unlock(&m_mutex));
84     }
85     //! return platform specific handle
86     pthread_mutex_t & native_handle()
87     {
88         return m_mutex;
89     }
90 };
91 
92 #endif
93 
94 #if STXXL_STD_THREADS
95 
96 typedef std::unique_lock<std::mutex> scoped_mutex_lock;
97 
98 #elif STXXL_BOOST_THREADS
99 
100 typedef boost::mutex::scoped_lock scoped_mutex_lock;
101 
102 #else
103 
104 //! Aquire a lock that's valid until the end of scope.
105 class scoped_mutex_lock
106 {
107     //! mutex reference
108     mutex& m_mutex;
109 
110     //! marker if already unlocked by this thread (needs no synchronization)
111     bool is_locked;
112 
113 public:
114     //! lock mutex
scoped_mutex_lock(mutex & m)115     scoped_mutex_lock(mutex& m)
116         : m_mutex(m), is_locked(true)
117     {
118         m_mutex.lock();
119     }
120     //! unlock mutex hold when object goes out of scope.
~scoped_mutex_lock()121     ~scoped_mutex_lock()
122     {
123         unlock();
124     }
125     //! unlock mutex hold prematurely
unlock()126     void unlock()
127     {
128         if (is_locked) {
129             is_locked = false;
130             m_mutex.unlock();
131         }
132     }
133     //! return platform specific handle
native_handle()134     pthread_mutex_t & native_handle()
135     {
136         return m_mutex.native_handle();
137     }
138 };
139 
140 #endif
141 
142 STXXL_END_NAMESPACE
143 
144 #endif // !STXXL_COMMON_MUTEX_HEADER
145