Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / thread / win32 / condition_variable.hpp
1 #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
2 #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_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 2007-8 Anthony Williams
7 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
8
9 #include <boost/thread/win32/thread_primitives.hpp>
10 #include <boost/thread/win32/thread_data.hpp>
11 #include <boost/thread/win32/thread_data.hpp>
12 #include <boost/thread/win32/interlocked_read.hpp>
13 #include <boost/thread/cv_status.hpp>
14 #if defined BOOST_THREAD_USES_DATETIME
15 #include <boost/thread/xtime.hpp>
16 #endif
17 #include <boost/thread/mutex.hpp>
18 #include <boost/thread/thread_time.hpp>
19 #include <boost/thread/lock_guard.hpp>
20 #include <boost/thread/lock_types.hpp>
21
22 #include <boost/assert.hpp>
23 #include <boost/intrusive_ptr.hpp>
24
25 #ifdef BOOST_THREAD_USES_CHRONO
26 #include <boost/chrono/system_clocks.hpp>
27 #include <boost/chrono/ceil.hpp>
28 #endif
29
30 #include <limits.h>
31 #include <algorithm>
32 #include <vector>
33
34 #include <boost/config/abi_prefix.hpp>
35
36 namespace boost
37 {
38     namespace detail
39     {
40         class basic_cv_list_entry;
41         void intrusive_ptr_add_ref(basic_cv_list_entry * p);
42         void intrusive_ptr_release(basic_cv_list_entry * p);
43
44         class basic_cv_list_entry
45         {
46         private:
47             detail::win32::handle_manager semaphore;
48             detail::win32::handle_manager wake_sem;
49             long waiters;
50             bool notified;
51             long references;
52
53         public:
54             BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
55             explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
56                 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
57                 wake_sem(wake_sem_.duplicate()),
58                 waiters(1),notified(false),references(0)
59             {}
60
61             static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
62             {
63                 return !detail::interlocked_read_acquire(&entry->waiters);
64             }
65
66             void add_waiter()
67             {
68                 BOOST_INTERLOCKED_INCREMENT(&waiters);
69             }
70
71             void remove_waiter()
72             {
73                 BOOST_INTERLOCKED_DECREMENT(&waiters);
74             }
75
76             void release(unsigned count_to_release)
77             {
78                 notified=true;
79                 detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
80             }
81
82             void release_waiters()
83             {
84                 release(detail::interlocked_read_acquire(&waiters));
85             }
86
87             bool is_notified() const
88             {
89                 return notified;
90             }
91
92             bool wait(timeout abs_time)
93             {
94                 return this_thread::interruptible_wait(semaphore,abs_time);
95             }
96
97             bool woken()
98             {
99                 unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
100                 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
101                 return woken_result==0;
102             }
103
104             friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
105             friend void intrusive_ptr_release(basic_cv_list_entry * p);
106         };
107
108         inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
109         {
110             BOOST_INTERLOCKED_INCREMENT(&p->references);
111         }
112
113         inline void intrusive_ptr_release(basic_cv_list_entry * p)
114         {
115             if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
116             {
117                 delete p;
118             }
119         }
120
121         class basic_condition_variable
122         {
123             boost::mutex internal_mutex;
124             long total_count;
125             unsigned active_generation_count;
126
127             typedef basic_cv_list_entry list_entry;
128
129             typedef boost::intrusive_ptr<list_entry> entry_ptr;
130             typedef std::vector<entry_ptr> generation_list;
131
132             generation_list generations;
133             detail::win32::handle_manager wake_sem;
134
135             void wake_waiters(long count_to_wake)
136             {
137                 detail::interlocked_write_release(&total_count,total_count-count_to_wake);
138                 detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
139             }
140
141             template<typename lock_type>
142             struct relocker
143             {
144                 BOOST_THREAD_NO_COPYABLE(relocker)
145                 lock_type& lock;
146                 bool unlocked;
147
148                 relocker(lock_type& lock_):
149                     lock(lock_),unlocked(false)
150                 {}
151                 void unlock()
152                 {
153                     lock.unlock();
154                     unlocked=true;
155                 }
156                 ~relocker()
157                 {
158                     if(unlocked)
159                     {
160                         lock.lock();
161                     }
162
163                 }
164             };
165
166
167             entry_ptr get_wait_entry()
168             {
169                 boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
170
171                 if(!wake_sem)
172                 {
173                     wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
174                     BOOST_ASSERT(wake_sem);
175                 }
176
177                 detail::interlocked_write_release(&total_count,total_count+1);
178                 if(generations.empty() || generations.back()->is_notified())
179                 {
180                     entry_ptr new_entry(new list_entry(wake_sem));
181                     generations.push_back(new_entry);
182                     return new_entry;
183                 }
184                 else
185                 {
186                     generations.back()->add_waiter();
187                     return generations.back();
188                 }
189             }
190
191             struct entry_manager
192             {
193                 entry_ptr const entry;
194                 boost::mutex& internal_mutex;
195
196                 BOOST_THREAD_NO_COPYABLE(entry_manager)
197                 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
198                     entry(entry_), internal_mutex(mutex_)
199                 {}
200
201                 ~entry_manager()
202                 {
203                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
204                     entry->remove_waiter();
205                 }
206
207                 list_entry* operator->()
208                 {
209                     return entry.get();
210                 }
211             };
212
213
214         protected:
215             template<typename lock_type>
216             bool do_wait(lock_type& lock,timeout abs_time)
217             {
218                 relocker<lock_type> locker(lock);
219
220                 entry_manager entry(get_wait_entry(), internal_mutex);
221
222                 locker.unlock();
223
224                 bool woken=false;
225                 while(!woken)
226                 {
227                     if(!entry->wait(abs_time))
228                     {
229                         return false;
230                     }
231
232                     woken=entry->woken();
233                 }
234                 return woken;
235             }
236
237             template<typename lock_type,typename predicate_type>
238             bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
239             {
240                 while (!pred())
241                 {
242                     if(!do_wait(m, abs_time))
243                         return pred();
244                 }
245                 return true;
246             }
247
248             basic_condition_variable(const basic_condition_variable& other);
249             basic_condition_variable& operator=(const basic_condition_variable& other);
250
251         public:
252             basic_condition_variable():
253                 total_count(0),active_generation_count(0),wake_sem(0)
254             {}
255
256             ~basic_condition_variable()
257             {}
258
259             void notify_one() BOOST_NOEXCEPT
260             {
261                 if(detail::interlocked_read_acquire(&total_count))
262                 {
263                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
264                     if(!total_count)
265                     {
266                         return;
267                     }
268                     wake_waiters(1);
269
270                     for(generation_list::iterator it=generations.begin(),
271                             end=generations.end();
272                         it!=end;++it)
273                     {
274                         (*it)->release(1);
275                     }
276                     generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
277                 }
278             }
279
280             void notify_all() BOOST_NOEXCEPT
281             {
282                 if(detail::interlocked_read_acquire(&total_count))
283                 {
284                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
285                     if(!total_count)
286                     {
287                         return;
288                     }
289                     wake_waiters(total_count);
290                     for(generation_list::iterator it=generations.begin(),
291                             end=generations.end();
292                         it!=end;++it)
293                     {
294                         (*it)->release_waiters();
295                     }
296                     generations.clear();
297                     wake_sem=detail::win32::handle(0);
298                 }
299             }
300
301         };
302     }
303
304     class condition_variable:
305         private detail::basic_condition_variable
306     {
307     public:
308         BOOST_THREAD_NO_COPYABLE(condition_variable)
309         condition_variable()
310         {}
311
312         using detail::basic_condition_variable::notify_one;
313         using detail::basic_condition_variable::notify_all;
314
315         void wait(unique_lock<mutex>& m)
316         {
317             do_wait(m,detail::timeout::sentinel());
318         }
319
320         template<typename predicate_type>
321         void wait(unique_lock<mutex>& m,predicate_type pred)
322         {
323             while(!pred()) wait(m);
324         }
325
326
327 #if defined BOOST_THREAD_USES_DATETIME
328         bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
329         {
330             return do_wait(m,abs_time);
331         }
332
333         bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
334         {
335             return do_wait(m,system_time(abs_time));
336         }
337         template<typename duration_type>
338         bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
339         {
340           if (wait_duration.is_pos_infinity())
341           {
342               wait(m); // or do_wait(m,detail::timeout::sentinel());
343               return true;
344           }
345           if (wait_duration.is_special())
346           {
347             return true;
348           }
349           return do_wait(m,wait_duration.total_milliseconds());
350         }
351
352         template<typename predicate_type>
353         bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
354         {
355             return do_wait(m,abs_time,pred);
356         }
357         template<typename predicate_type>
358         bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
359         {
360             return do_wait(m,system_time(abs_time),pred);
361         }
362         template<typename duration_type,typename predicate_type>
363         bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
364         {
365             return do_wait(m,wait_duration.total_milliseconds(),pred);
366         }
367 #endif
368 #ifdef BOOST_THREAD_USES_CHRONO
369
370         template <class Clock, class Duration>
371         cv_status
372         wait_until(
373                 unique_lock<mutex>& lock,
374                 const chrono::time_point<Clock, Duration>& t)
375         {
376           using namespace chrono;
377           chrono::time_point<Clock, Duration> now = Clock::now();
378           if (t<=now) {
379             return cv_status::timeout;
380           }
381           do_wait(lock, ceil<milliseconds>(t-now).count());
382           return Clock::now() < t ? cv_status::no_timeout :
383                                              cv_status::timeout;
384         }
385
386         template <class Rep, class Period>
387         cv_status
388         wait_for(
389                 unique_lock<mutex>& lock,
390                 const chrono::duration<Rep, Period>& d)
391         {
392           using namespace chrono;
393           if (d<=chrono::duration<Rep, Period>::zero()) {
394             return cv_status::timeout;
395           }
396
397           steady_clock::time_point c_now = steady_clock::now();
398           do_wait(lock, ceil<milliseconds>(d).count());
399           return steady_clock::now() - c_now < d ? cv_status::no_timeout :
400                                                    cv_status::timeout;
401         }
402
403         template <class Clock, class Duration, class Predicate>
404         bool
405         wait_until(
406                 unique_lock<mutex>& lock,
407                 const chrono::time_point<Clock, Duration>& t,
408                 Predicate pred)
409         {
410             while (!pred())
411             {
412                 if (wait_until(lock, t) == cv_status::timeout)
413                     return pred();
414             }
415             return true;
416         }
417         template <class Rep, class Period, class Predicate>
418         bool
419         wait_for(
420                 unique_lock<mutex>& lock,
421                 const chrono::duration<Rep, Period>& d,
422                 Predicate pred)
423         {
424             return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
425         }
426 #endif
427     };
428
429     class condition_variable_any:
430         private detail::basic_condition_variable
431     {
432     public:
433         BOOST_THREAD_NO_COPYABLE(condition_variable_any)
434         condition_variable_any()
435         {}
436
437         using detail::basic_condition_variable::notify_one;
438         using detail::basic_condition_variable::notify_all;
439
440         template<typename lock_type>
441         void wait(lock_type& m)
442         {
443             do_wait(m,detail::timeout::sentinel());
444         }
445
446         template<typename lock_type,typename predicate_type>
447         void wait(lock_type& m,predicate_type pred)
448         {
449             while(!pred()) wait(m);
450         }
451
452 #if defined BOOST_THREAD_USES_DATETIME
453         template<typename lock_type>
454         bool timed_wait(lock_type& m,boost::system_time const& abs_time)
455         {
456             return do_wait(m,abs_time);
457         }
458
459         template<typename lock_type>
460         bool timed_wait(lock_type& m,boost::xtime const& abs_time)
461         {
462             return do_wait(m,system_time(abs_time));
463         }
464
465         template<typename lock_type,typename duration_type>
466         bool timed_wait(lock_type& m,duration_type const& wait_duration)
467         {
468             return do_wait(m,wait_duration.total_milliseconds());
469         }
470
471         template<typename lock_type,typename predicate_type>
472         bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
473         {
474             return do_wait(m,abs_time,pred);
475         }
476
477         template<typename lock_type,typename predicate_type>
478         bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
479         {
480             return do_wait(m,system_time(abs_time),pred);
481         }
482
483         template<typename lock_type,typename duration_type,typename predicate_type>
484         bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
485         {
486             return do_wait(m,wait_duration.total_milliseconds(),pred);
487         }
488 #endif
489 #ifdef BOOST_THREAD_USES_CHRONO
490
491         template <class lock_type, class Clock, class Duration>
492         cv_status
493         wait_until(
494                 lock_type& lock,
495                 const chrono::time_point<Clock, Duration>& t)
496         {
497           using namespace chrono;
498           chrono::time_point<Clock, Duration> now = Clock::now();
499           if (t<=now) {
500             return cv_status::timeout;
501           }
502           do_wait(lock, ceil<milliseconds>(t-now).count());
503           return Clock::now() < t ? cv_status::no_timeout :
504                                              cv_status::timeout;
505         }
506
507         template <class lock_type,  class Rep, class Period>
508         cv_status
509         wait_for(
510                 lock_type& lock,
511                 const chrono::duration<Rep, Period>& d)
512         {
513           using namespace chrono;
514           if (d<=chrono::duration<Rep, Period>::zero()) {
515             return cv_status::timeout;
516           }
517           steady_clock::time_point c_now = steady_clock::now();
518           do_wait(lock, ceil<milliseconds>(d).count());
519           return steady_clock::now() - c_now < d ? cv_status::no_timeout :
520                                                    cv_status::timeout;
521         }
522
523         template <class lock_type, class Clock, class Duration, class Predicate>
524         bool
525         wait_until(
526                 lock_type& lock,
527                 const chrono::time_point<Clock, Duration>& t,
528                 Predicate pred)
529         {
530             while (!pred())
531             {
532                 if (wait_until(lock, t) == cv_status::timeout)
533                     return pred();
534             }
535             return true;
536         }
537
538         template <class lock_type, class Rep, class Period, class Predicate>
539         bool
540         wait_for(
541                 lock_type& lock,
542                 const chrono::duration<Rep, Period>& d,
543                 Predicate pred)
544         {
545             return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
546         }
547 #endif
548     };
549
550         BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
551 }
552
553 #include <boost/config/abi_suffix.hpp>
554
555 #endif