summaryrefslogtreecommitdiffstats
blob: 05eb8d7630b3d99993af4b2bea6233cd360b7f0c (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
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP

//  basic_recursive_mutex.hpp
//
//  (C) Copyright 2006-8 Anthony Williams 
//
//  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)

#include "thread_primitives.hpp"
#include "basic_timed_mutex.hpp"

#include <boost/config/abi_prefix.hpp>

namespace boost
{
    namespace detail
    {
        template<typename underlying_mutex_type>
        struct basic_recursive_mutex_impl
        {
            long recursion_count;
            long locking_thread_id;
            underlying_mutex_type mutex;

            void initialize()
            {
                recursion_count=0;
                locking_thread_id=0;
                mutex.initialize();
            }

            void destroy()
            {
                mutex.destroy();
            }

            bool try_lock()
            {
                long const current_thread_id=win32::GetCurrentThreadId();
                return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
            }
            
            void lock()
            {
                long const current_thread_id=win32::GetCurrentThreadId();
                if(!try_recursive_lock(current_thread_id))
                {
                    mutex.lock();
                    BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
                    recursion_count=1;
                }
            }
            bool timed_lock(::boost::system_time const& target)
            {
                long const current_thread_id=win32::GetCurrentThreadId();
                return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
            }
            template<typename Duration>
            bool timed_lock(Duration const& timeout)
            {
                return timed_lock(get_system_time()+timeout);
            }

            void unlock()
            {
                if(!--recursion_count)
                {
                    BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
                    mutex.unlock();
                }
            }

        private:
            bool try_recursive_lock(long current_thread_id)
            {
                if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id)
                {
                    ++recursion_count;
                    return true;
                }
                return false;
            }
            
            bool try_basic_lock(long current_thread_id)
            {
                if(mutex.try_lock())
                {
                    BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
                    recursion_count=1;
                    return true;
                }
                return false;
            }
            
            bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
            {
                if(mutex.timed_lock(target))
                {
                    BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
                    recursion_count=1;
                    return true;
                }
                return false;
            }
            
        };

        typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
        typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
    }
}

#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}

#include <boost/config/abi_suffix.hpp>

#endif