1 #ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
2 #define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 // (C) Copyright 2008 Anthony Williams
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
8 
9 #include <boost/thread/detail/config.hpp>
10 #include <boost/thread/thread_time.hpp>
11 #include <boost/thread/win32/thread_primitives.hpp>
12 #include <boost/thread/win32/thread_heap_alloc.hpp>
13 
14 #include <boost/predef/platform.h>
15 
16 #include <boost/intrusive_ptr.hpp>
17 #ifdef BOOST_THREAD_USES_CHRONO
18 #include <boost/chrono/system_clocks.hpp>
19 #endif
20 
21 #include <map>
22 #include <vector>
23 #include <utility>
24 
25 #include <boost/config/abi_prefix.hpp>
26 
27 #ifdef BOOST_MSVC
28 #pragma warning(push)
29 #pragma warning(disable:4251)
30 #endif
31 
32 namespace boost
33 {
34   class condition_variable;
35   class mutex;
36 
37   class thread_attributes {
38   public:
thread_attributes()39       thread_attributes() BOOST_NOEXCEPT {
40         val_.stack_size = 0;
41         //val_.lpThreadAttributes=0;
42       }
~thread_attributes()43       ~thread_attributes() {
44       }
45       // stack size
set_stack_size(std::size_t size)46       void set_stack_size(std::size_t size) BOOST_NOEXCEPT {
47         val_.stack_size = size;
48       }
49 
get_stack_size() const50       std::size_t get_stack_size() const BOOST_NOEXCEPT {
51           return val_.stack_size;
52       }
53 
54       //void set_security(LPSECURITY_ATTRIBUTES lpThreadAttributes)
55       //{
56       //  val_.lpThreadAttributes=lpThreadAttributes;
57       //}
58       //LPSECURITY_ATTRIBUTES get_security()
59       //{
60       //  return val_.lpThreadAttributes;
61       //}
62 
63       struct win_attrs {
64         std::size_t stack_size;
65         //LPSECURITY_ATTRIBUTES lpThreadAttributes;
66       };
67       typedef win_attrs native_handle_type;
native_handle()68       native_handle_type* native_handle() {return &val_;}
native_handle() const69       const native_handle_type* native_handle() const {return &val_;}
70 
71   private:
72       win_attrs val_;
73   };
74 
75     namespace detail
76     {
77         struct shared_state_base;
78         struct tss_cleanup_function;
79         struct thread_exit_callback_node;
80         struct tss_data_node
81         {
82             boost::shared_ptr<boost::detail::tss_cleanup_function> func;
83             void* value;
84 
tss_data_nodeboost::detail::tss_data_node85             tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
86                           void* value_):
87                 func(func_),value(value_)
88             {}
89         };
90 
91         struct thread_data_base;
92         void intrusive_ptr_add_ref(thread_data_base * p);
93         void intrusive_ptr_release(thread_data_base * p);
94 
95         struct BOOST_THREAD_DECL thread_data_base
96         {
97             long count;
98 
99             // Win32 threading APIs are not available in store apps so
100             // use abstraction on top of Windows::System::Threading.
101 #if BOOST_PLAT_WINDOWS_RUNTIME
102             detail::win32::scoped_winrt_thread thread_handle;
103 #else
104             detail::win32::handle_manager thread_handle;
105 #endif
106 
107             boost::detail::thread_exit_callback_node* thread_exit_callbacks;
108             unsigned id;
109             std::map<void const*,boost::detail::tss_data_node> tss_data;
110             typedef std::vector<std::pair<condition_variable*, mutex*>
111             //, hidden_allocator<std::pair<condition_variable*, mutex*> >
112             > notify_list_t;
113             notify_list_t notify;
114 
115             typedef std::vector<shared_ptr<shared_state_base> > async_states_t;
116             async_states_t async_states_;
117 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
118             // These data must be at the end so that the access to the other fields doesn't change
119             // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined
120             // Another option is to have them always
121             detail::win32::handle_manager interruption_handle;
122             bool interruption_enabled;
123 //#endif
124 
thread_data_baseboost::detail::thread_data_base125             thread_data_base():
126                 count(0),
127                 thread_handle(),
128                 thread_exit_callbacks(0),
129                 id(0),
130                 tss_data(),
131                 notify(),
132                 async_states_()
133 //#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
134                 , interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset))
135                 , interruption_enabled(true)
136 //#endif
137             {}
138             virtual ~thread_data_base();
139 
intrusive_ptr_add_ref(thread_data_base * p)140             friend void intrusive_ptr_add_ref(thread_data_base * p)
141             {
142                 BOOST_INTERLOCKED_INCREMENT(&p->count);
143             }
144 
intrusive_ptr_release(thread_data_base * p)145             friend void intrusive_ptr_release(thread_data_base * p)
146             {
147                 if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
148                 {
149                     detail::heap_delete(p);
150                 }
151             }
152 
153 #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
interruptboost::detail::thread_data_base154             void interrupt()
155             {
156                 BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
157             }
158 #endif
159             typedef detail::win32::handle native_handle_type;
160 
161             virtual void run()=0;
162 
notify_all_at_thread_exitboost::detail::thread_data_base163             virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m)
164             {
165               notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
166             }
167 
make_ready_at_thread_exitboost::detail::thread_data_base168             void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
169             {
170               async_states_.push_back(as);
171             }
172 
173         };
174         BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
175 
176         typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
177 
178         struct BOOST_SYMBOL_VISIBLE timeout
179         {
180             win32::ticks_type start;
181             uintmax_t milliseconds;
182             bool relative;
183             boost::system_time abs_time;
184 
185             static unsigned long const max_non_infinite_wait=0xfffffffe;
186 
timeoutboost::detail::timeout187             timeout(uintmax_t milliseconds_):
188                 start(win32::GetTickCount64_()()),
189                 milliseconds(milliseconds_),
190                 relative(true)
191             //,
192             //    abs_time(boost::get_system_time())
193             {}
194 
timeoutboost::detail::timeout195             timeout(boost::system_time const& abs_time_):
196                 start(win32::GetTickCount64_()()),
197                 milliseconds(0),
198                 relative(false),
199                 abs_time(abs_time_)
200             {}
201 
202             struct BOOST_SYMBOL_VISIBLE remaining_time
203             {
204                 bool more;
205                 unsigned long milliseconds;
206 
remaining_timeboost::detail::timeout::remaining_time207                 remaining_time(uintmax_t remaining):
208                     more(remaining>max_non_infinite_wait),
209                     milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
210                 {}
211             };
212 
remaining_millisecondsboost::detail::timeout213             remaining_time remaining_milliseconds() const
214             {
215                 if(is_sentinel())
216                 {
217                     return remaining_time(win32::infinite);
218                 }
219                 else if(relative)
220                 {
221                     win32::ticks_type const now=win32::GetTickCount64_()();
222                     win32::ticks_type const elapsed=now-start;
223                     return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
224                 }
225                 else
226                 {
227                     system_time const now=get_system_time();
228                     if(abs_time<=now)
229                     {
230                         return remaining_time(0);
231                     }
232                     return remaining_time((abs_time-now).total_milliseconds()+1);
233                 }
234             }
235 
is_sentinelboost::detail::timeout236             bool is_sentinel() const
237             {
238                 return milliseconds==~uintmax_t(0);
239             }
240 
241 
sentinelboost::detail::timeout242             static timeout sentinel()
243             {
244                 return timeout(sentinel_type());
245             }
246         private:
247             struct sentinel_type
248             {};
249 
timeoutboost::detail::timeout250             explicit timeout(sentinel_type):
251                 start(0),milliseconds(~uintmax_t(0)),relative(true)
252             {}
253         };
254 
pin_to_zero(intmax_t value)255         inline uintmax_t pin_to_zero(intmax_t value)
256         {
257             return (value<0)?0u:(uintmax_t)value;
258         }
259     }
260 
261     namespace this_thread
262     {
263         void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
264 
265         bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
interruptible_wait(uintmax_t milliseconds)266         inline void interruptible_wait(uintmax_t milliseconds)
267         {
268             interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
269         }
interruptible_wait(system_time const & abs_time)270         inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time)
271         {
272             interruptible_wait(detail::win32::invalid_handle_value,abs_time);
273         }
274         template<typename TimeDuration>
sleep(TimeDuration const & rel_time)275         inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
276         {
277             interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
278         }
sleep(system_time const & abs_time)279         inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
280         {
281             interruptible_wait(abs_time);
282         }
283 #ifdef BOOST_THREAD_USES_CHRONO
sleep_for(const chrono::nanoseconds & ns)284         inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
285         {
286           interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
287         }
288 #endif
289         namespace no_interruption_point
290         {
291           bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
non_interruptible_wait(uintmax_t milliseconds)292           inline void non_interruptible_wait(uintmax_t milliseconds)
293           {
294             non_interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
295           }
non_interruptible_wait(system_time const & abs_time)296           inline BOOST_SYMBOL_VISIBLE void non_interruptible_wait(system_time const& abs_time)
297           {
298             non_interruptible_wait(detail::win32::invalid_handle_value,abs_time);
299           }
300           template<typename TimeDuration>
sleep(TimeDuration const & rel_time)301           inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
302           {
303             non_interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
304           }
sleep(system_time const & abs_time)305           inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
306           {
307             non_interruptible_wait(abs_time);
308           }
309 #ifdef BOOST_THREAD_USES_CHRONO
sleep_for(const chrono::nanoseconds & ns)310           inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
311           {
312             non_interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
313           }
314 #endif
315         }
316     }
317 
318 }
319 
320 #ifdef BOOST_MSVC
321 #pragma warning(pop)
322 #endif
323 
324 #include <boost/config/abi_suffix.hpp>
325 
326 #endif
327