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