1 #ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
2 #define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
3 
4 //  basic_timed_mutex_win32.hpp
5 //
6 //  (C) Copyright 2006-8 Anthony Williams
7 //
8 //  Distributed under the Boost Software License, Version 1.0. (See
9 //  accompanying file LICENSE_1_0.txt or copy at
10 //  http://www.boost.org/LICENSE_1_0.txt)
11 
12 #include <boost/assert.hpp>
13 #include "thread_primitives.hpp"
14 #include "interlocked_read.hpp"
15 #include <boost/thread/thread_time.hpp>
16 #include <boost/thread/xtime.hpp>
17 #include <boost/detail/interlocked.hpp>
18 
19 #include <boost/config/abi_prefix.hpp>
20 
21 namespace boost
22 {
23     namespace detail
24     {
25         struct basic_timed_mutex
26         {
27             BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
28             BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
29             BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
30             BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
31             long active_count;
32             void* event;
33 
initializeboost::detail::basic_timed_mutex34             void initialize()
35             {
36                 active_count=0;
37                 event=0;
38             }
39 
destroyboost::detail::basic_timed_mutex40             void destroy()
41             {
42 #ifdef BOOST_MSVC
43 #pragma warning(push)
44 #pragma warning(disable:4312)
45 #endif
46                 void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
47 #ifdef BOOST_MSVC
48 #pragma warning(pop)
49 #endif
50                 if(old_event)
51                 {
52                     win32::CloseHandle(old_event);
53                 }
54             }
55 
56 
try_lockboost::detail::basic_timed_mutex57             bool try_lock()
58             {
59                 return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
60             }
61 
lockboost::detail::basic_timed_mutex62             void lock()
63             {
64                 if(try_lock())
65                 {
66                     return;
67                 }
68                 long old_count=active_count;
69                 mark_waiting_and_try_lock(old_count);
70 
71                 if(old_count&lock_flag_value)
72                 {
73                     bool lock_acquired=false;
74                     void* const sem=get_event();
75 
76                     do
77                     {
78                         BOOST_VERIFY(win32::WaitForSingleObject(
79                                          sem,::boost::detail::win32::infinite)==0);
80                         clear_waiting_and_try_lock(old_count);
81                         lock_acquired=!(old_count&lock_flag_value);
82                     }
83                     while(!lock_acquired);
84                 }
85             }
mark_waiting_and_try_lockboost::detail::basic_timed_mutex86             void mark_waiting_and_try_lock(long& old_count)
87             {
88                 for(;;)
89                 {
90                     long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
91                     long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
92                     if(current==old_count)
93                     {
94                         break;
95                     }
96                     old_count=current;
97                 }
98             }
99 
clear_waiting_and_try_lockboost::detail::basic_timed_mutex100             void clear_waiting_and_try_lock(long& old_count)
101             {
102                 old_count&=~lock_flag_value;
103                 old_count|=event_set_flag_value;
104                 for(;;)
105                 {
106                     long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
107                     long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
108                     if(current==old_count)
109                     {
110                         break;
111                     }
112                     old_count=current;
113                 }
114             }
115 
116 
timed_lockboost::detail::basic_timed_mutex117             bool timed_lock(::boost::system_time const& wait_until)
118             {
119                 if(try_lock())
120                 {
121                     return true;
122                 }
123                 long old_count=active_count;
124                 mark_waiting_and_try_lock(old_count);
125 
126                 if(old_count&lock_flag_value)
127                 {
128                     bool lock_acquired=false;
129                     void* const sem=get_event();
130 
131                     do
132                     {
133                         if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
134                         {
135                             BOOST_INTERLOCKED_DECREMENT(&active_count);
136                             return false;
137                         }
138                         clear_waiting_and_try_lock(old_count);
139                         lock_acquired=!(old_count&lock_flag_value);
140                     }
141                     while(!lock_acquired);
142                 }
143                 return true;
144             }
145 
146             template<typename Duration>
timed_lockboost::detail::basic_timed_mutex147             bool timed_lock(Duration const& timeout)
148             {
149                 return timed_lock(get_system_time()+timeout);
150             }
151 
timed_lockboost::detail::basic_timed_mutex152             bool timed_lock(boost::xtime const& timeout)
153             {
154                 return timed_lock(system_time(timeout));
155             }
156 
unlockboost::detail::basic_timed_mutex157             void unlock()
158             {
159                 long const offset=lock_flag_value;
160                 long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
161                 if(!(old_count&event_set_flag_value) && (old_count>offset))
162                 {
163                     if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
164                     {
165                         win32::SetEvent(get_event());
166                     }
167                 }
168             }
169 
170         private:
get_eventboost::detail::basic_timed_mutex171             void* get_event()
172             {
173                 void* current_event=::boost::detail::interlocked_read_acquire(&event);
174 
175                 if(!current_event)
176                 {
177                     void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
178 #ifdef BOOST_MSVC
179 #pragma warning(push)
180 #pragma warning(disable:4311)
181 #pragma warning(disable:4312)
182 #endif
183                     void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
184 #ifdef BOOST_MSVC
185 #pragma warning(pop)
186 #endif
187                     if(old_event!=0)
188                     {
189                         win32::CloseHandle(new_event);
190                         return old_event;
191                     }
192                     else
193                     {
194                         return new_event;
195                     }
196                 }
197                 return current_event;
198             }
199 
200         };
201 
202     }
203 }
204 
205 #define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
206 
207 #include <boost/config/abi_suffix.hpp>
208 
209 #endif
210