1 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
2 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
3 
4 //  (C) Copyright 2006-8 Anthony Williams
5 //  (C) Copyright 2011-2012 Vicente J. Botet Escriba
6 //
7 //  Distributed under the Boost Software License, Version 1.0. (See
8 //  accompanying file LICENSE_1_0.txt or copy at
9 //  http://www.boost.org/LICENSE_1_0.txt)
10 
11 #include <boost/assert.hpp>
12 #include <boost/detail/interlocked.hpp>
13 #include <boost/thread/win32/thread_primitives.hpp>
14 #include <boost/static_assert.hpp>
15 #include <limits.h>
16 #include <boost/thread/thread_time.hpp>
17 #ifdef BOOST_THREAD_USES_CHRONO
18 #include <boost/chrono/system_clocks.hpp>
19 #include <boost/chrono/ceil.hpp>
20 #endif
21 #include <boost/thread/detail/delete.hpp>
22 
23 #include <boost/config/abi_prefix.hpp>
24 
25 namespace boost
26 {
27     class shared_mutex
28     {
29     private:
30         struct state_data
31         {
32             unsigned shared_count:11,
33                 shared_waiting:11,
34                 exclusive:1,
35                 upgrade:1,
36                 exclusive_waiting:7,
37                 exclusive_waiting_blocked:1;
38 
operator ==(state_data const & lhs,state_data const & rhs)39             friend bool operator==(state_data const& lhs,state_data const& rhs)
40             {
41                 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
42             }
43         };
44 
45 
46         template<typename T>
interlocked_compare_exchange(T * target,T new_value,T comparand)47         T interlocked_compare_exchange(T* target,T new_value,T comparand)
48         {
49             BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
50             long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
51                                                               *reinterpret_cast<long*>(&new_value),
52                                                               *reinterpret_cast<long*>(&comparand));
53             return *reinterpret_cast<T const*>(&res);
54         }
55 
56         enum
57         {
58             unlock_sem = 0,
59             exclusive_sem = 1
60         };
61 
62         state_data state;
63         detail::win32::handle semaphores[2];
64         detail::win32::handle upgrade_sem;
65 
release_waiters(state_data old_state)66         void release_waiters(state_data old_state)
67         {
68             if(old_state.exclusive_waiting)
69             {
70                 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
71             }
72 
73             if(old_state.shared_waiting || old_state.exclusive_waiting)
74             {
75                 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
76             }
77         }
release_shared_waiters(state_data old_state)78         void release_shared_waiters(state_data old_state)
79         {
80             if(old_state.shared_waiting || old_state.exclusive_waiting)
81             {
82                 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
83             }
84         }
85 
86     public:
87         BOOST_THREAD_NO_COPYABLE(shared_mutex)
shared_mutex()88         shared_mutex()
89         {
90             semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
91             semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
92             if (!semaphores[exclusive_sem])
93             {
94               detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
95               boost::throw_exception(thread_resource_error());
96             }
97             upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
98             if (!upgrade_sem)
99             {
100               detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
101               detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
102               boost::throw_exception(thread_resource_error());
103             }
104             state_data state_={0,0,0,0,0,0};
105             state=state_;
106         }
107 
~shared_mutex()108         ~shared_mutex()
109         {
110             detail::win32::CloseHandle(upgrade_sem);
111             detail::win32::CloseHandle(semaphores[unlock_sem]);
112             detail::win32::CloseHandle(semaphores[exclusive_sem]);
113         }
114 
try_lock_shared()115         bool try_lock_shared()
116         {
117             state_data old_state=state;
118             for(;;)
119             {
120                 state_data new_state=old_state;
121                 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
122                 {
123                     ++new_state.shared_count;
124                     if(!new_state.shared_count)
125                     {
126                         return false;
127                     }
128                 }
129 
130                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
131                 if(current_state==old_state)
132                 {
133                     break;
134                 }
135                 old_state=current_state;
136             }
137             return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
138         }
139 
lock_shared()140         void lock_shared()
141         {
142 
143 #if defined BOOST_THREAD_USES_DATETIME
144             BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
145 #else
146             BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now()));
147 #endif
148         }
149 
150 #if defined BOOST_THREAD_USES_DATETIME
151         template<typename TimeDuration>
timed_lock_shared(TimeDuration const & relative_time)152         bool timed_lock_shared(TimeDuration const & relative_time)
153         {
154             return timed_lock_shared(get_system_time()+relative_time);
155         }
timed_lock_shared(boost::system_time const & wait_until)156         bool timed_lock_shared(boost::system_time const& wait_until)
157         {
158             for(;;)
159             {
160                 state_data old_state=state;
161                 for(;;)
162                 {
163                     state_data new_state=old_state;
164                     if(new_state.exclusive || new_state.exclusive_waiting_blocked)
165                     {
166                         ++new_state.shared_waiting;
167                         if(!new_state.shared_waiting)
168                         {
169                             boost::throw_exception(boost::lock_error());
170                         }
171                     }
172                     else
173                     {
174                         ++new_state.shared_count;
175                         if(!new_state.shared_count)
176                         {
177                             boost::throw_exception(boost::lock_error());
178                         }
179                     }
180 
181                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
182                     if(current_state==old_state)
183                     {
184                         break;
185                     }
186                     old_state=current_state;
187                 }
188 
189                 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
190                 {
191                     return true;
192                 }
193 
194                 unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
195                 if(res==detail::win32::timeout)
196                 {
197                     for(;;)
198                     {
199                         state_data new_state=old_state;
200                         if(new_state.exclusive || new_state.exclusive_waiting_blocked)
201                         {
202                             if(new_state.shared_waiting)
203                             {
204                                 --new_state.shared_waiting;
205                             }
206                         }
207                         else
208                         {
209                             ++new_state.shared_count;
210                             if(!new_state.shared_count)
211                             {
212                                 return false;
213                             }
214                         }
215 
216                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
217                         if(current_state==old_state)
218                         {
219                             break;
220                         }
221                         old_state=current_state;
222                     }
223 
224                     if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
225                     {
226                         return true;
227                     }
228                     return false;
229                 }
230 
231                 BOOST_ASSERT(res==0);
232             }
233         }
234 #endif
235 
236 #ifdef BOOST_THREAD_USES_CHRONO
237         template <class Rep, class Period>
try_lock_shared_for(const chrono::duration<Rep,Period> & rel_time)238         bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
239         {
240           return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
241         }
242         template <class Clock, class Duration>
try_lock_shared_until(const chrono::time_point<Clock,Duration> & t)243         bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
244         {
245           using namespace chrono;
246           system_clock::time_point     s_now = system_clock::now();
247           typename Clock::time_point  c_now = Clock::now();
248           return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
249         }
250         template <class Duration>
try_lock_shared_until(const chrono::time_point<chrono::system_clock,Duration> & t)251         bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
252         {
253           using namespace chrono;
254           typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
255           return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
256         }
try_lock_shared_until(const chrono::time_point<chrono::system_clock,chrono::system_clock::duration> & tp)257         bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
258         {
259           for(;;)
260           {
261             state_data old_state=state;
262             for(;;)
263             {
264               state_data new_state=old_state;
265               if(new_state.exclusive || new_state.exclusive_waiting_blocked)
266               {
267                   ++new_state.shared_waiting;
268                   if(!new_state.shared_waiting)
269                   {
270                       boost::throw_exception(boost::lock_error());
271                   }
272               }
273               else
274               {
275                   ++new_state.shared_count;
276                   if(!new_state.shared_count)
277                   {
278                       boost::throw_exception(boost::lock_error());
279                   }
280               }
281 
282               state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
283               if(current_state==old_state)
284               {
285                   break;
286               }
287               old_state=current_state;
288             }
289 
290             if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
291             {
292               return true;
293             }
294 
295             chrono::system_clock::time_point n = chrono::system_clock::now();
296             unsigned long res;
297             if (tp>n) {
298               chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
299               res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
300                 static_cast<unsigned long>(rel_time.count()), 0);
301             } else {
302               res=detail::win32::timeout;
303             }
304             if(res==detail::win32::timeout)
305             {
306               for(;;)
307               {
308                 state_data new_state=old_state;
309                 if(new_state.exclusive || new_state.exclusive_waiting_blocked)
310                 {
311                   if(new_state.shared_waiting)
312                   {
313                       --new_state.shared_waiting;
314                   }
315                 }
316                 else
317                 {
318                   ++new_state.shared_count;
319                   if(!new_state.shared_count)
320                   {
321                       return false;
322                   }
323                 }
324 
325                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
326                 if(current_state==old_state)
327                 {
328                     break;
329                 }
330                 old_state=current_state;
331               }
332 
333               if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
334               {
335                 return true;
336               }
337               return false;
338             }
339 
340             BOOST_ASSERT(res==0);
341           }
342         }
343 #endif
344 
unlock_shared()345         void unlock_shared()
346         {
347             state_data old_state=state;
348             for(;;)
349             {
350                 state_data new_state=old_state;
351                 bool const last_reader=!--new_state.shared_count;
352 
353                 if(last_reader)
354                 {
355                     if(new_state.upgrade)
356                     {
357                         new_state.upgrade=false;
358                         new_state.exclusive=true;
359                     }
360                     else
361                     {
362                         if(new_state.exclusive_waiting)
363                         {
364                             --new_state.exclusive_waiting;
365                             new_state.exclusive_waiting_blocked=false;
366                         }
367                         new_state.shared_waiting=0;
368                     }
369                 }
370 
371                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
372                 if(current_state==old_state)
373                 {
374                     if(last_reader)
375                     {
376                         if(old_state.upgrade)
377                         {
378                             BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
379                         }
380                         else
381                         {
382                             release_waiters(old_state);
383                         }
384                     }
385                     break;
386                 }
387                 old_state=current_state;
388             }
389         }
390 
lock()391         void lock()
392         {
393 
394 #if defined BOOST_THREAD_USES_DATETIME
395             BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
396 #else
397             BOOST_VERIFY(try_lock_until(chrono::steady_clock::now()));
398 #endif
399         }
400 
401 #if defined BOOST_THREAD_USES_DATETIME
402         template<typename TimeDuration>
timed_lock(TimeDuration const & relative_time)403         bool timed_lock(TimeDuration const & relative_time)
404         {
405             return timed_lock(get_system_time()+relative_time);
406         }
407 #endif
408 
try_lock()409         bool try_lock()
410         {
411             state_data old_state=state;
412             for(;;)
413             {
414                 state_data new_state=old_state;
415                 if(new_state.shared_count || new_state.exclusive)
416                 {
417                     return false;
418                 }
419                 else
420                 {
421                     new_state.exclusive=true;
422                 }
423 
424                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
425                 if(current_state==old_state)
426                 {
427                     break;
428                 }
429                 old_state=current_state;
430             }
431             return true;
432         }
433 
434 
435 #if defined BOOST_THREAD_USES_DATETIME
timed_lock(boost::system_time const & wait_until)436         bool timed_lock(boost::system_time const& wait_until)
437         {
438             for(;;)
439             {
440                 state_data old_state=state;
441 
442                 for(;;)
443                 {
444                     state_data new_state=old_state;
445                     if(new_state.shared_count || new_state.exclusive)
446                     {
447                         ++new_state.exclusive_waiting;
448                         if(!new_state.exclusive_waiting)
449                         {
450                             boost::throw_exception(boost::lock_error());
451                         }
452 
453                         new_state.exclusive_waiting_blocked=true;
454                     }
455                     else
456                     {
457                         new_state.exclusive=true;
458                     }
459 
460                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
461                     if(current_state==old_state)
462                     {
463                         break;
464                     }
465                     old_state=current_state;
466                 }
467 
468                 if(!old_state.shared_count && !old_state.exclusive)
469                 {
470                     return true;
471                 }
472                 #ifndef UNDER_CE
473                 const bool wait_all = true;
474                 #else
475                 const bool wait_all = false;
476                 #endif
477                 unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
478                 if(wait_res==detail::win32::timeout)
479                 {
480                     for(;;)
481                     {
482                         bool must_notify = false;
483                         state_data new_state=old_state;
484                         if(new_state.shared_count || new_state.exclusive)
485                         {
486                             if(new_state.exclusive_waiting)
487                             {
488                                 if(!--new_state.exclusive_waiting)
489                                 {
490                                     new_state.exclusive_waiting_blocked=false;
491                                     must_notify = true;
492                                 }
493                             }
494                         }
495                         else
496                         {
497                             new_state.exclusive=true;
498                         }
499 
500                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
501                         if (must_notify)
502                         {
503                           BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
504                         }
505 
506                         if(current_state==old_state)
507                         {
508                             break;
509                         }
510                         old_state=current_state;
511                     }
512                     if(!old_state.shared_count && !old_state.exclusive)
513                     {
514                         return true;
515                     }
516                     return false;
517                 }
518                 BOOST_ASSERT(wait_res<2);
519             }
520         }
521 #endif
522 #ifdef BOOST_THREAD_USES_CHRONO
523         template <class Rep, class Period>
try_lock_for(const chrono::duration<Rep,Period> & rel_time)524         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
525         {
526           return try_lock_until(chrono::steady_clock::now() + rel_time);
527         }
528         template <class Clock, class Duration>
try_lock_until(const chrono::time_point<Clock,Duration> & t)529         bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
530         {
531           using namespace chrono;
532           system_clock::time_point     s_now = system_clock::now();
533           typename Clock::time_point  c_now = Clock::now();
534           return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
535         }
536         template <class Duration>
try_lock_until(const chrono::time_point<chrono::system_clock,Duration> & t)537         bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
538         {
539           using namespace chrono;
540           typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
541           return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
542         }
try_lock_until(const chrono::time_point<chrono::system_clock,chrono::system_clock::duration> & tp)543         bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
544         {
545           for(;;)
546           {
547             state_data old_state=state;
548 
549             for(;;)
550             {
551               state_data new_state=old_state;
552               if(new_state.shared_count || new_state.exclusive)
553               {
554                 ++new_state.exclusive_waiting;
555                 if(!new_state.exclusive_waiting)
556                 {
557                     boost::throw_exception(boost::lock_error());
558                 }
559 
560                 new_state.exclusive_waiting_blocked=true;
561               }
562               else
563               {
564                 new_state.exclusive=true;
565               }
566 
567               state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
568               if(current_state==old_state)
569               {
570                 break;
571               }
572               old_state=current_state;
573             }
574 
575             if(!old_state.shared_count && !old_state.exclusive)
576             {
577                 return true;
578             }
579             #ifndef UNDER_CE
580             const bool wait_all = true;
581             #else
582             const bool wait_all = false;
583             #endif
584 
585             chrono::system_clock::time_point n = chrono::system_clock::now();
586             unsigned long wait_res;
587             if (tp>n) {
588               chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
589               wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
590                   static_cast<unsigned long>(rel_time.count()), 0);
591             } else {
592               wait_res=detail::win32::timeout;
593             }
594             if(wait_res==detail::win32::timeout)
595             {
596               for(;;)
597               {
598                 bool must_notify = false;
599                 state_data new_state=old_state;
600                 if(new_state.shared_count || new_state.exclusive)
601                 {
602                   if(new_state.exclusive_waiting)
603                   {
604                     if(!--new_state.exclusive_waiting)
605                     {
606                       new_state.exclusive_waiting_blocked=false;
607                       must_notify = true;
608                     }
609                   }
610                 }
611                 else
612                 {
613                   new_state.exclusive=true;
614                 }
615 
616                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
617                 if (must_notify)
618                 {
619                   BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
620                 }
621                 if(current_state==old_state)
622                 {
623                   break;
624                 }
625                 old_state=current_state;
626               }
627               if(!old_state.shared_count && !old_state.exclusive)
628               {
629                 return true;
630               }
631               return false;
632             }
633             BOOST_ASSERT(wait_res<2);
634           }
635         }
636 #endif
637 
unlock()638         void unlock()
639         {
640             state_data old_state=state;
641             for(;;)
642             {
643                 state_data new_state=old_state;
644                 new_state.exclusive=false;
645                 if(new_state.exclusive_waiting)
646                 {
647                     --new_state.exclusive_waiting;
648                     new_state.exclusive_waiting_blocked=false;
649                 }
650                 new_state.shared_waiting=0;
651 
652                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
653                 if(current_state==old_state)
654                 {
655                     break;
656                 }
657                 old_state=current_state;
658             }
659             release_waiters(old_state);
660         }
661 
lock_upgrade()662         void lock_upgrade()
663         {
664             for(;;)
665             {
666                 state_data old_state=state;
667                 for(;;)
668                 {
669                     state_data new_state=old_state;
670                     if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
671                     {
672                         ++new_state.shared_waiting;
673                         if(!new_state.shared_waiting)
674                         {
675                             boost::throw_exception(boost::lock_error());
676                         }
677                     }
678                     else
679                     {
680                         ++new_state.shared_count;
681                         if(!new_state.shared_count)
682                         {
683                             boost::throw_exception(boost::lock_error());
684                         }
685                         new_state.upgrade=true;
686                     }
687 
688                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
689                     if(current_state==old_state)
690                     {
691                         break;
692                     }
693                     old_state=current_state;
694                 }
695 
696                 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
697                 {
698                     return;
699                 }
700 
701                 BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
702             }
703         }
704 
try_lock_upgrade()705         bool try_lock_upgrade()
706         {
707             state_data old_state=state;
708             for(;;)
709             {
710                 state_data new_state=old_state;
711                 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
712                 {
713                     return false;
714                 }
715                 else
716                 {
717                     ++new_state.shared_count;
718                     if(!new_state.shared_count)
719                     {
720                         return false;
721                     }
722                     new_state.upgrade=true;
723                 }
724 
725                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
726                 if(current_state==old_state)
727                 {
728                     break;
729                 }
730                 old_state=current_state;
731             }
732             return true;
733         }
734 
unlock_upgrade()735         void unlock_upgrade()
736         {
737             state_data old_state=state;
738             for(;;)
739             {
740                 state_data new_state=old_state;
741                 new_state.upgrade=false;
742                 bool const last_reader=!--new_state.shared_count;
743 
744                 new_state.shared_waiting=0;
745                 if(last_reader)
746                 {
747                     if(new_state.exclusive_waiting)
748                     {
749                         --new_state.exclusive_waiting;
750                         new_state.exclusive_waiting_blocked=false;
751                     }
752                 }
753 
754                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
755                 if(current_state==old_state)
756                 {
757                     if(last_reader)
758                     {
759                         release_waiters(old_state);
760                     }
761                     else {
762                         release_shared_waiters(old_state);
763                     }
764                     // #7720
765                     //else {
766                     //    release_waiters(old_state);
767                     //}
768                     break;
769                 }
770                 old_state=current_state;
771             }
772         }
773 
unlock_upgrade_and_lock()774         void unlock_upgrade_and_lock()
775         {
776             state_data old_state=state;
777             for(;;)
778             {
779                 state_data new_state=old_state;
780                 bool const last_reader=!--new_state.shared_count;
781 
782                 if(last_reader)
783                 {
784                     new_state.upgrade=false;
785                     new_state.exclusive=true;
786                 }
787 
788                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
789                 if(current_state==old_state)
790                 {
791                     if(!last_reader)
792                     {
793                         BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
794                     }
795                     break;
796                 }
797                 old_state=current_state;
798             }
799         }
800 
unlock_and_lock_upgrade()801         void unlock_and_lock_upgrade()
802         {
803             state_data old_state=state;
804             for(;;)
805             {
806                 state_data new_state=old_state;
807                 new_state.exclusive=false;
808                 new_state.upgrade=true;
809                 ++new_state.shared_count;
810                 if(new_state.exclusive_waiting)
811                 {
812                     --new_state.exclusive_waiting;
813                     new_state.exclusive_waiting_blocked=false;
814                 }
815                 new_state.shared_waiting=0;
816 
817                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
818                 if(current_state==old_state)
819                 {
820                     break;
821                 }
822                 old_state=current_state;
823             }
824             release_waiters(old_state);
825         }
826 //        bool try_unlock_upgrade_and_lock()
827 //        {
828 //          return false;
829 //        }
830 //#ifdef BOOST_THREAD_USES_CHRONO
831 //        template <class Rep, class Period>
832 //        bool
833 //        try_unlock_upgrade_and_lock_for(
834 //                                const chrono::duration<Rep, Period>& rel_time)
835 //        {
836 //          return try_unlock_upgrade_and_lock_until(
837 //                                 chrono::steady_clock::now() + rel_time);
838 //        }
839 //        template <class Clock, class Duration>
840 //        bool
841 //        try_unlock_upgrade_and_lock_until(
842 //                          const chrono::time_point<Clock, Duration>& abs_time)
843 //        {
844 //          return false;
845 //        }
846 //#endif
847 
unlock_and_lock_shared()848         void unlock_and_lock_shared()
849         {
850             state_data old_state=state;
851             for(;;)
852             {
853                 state_data new_state=old_state;
854                 new_state.exclusive=false;
855                 ++new_state.shared_count;
856                 if(new_state.exclusive_waiting)
857                 {
858                     --new_state.exclusive_waiting;
859                     new_state.exclusive_waiting_blocked=false;
860                 }
861                 new_state.shared_waiting=0;
862 
863                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
864                 if(current_state==old_state)
865                 {
866                     break;
867                 }
868                 old_state=current_state;
869             }
870             release_waiters(old_state);
871         }
unlock_upgrade_and_lock_shared()872         void unlock_upgrade_and_lock_shared()
873         {
874             state_data old_state=state;
875             for(;;)
876             {
877                 state_data new_state=old_state;
878                 new_state.upgrade=false;
879                 if(new_state.exclusive_waiting)
880                 {
881                     --new_state.exclusive_waiting;
882                     new_state.exclusive_waiting_blocked=false;
883                 }
884                 new_state.shared_waiting=0;
885 
886                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
887                 if(current_state==old_state)
888                 {
889                     break;
890                 }
891                 old_state=current_state;
892             }
893             release_waiters(old_state);
894         }
895 
896     };
897     typedef shared_mutex upgrade_mutex;
898 
899 }
900 
901 #include <boost/config/abi_suffix.hpp>
902 
903 #endif
904