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