Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/thread/win32/shared_mutex.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 #ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
0002 #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
0003 
0004 //  (C) Copyright 2006-8 Anthony Williams
0005 //  (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba
0006 //
0007 //  Distributed under the Boost Software License, Version 1.0. (See
0008 //  accompanying file LICENSE_1_0.txt or copy at
0009 //  http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 #include <cstring>
0012 #include <boost/assert.hpp>
0013 #include <boost/detail/interlocked.hpp>
0014 #include <boost/thread/win32/thread_primitives.hpp>
0015 #include <boost/static_assert.hpp>
0016 #include <limits.h>
0017 #include <boost/thread/thread_time.hpp>
0018 #ifdef BOOST_THREAD_USES_CHRONO
0019 #include <boost/chrono/system_clocks.hpp>
0020 #include <boost/chrono/ceil.hpp>
0021 #endif
0022 #include <boost/thread/detail/delete.hpp>
0023 #include <boost/thread/detail/platform_time.hpp>
0024 
0025 #include <boost/config/abi_prefix.hpp>
0026 
0027 namespace boost
0028 {
0029     class shared_mutex
0030     {
0031     private:
0032         struct state_data
0033         {
0034             unsigned long shared_count:11,
0035                 shared_waiting:11,
0036                 exclusive:1,
0037                 upgrade:1,
0038                 exclusive_waiting:7,
0039                 exclusive_waiting_blocked:1;
0040 
0041             friend bool operator==(state_data const& lhs,state_data const& rhs)
0042             {
0043                 return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
0044             }
0045         };
0046 
0047         static state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand)
0048         {
0049             BOOST_STATIC_ASSERT(sizeof(state_data) == sizeof(long));
0050             long new_val, comp;
0051             std::memcpy(&new_val, &new_value, sizeof(new_value));
0052             std::memcpy(&comp, &comparand, sizeof(comparand));
0053             long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
0054                                                               new_val,
0055                                                               comp);
0056             state_data result;
0057             std::memcpy(&result, &res, sizeof(result));
0058             return result;
0059         }
0060 
0061         enum
0062         {
0063             unlock_sem = 0,
0064             exclusive_sem = 1
0065         };
0066 
0067         state_data state;
0068         detail::win32::handle semaphores[2];
0069         detail::win32::handle upgrade_sem;
0070 
0071         void release_waiters(state_data old_state)
0072         {
0073             if(old_state.exclusive_waiting)
0074             {
0075                 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
0076             }
0077 
0078             if(old_state.shared_waiting || old_state.exclusive_waiting)
0079             {
0080                 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
0081             }
0082         }
0083         void release_shared_waiters(state_data old_state)
0084         {
0085             if(old_state.shared_waiting || old_state.exclusive_waiting)
0086             {
0087                 BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
0088             }
0089         }
0090 
0091     public:
0092         BOOST_THREAD_NO_COPYABLE(shared_mutex)
0093         shared_mutex()
0094         {
0095             semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
0096             semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
0097             if (!semaphores[exclusive_sem])
0098             {
0099               detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
0100               boost::throw_exception(thread_resource_error());
0101             }
0102             upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
0103             if (!upgrade_sem)
0104             {
0105               detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
0106               detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
0107               boost::throw_exception(thread_resource_error());
0108             }
0109             state_data state_={0,0,0,0,0,0};
0110             state=state_;
0111         }
0112 
0113         ~shared_mutex()
0114         {
0115             winapi::CloseHandle(upgrade_sem);
0116             winapi::CloseHandle(semaphores[unlock_sem]);
0117             winapi::CloseHandle(semaphores[exclusive_sem]);
0118         }
0119 
0120         bool try_lock_shared()
0121         {
0122             state_data old_state=state;
0123             for(;;)
0124             {
0125                 state_data new_state=old_state;
0126                 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
0127                 {
0128                     ++new_state.shared_count;
0129                     if(!new_state.shared_count)
0130                     {
0131                         return false;
0132                     }
0133                 }
0134 
0135                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0136                 if(current_state==old_state)
0137                 {
0138                     break;
0139                 }
0140                 old_state=current_state;
0141             }
0142             return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
0143         }
0144 
0145         void lock_shared()
0146         {
0147             for(;;)
0148             {
0149                 state_data old_state=state;
0150                 for(;;)
0151                 {
0152                     state_data new_state=old_state;
0153                     if(new_state.exclusive || new_state.exclusive_waiting_blocked)
0154                     {
0155                         ++new_state.shared_waiting;
0156                         if(!new_state.shared_waiting)
0157                         {
0158                             boost::throw_exception(boost::lock_error());
0159                         }
0160                     }
0161                     else
0162                     {
0163                         ++new_state.shared_count;
0164                         if(!new_state.shared_count)
0165                         {
0166                             boost::throw_exception(boost::lock_error());
0167                         }
0168                     }
0169 
0170                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0171                     if(current_state==old_state)
0172                     {
0173                         break;
0174                     }
0175                     old_state=current_state;
0176                 }
0177 
0178                 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
0179                 {
0180                     return;
0181                 }
0182 
0183                 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0);
0184             }
0185         }
0186 
0187     private:
0188         unsigned long getMs(detail::platform_duration const& d)
0189         {
0190             return static_cast<unsigned long>(d.getMs());
0191         }
0192 
0193         template <typename Duration>
0194         unsigned long getMs(Duration const& d)
0195         {
0196             return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count());
0197         }
0198 
0199         template <typename Clock, typename Timepoint, typename Duration>
0200         bool do_lock_shared_until(Timepoint const& t, Duration const& max)
0201         {
0202             for(;;)
0203             {
0204                 state_data old_state=state;
0205                 for(;;)
0206                 {
0207                     state_data new_state=old_state;
0208                     if(new_state.exclusive || new_state.exclusive_waiting_blocked)
0209                     {
0210                         ++new_state.shared_waiting;
0211                         if(!new_state.shared_waiting)
0212                         {
0213                             boost::throw_exception(boost::lock_error());
0214                         }
0215                     }
0216                     else
0217                     {
0218                         ++new_state.shared_count;
0219                         if(!new_state.shared_count)
0220                         {
0221                             boost::throw_exception(boost::lock_error());
0222                         }
0223                     }
0224 
0225                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0226                     if(current_state==old_state)
0227                     {
0228                         break;
0229                     }
0230                     old_state=current_state;
0231                 }
0232 
0233                 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
0234                 {
0235                     return true;
0236                 }
0237 
0238                 // If the clock is the system clock, it may jump while this function
0239                 // is waiting. To compensate for this and time out near the correct
0240                 // time, we call WaitForSingleObjectEx() in a loop with a short
0241                 // timeout and recheck the time remaining each time through the loop.
0242                 unsigned long res=0;
0243                 for(;;)
0244                 {
0245                     Duration d(t - Clock::now());
0246                     if(d <= Duration::zero()) // timeout occurred
0247                     {
0248                         res=detail::win32::timeout;
0249                         break;
0250                     }
0251                     if(max != Duration::zero())
0252                     {
0253                         d = (std::min)(d, max);
0254                     }
0255                     res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0);
0256                     if(res!=detail::win32::timeout) // semaphore released
0257                     {
0258                         break;
0259                     }
0260                 }
0261 
0262                 if(res==detail::win32::timeout)
0263                 {
0264                     for(;;)
0265                     {
0266                         state_data new_state=old_state;
0267                         if(new_state.exclusive || new_state.exclusive_waiting_blocked)
0268                         {
0269                             if(new_state.shared_waiting)
0270                             {
0271                                 --new_state.shared_waiting;
0272                             }
0273                         }
0274                         else
0275                         {
0276                             ++new_state.shared_count;
0277                             if(!new_state.shared_count)
0278                             {
0279                                 return false;
0280                             }
0281                         }
0282 
0283                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0284                         if(current_state==old_state)
0285                         {
0286                             break;
0287                         }
0288                         old_state=current_state;
0289                     }
0290 
0291                     if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
0292                     {
0293                         return true;
0294                     }
0295                     return false;
0296                 }
0297 
0298                 BOOST_ASSERT(res==0);
0299             }
0300         }
0301     public:
0302 
0303 #if defined BOOST_THREAD_USES_DATETIME
0304         template<typename TimeDuration>
0305         bool timed_lock_shared(TimeDuration const & relative_time)
0306         {
0307             const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
0308             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0309             return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
0310         }
0311         bool timed_lock_shared(boost::system_time const& wait_until)
0312         {
0313             const detail::real_platform_timepoint t(wait_until);
0314             return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0315         }
0316 #endif
0317 
0318 #ifdef BOOST_THREAD_USES_CHRONO
0319         template <class Rep, class Period>
0320         bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
0321         {
0322             const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
0323             typedef typename chrono::duration<Rep, Period> Duration;
0324             typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0325             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0326             return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
0327         }
0328         template <class Duration>
0329         bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
0330         {
0331             typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0332             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0333             return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero());
0334         }
0335         template <class Clock, class Duration>
0336         bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
0337         {
0338             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0339             return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0340         }
0341 #endif
0342 
0343         void unlock_shared()
0344         {
0345             state_data old_state=state;
0346             for(;;)
0347             {
0348                 state_data new_state=old_state;
0349                 bool const last_reader=!--new_state.shared_count;
0350 
0351                 if(last_reader)
0352                 {
0353                     if(new_state.upgrade)
0354                     {
0355                         new_state.upgrade=false;
0356                         new_state.exclusive=true;
0357                     }
0358                     else
0359                     {
0360                         if(new_state.exclusive_waiting)
0361                         {
0362                             --new_state.exclusive_waiting;
0363                             new_state.exclusive_waiting_blocked=false;
0364                         }
0365                         new_state.shared_waiting=0;
0366                     }
0367                 }
0368 
0369                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0370                 if(current_state==old_state)
0371                 {
0372                     if(last_reader)
0373                     {
0374                         if(old_state.upgrade)
0375                         {
0376                             BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0);
0377                         }
0378                         else
0379                         {
0380                             release_waiters(old_state);
0381                         }
0382                     }
0383                     break;
0384                 }
0385                 old_state=current_state;
0386             }
0387         }
0388 
0389         bool try_lock()
0390         {
0391             state_data old_state=state;
0392             for(;;)
0393             {
0394                 state_data new_state=old_state;
0395                 if(new_state.shared_count || new_state.exclusive)
0396                 {
0397                     return false;
0398                 }
0399                 else
0400                 {
0401                     new_state.exclusive=true;
0402                 }
0403 
0404                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0405                 if(current_state==old_state)
0406                 {
0407                     break;
0408                 }
0409                 old_state=current_state;
0410             }
0411             return true;
0412         }
0413 
0414         void lock()
0415         {
0416             for(;;)
0417             {
0418                 state_data old_state=state;
0419                 for(;;)
0420                 {
0421                     state_data new_state=old_state;
0422                     if(new_state.shared_count || new_state.exclusive)
0423                     {
0424                         ++new_state.exclusive_waiting;
0425                         if(!new_state.exclusive_waiting)
0426                         {
0427                             boost::throw_exception(boost::lock_error());
0428                         }
0429 
0430                         new_state.exclusive_waiting_blocked=true;
0431                     }
0432                     else
0433                     {
0434                         new_state.exclusive=true;
0435                     }
0436 
0437                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0438                     if(current_state==old_state)
0439                     {
0440                         break;
0441                     }
0442                     old_state=current_state;
0443                 }
0444 
0445                 if(!old_state.shared_count && !old_state.exclusive)
0446                 {
0447                     return;
0448                 }
0449 
0450                 #ifndef UNDER_CE
0451                 const bool wait_all = true;
0452                 #else
0453                 const bool wait_all = false;
0454                 #endif
0455                 BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2);
0456             }
0457         }
0458 
0459     private:
0460         template <typename Clock, typename Timepoint, typename Duration>
0461         bool do_lock_until(Timepoint const& t, Duration const& max)
0462         {
0463             for(;;)
0464             {
0465                 state_data old_state=state;
0466                 for(;;)
0467                 {
0468                     state_data new_state=old_state;
0469                     if(new_state.shared_count || new_state.exclusive)
0470                     {
0471                         ++new_state.exclusive_waiting;
0472                         if(!new_state.exclusive_waiting)
0473                         {
0474                             boost::throw_exception(boost::lock_error());
0475                         }
0476 
0477                         new_state.exclusive_waiting_blocked=true;
0478                     }
0479                     else
0480                     {
0481                         new_state.exclusive=true;
0482                     }
0483 
0484                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0485                     if(current_state==old_state)
0486                     {
0487                         break;
0488                     }
0489                     old_state=current_state;
0490                 }
0491 
0492                 if(!old_state.shared_count && !old_state.exclusive)
0493                 {
0494                     return true;
0495                 }
0496 
0497                 // If the clock is the system clock, it may jump while this function
0498                 // is waiting. To compensate for this and time out near the correct
0499                 // time, we call WaitForMultipleObjectsEx() in a loop with a short
0500                 // timeout and recheck the time remaining each time through the loop.
0501                 unsigned long wait_res=0;
0502                 for(;;)
0503                 {
0504                     Duration d(t - Clock::now());
0505                     if(d <= Duration::zero()) // timeout occurred
0506                     {
0507                         wait_res=detail::win32::timeout;
0508                         break;
0509                     }
0510                     if(max != Duration::zero())
0511                     {
0512                         d = (std::min)(d, max);
0513                     }
0514                     #ifndef UNDER_CE
0515                     wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0);
0516                     #else
0517                     wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0);
0518                     #endif
0519                     //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0);
0520 
0521                     if(wait_res!=detail::win32::timeout) // semaphore released
0522                     {
0523                         break;
0524                     }
0525                 }
0526 
0527                 if(wait_res==detail::win32::timeout)
0528                 {
0529                     for(;;)
0530                     {
0531                         bool must_notify = false;
0532                         state_data new_state=old_state;
0533                         if(new_state.shared_count || new_state.exclusive)
0534                         {
0535                             if(new_state.exclusive_waiting)
0536                             {
0537                                 if(!--new_state.exclusive_waiting)
0538                                 {
0539                                     new_state.exclusive_waiting_blocked=false;
0540                                     must_notify = true;
0541                                 }
0542                             }
0543                         }
0544                         else
0545                         {
0546                             new_state.exclusive=true;
0547                         }
0548 
0549                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0550                         if (must_notify)
0551                         {
0552                           BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0);
0553                         }
0554 
0555                         if(current_state==old_state)
0556                         {
0557                             break;
0558                         }
0559                         old_state=current_state;
0560                     }
0561                     if(!old_state.shared_count && !old_state.exclusive)
0562                     {
0563                         return true;
0564                     }
0565                     return false;
0566                 }
0567 
0568                 BOOST_ASSERT(wait_res<2);
0569             }
0570         }
0571     public:
0572 
0573 #if defined BOOST_THREAD_USES_DATETIME
0574         bool timed_lock(boost::system_time const& wait_until)
0575         {
0576             const detail::real_platform_timepoint t(wait_until);
0577             return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0578         }
0579         template<typename TimeDuration>
0580         bool timed_lock(TimeDuration const & relative_time)
0581         {
0582             const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time));
0583             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0584             return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero());
0585         }
0586 #endif
0587 #ifdef BOOST_THREAD_USES_CHRONO
0588         template <class Rep, class Period>
0589         bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
0590         {
0591             const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time);
0592             typedef typename chrono::duration<Rep, Period> Duration;
0593             typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0594             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0595             return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
0596         }
0597         template <class Duration>
0598         bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
0599         {
0600             typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration;
0601             // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max)
0602             return do_lock_until<chrono::steady_clock>(t, common_duration::zero());
0603         }
0604         template <class Clock, class Duration>
0605         bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
0606         {
0607             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0608             return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0609         }
0610 #endif
0611 
0612         void unlock()
0613         {
0614             state_data old_state=state;
0615             for(;;)
0616             {
0617                 state_data new_state=old_state;
0618                 new_state.exclusive=false;
0619                 if(new_state.exclusive_waiting)
0620                 {
0621                     --new_state.exclusive_waiting;
0622                     new_state.exclusive_waiting_blocked=false;
0623                 }
0624                 new_state.shared_waiting=0;
0625 
0626                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0627                 if(current_state==old_state)
0628                 {
0629                     break;
0630                 }
0631                 old_state=current_state;
0632             }
0633             release_waiters(old_state);
0634         }
0635 
0636         void lock_upgrade()
0637         {
0638             for(;;)
0639             {
0640                 state_data old_state=state;
0641                 for(;;)
0642                 {
0643                     state_data new_state=old_state;
0644                     if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
0645                     {
0646                         ++new_state.shared_waiting;
0647                         if(!new_state.shared_waiting)
0648                         {
0649                             boost::throw_exception(boost::lock_error());
0650                         }
0651                     }
0652                     else
0653                     {
0654                         ++new_state.shared_count;
0655                         if(!new_state.shared_count)
0656                         {
0657                             boost::throw_exception(boost::lock_error());
0658                         }
0659                         new_state.upgrade=true;
0660                     }
0661 
0662                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0663                     if(current_state==old_state)
0664                     {
0665                         break;
0666                     }
0667                     old_state=current_state;
0668                 }
0669 
0670                 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
0671                 {
0672                     return;
0673                 }
0674 
0675                 BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0);
0676             }
0677         }
0678 
0679         bool try_lock_upgrade()
0680         {
0681             state_data old_state=state;
0682             for(;;)
0683             {
0684                 state_data new_state=old_state;
0685                 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
0686                 {
0687                     return false;
0688                 }
0689                 else
0690                 {
0691                     ++new_state.shared_count;
0692                     if(!new_state.shared_count)
0693                     {
0694                         return false;
0695                     }
0696                     new_state.upgrade=true;
0697                 }
0698 
0699                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0700                 if(current_state==old_state)
0701                 {
0702                     break;
0703                 }
0704                 old_state=current_state;
0705             }
0706             return true;
0707         }
0708 
0709         void unlock_upgrade()
0710         {
0711             state_data old_state=state;
0712             for(;;)
0713             {
0714                 state_data new_state=old_state;
0715                 new_state.upgrade=false;
0716                 bool const last_reader=!--new_state.shared_count;
0717 
0718                 new_state.shared_waiting=0;
0719                 if(last_reader)
0720                 {
0721                     if(new_state.exclusive_waiting)
0722                     {
0723                         --new_state.exclusive_waiting;
0724                         new_state.exclusive_waiting_blocked=false;
0725                     }
0726                 }
0727 
0728                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0729                 if(current_state==old_state)
0730                 {
0731                     if(last_reader)
0732                     {
0733                         release_waiters(old_state);
0734                     }
0735                     else {
0736                         release_shared_waiters(old_state);
0737                     }
0738                     // #7720
0739                     //else {
0740                     //    release_waiters(old_state);
0741                     //}
0742                     break;
0743                 }
0744                 old_state=current_state;
0745             }
0746         }
0747 
0748         void unlock_upgrade_and_lock()
0749         {
0750             state_data old_state=state;
0751             for(;;)
0752             {
0753                 state_data new_state=old_state;
0754                 bool const last_reader=!--new_state.shared_count;
0755 
0756                 if(last_reader)
0757                 {
0758                     new_state.upgrade=false;
0759                     new_state.exclusive=true;
0760                 }
0761 
0762                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0763                 if(current_state==old_state)
0764                 {
0765                     if(!last_reader)
0766                     {
0767                         BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0);
0768                     }
0769                     break;
0770                 }
0771                 old_state=current_state;
0772             }
0773         }
0774 
0775         void unlock_and_lock_upgrade()
0776         {
0777             state_data old_state=state;
0778             for(;;)
0779             {
0780                 state_data new_state=old_state;
0781                 new_state.exclusive=false;
0782                 new_state.upgrade=true;
0783                 ++new_state.shared_count;
0784                 if(new_state.exclusive_waiting)
0785                 {
0786                     --new_state.exclusive_waiting;
0787                     new_state.exclusive_waiting_blocked=false;
0788                 }
0789                 new_state.shared_waiting=0;
0790 
0791                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0792                 if(current_state==old_state)
0793                 {
0794                     break;
0795                 }
0796                 old_state=current_state;
0797             }
0798             release_waiters(old_state);
0799         }
0800 
0801         void unlock_and_lock_shared()
0802         {
0803             state_data old_state=state;
0804             for(;;)
0805             {
0806                 state_data new_state=old_state;
0807                 new_state.exclusive=false;
0808                 ++new_state.shared_count;
0809                 if(new_state.exclusive_waiting)
0810                 {
0811                     --new_state.exclusive_waiting;
0812                     new_state.exclusive_waiting_blocked=false;
0813                 }
0814                 new_state.shared_waiting=0;
0815 
0816                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0817                 if(current_state==old_state)
0818                 {
0819                     break;
0820                 }
0821                 old_state=current_state;
0822             }
0823             release_waiters(old_state);
0824         }
0825         void unlock_upgrade_and_lock_shared()
0826         {
0827             state_data old_state=state;
0828             for(;;)
0829             {
0830                 state_data new_state=old_state;
0831                 new_state.upgrade=false;
0832                 if(new_state.exclusive_waiting)
0833                 {
0834                     --new_state.exclusive_waiting;
0835                     new_state.exclusive_waiting_blocked=false;
0836                 }
0837                 new_state.shared_waiting=0;
0838 
0839                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
0840                 if(current_state==old_state)
0841                 {
0842                     break;
0843                 }
0844                 old_state=current_state;
0845             }
0846             release_waiters(old_state);
0847         }
0848 
0849     };
0850     typedef shared_mutex upgrade_mutex;
0851 
0852 }
0853 
0854 #include <boost/config/abi_suffix.hpp>
0855 
0856 #endif