summaryrefslogtreecommitdiff
path: root/boost/log/detail/locks.hpp
blob: 72b8945b267efb585a279b1d07846283dfac9534 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 *          Copyright Andrey Semashev 2007 - 2014.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   locks.hpp
 * \author Andrey Semashev
 * \date   30.05.2010
 *
 * \brief  This header is the Boost.Log library implementation, see the library documentation
 *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
 */

#ifndef BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_
#define BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_

#include <boost/log/detail/config.hpp>
#include <boost/log/detail/header.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

namespace boost {

#ifndef BOOST_LOG_NO_THREADS

// Forward declaration of Boost.Thread locks. Specified here to avoid including Boost.Thread,
// which would bring in many dependent headers, including a great deal of Boost.DateTime.
template< typename >
class lock_guard;
template< typename >
class shared_lock;
template< typename >
class upgrade_lock;
template< typename >
class unique_lock;

template< typename >
struct is_mutex_type;

#endif // BOOST_LOG_NO_THREADS

BOOST_LOG_OPEN_NAMESPACE

//! An auxiliary pseudo-lock to express no locking requirements in logger features
template< typename MutexT >
class no_lock
{
public:
    /*!
     * Constructs the pseudo-lock. The mutex is not affected during the construction.
     */
    explicit no_lock(MutexT&) {}

private:
    no_lock(no_lock const&);
    no_lock& operator= (no_lock const&);
};

namespace aux {

#ifndef BOOST_LOG_NO_THREADS

//! A trait to detect if the mutex supports exclusive locking
template< typename MutexT >
struct is_exclusively_lockable
{
    typedef char true_type;
    struct false_type { char t[2]; };

    template< typename T >
    static true_type check_lockable(T*, void (T::*)() = &T::lock, void (T::*)() = &T::unlock);
    static false_type check_lockable(void*);

    enum value_t { value = sizeof(check_lockable((MutexT*)NULL)) == sizeof(true_type) };
};

//! A trait to detect if the mutex supports shared locking
template< typename MutexT >
struct is_shared_lockable
{
    typedef char true_type;
    struct false_type { char t[2]; };

    template< typename T >
    static true_type check_shared_lockable(T*, void (T::*)() = &T::lock_shared, void (T::*)() = &T::unlock_shared);
    static false_type check_shared_lockable(void*);

    enum value_t { value = sizeof(check_shared_lockable((MutexT*)NULL)) == sizeof(true_type) };
};

//! An analogue to the minimalistic \c lock_guard template. Defined here to avoid including Boost.Thread.
template< typename MutexT >
struct exclusive_lock_guard
{
    explicit exclusive_lock_guard(MutexT& m) : m_Mutex(m)
    {
        m.lock();
    }
    ~exclusive_lock_guard()
    {
        m_Mutex.unlock();
    }

private:
    exclusive_lock_guard(exclusive_lock_guard const&);
    exclusive_lock_guard& operator= (exclusive_lock_guard const&);

private:
    MutexT& m_Mutex;
};

//! An analogue to the minimalistic \c lock_guard template that locks \c shared_mutex with shared ownership.
template< typename MutexT >
struct shared_lock_guard
{
    explicit shared_lock_guard(MutexT& m) : m_Mutex(m)
    {
        m.lock_shared();
    }
    ~shared_lock_guard()
    {
        m_Mutex.unlock_shared();
    }

private:
    shared_lock_guard(shared_lock_guard const&);
    shared_lock_guard& operator= (shared_lock_guard const&);

private:
    MutexT& m_Mutex;
};

//! A deadlock-safe lock type that exclusively locks two mutexes
template< typename MutexT1, typename MutexT2 >
class multiple_unique_lock2
{
public:
    multiple_unique_lock2(MutexT1& m1, MutexT2& m2) :
        m_p1(&m1),
        m_p2(&m2)
    {
        // Yes, it's not conforming, but it works
        // and it doesn't require to #include <functional>
        if (static_cast< void* >(m_p1) < static_cast< void* >(m_p2))
        {
            m_p1->lock();
            m_p2->lock();
        }
        else
        {
            m_p2->lock();
            m_p1->lock();
        }
    }
    ~multiple_unique_lock2()
    {
        m_p2->unlock();
        m_p1->unlock();
    }

private:
    MutexT1* m_p1;
    MutexT2* m_p2;
};

#endif // BOOST_LOG_NO_THREADS

} // namespace aux

BOOST_LOG_CLOSE_NAMESPACE // namespace log

} // namespace boost

#include <boost/log/detail/footer.hpp>

#endif // BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_