]> git.sesse.net Git - casparcg/blob - dependencies/boost/boost/thread/win32/shared_mutex.hpp
Manually merged pull request #222
[casparcg] / dependencies / boost / boost / thread / win32 / shared_mutex.hpp
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 //
6 //  Distributed under the Boost Software License, Version 1.0. (See
7 //  accompanying file LICENSE_1_0.txt or copy at
8 //  http://www.boost.org/LICENSE_1_0.txt)
9
10 #include <boost/assert.hpp>
11 #include <boost/detail/interlocked.hpp>
12 #include <boost/thread/win32/thread_primitives.hpp>
13 #include <boost/static_assert.hpp>
14 #include <limits.h>
15 #include <boost/utility.hpp>
16 #include <boost/thread/thread_time.hpp>
17
18 #include <boost/config/abi_prefix.hpp>
19
20 namespace boost
21 {
22     class shared_mutex
23     {
24     private:
25         shared_mutex(shared_mutex const&);
26         shared_mutex& operator=(shared_mutex const&);        
27     private:
28         struct state_data
29         {
30             unsigned shared_count:11,
31                 shared_waiting:11,
32                 exclusive:1,
33                 upgrade:1,
34                 exclusive_waiting:7,
35                 exclusive_waiting_blocked:1;
36
37             friend bool operator==(state_data const& lhs,state_data const& rhs)
38             {
39                 return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
40             }
41         };
42         
43
44         template<typename T>
45         T interlocked_compare_exchange(T* target,T new_value,T comparand)
46         {
47             BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
48             long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
49                                                               *reinterpret_cast<long*>(&new_value),
50                                                               *reinterpret_cast<long*>(&comparand));
51             return *reinterpret_cast<T const*>(&res);
52         }
53
54         enum
55         {
56             unlock_sem = 0,
57             exclusive_sem = 1
58         };
59
60         state_data state;
61         detail::win32::handle semaphores[2];
62         detail::win32::handle upgrade_sem;
63
64         void release_waiters(state_data old_state)
65         {
66             if(old_state.exclusive_waiting)
67             {
68                 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
69             }
70                         
71             if(old_state.shared_waiting || old_state.exclusive_waiting)
72             {
73                 BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
74             }
75         }
76         
77
78     public:
79         shared_mutex()
80         {
81             semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
82             semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
83             upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
84             state_data state_={0};
85             state=state_;
86         }
87
88         ~shared_mutex()
89         {
90             detail::win32::CloseHandle(upgrade_sem);
91             detail::win32::CloseHandle(semaphores[unlock_sem]);
92             detail::win32::CloseHandle(semaphores[exclusive_sem]);
93         }
94
95         bool try_lock_shared()
96         {
97             state_data old_state=state;
98             for(;;)
99             {
100                 state_data new_state=old_state;
101                 if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
102                 {
103                     ++new_state.shared_count;
104                     if(!new_state.shared_count)
105                     {
106                         return false;
107                     }
108                 }
109                 
110                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
111                 if(current_state==old_state)
112                 {
113                     break;
114                 }
115                 old_state=current_state;
116             }
117             return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
118         }
119
120         void lock_shared()
121         {
122             BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
123         }
124
125         template<typename TimeDuration>
126         bool timed_lock_shared(TimeDuration const & relative_time)
127         {
128             return timed_lock_shared(get_system_time()+relative_time);
129         }
130
131         bool timed_lock_shared(boost::system_time const& wait_until)
132         {
133             for(;;)
134             {
135                 state_data old_state=state;
136                 for(;;)
137                 {
138                     state_data new_state=old_state;
139                     if(new_state.exclusive || new_state.exclusive_waiting_blocked)
140                     {
141                         ++new_state.shared_waiting;
142                         if(!new_state.shared_waiting)
143                         {
144                             boost::throw_exception(boost::lock_error());
145                         }
146                     }
147                     else
148                     {
149                         ++new_state.shared_count;
150                         if(!new_state.shared_count)
151                         {
152                             boost::throw_exception(boost::lock_error());
153                         }
154                     }
155
156                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
157                     if(current_state==old_state)
158                     {
159                         break;
160                     }
161                     old_state=current_state;
162                 }
163
164                 if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
165                 {
166                     return true;
167                 }
168                     
169                 unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
170                 if(res==detail::win32::timeout)
171                 {
172                     for(;;)
173                     {
174                         state_data new_state=old_state;
175                         if(new_state.exclusive || new_state.exclusive_waiting_blocked)
176                         {
177                             if(new_state.shared_waiting)
178                             {
179                                 --new_state.shared_waiting;
180                             }
181                         }
182                         else
183                         {
184                             ++new_state.shared_count;
185                             if(!new_state.shared_count)
186                             {
187                                 return false;
188                             }
189                         }
190
191                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
192                         if(current_state==old_state)
193                         {
194                             break;
195                         }
196                         old_state=current_state;
197                     }
198
199                     if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
200                     {
201                         return true;
202                     }
203                     return false;
204                 }
205                 
206                 BOOST_ASSERT(res==0);
207             }
208         }
209
210         void unlock_shared()
211         {
212             state_data old_state=state;
213             for(;;)
214             {
215                 state_data new_state=old_state;
216                 bool const last_reader=!--new_state.shared_count;
217                 
218                 if(last_reader)
219                 {
220                     if(new_state.upgrade)
221                     {
222                         new_state.upgrade=false;
223                         new_state.exclusive=true;
224                     }
225                     else
226                     {
227                         if(new_state.exclusive_waiting)
228                         {
229                             --new_state.exclusive_waiting;
230                             new_state.exclusive_waiting_blocked=false;
231                         }
232                         new_state.shared_waiting=0;
233                     }
234                 }
235                 
236                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
237                 if(current_state==old_state)
238                 {
239                     if(last_reader)
240                     {
241                         if(old_state.upgrade)
242                         {
243                             BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
244                         }
245                         else
246                         {
247                             release_waiters(old_state);
248                         }
249                     }
250                     break;
251                 }
252                 old_state=current_state;
253             }
254         }
255
256         void lock()
257         {
258             BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
259         }
260
261         template<typename TimeDuration>
262         bool timed_lock(TimeDuration const & relative_time)
263         {
264             return timed_lock(get_system_time()+relative_time);
265         }
266
267         bool try_lock()
268         {
269             state_data old_state=state;
270             for(;;)
271             {
272                 state_data new_state=old_state;
273                 if(new_state.shared_count || new_state.exclusive)
274                 {
275                     return false;
276                 }
277                 else
278                 {
279                     new_state.exclusive=true;
280                 }
281                 
282                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
283                 if(current_state==old_state)
284                 {
285                     break;
286                 }
287                 old_state=current_state;
288             }
289             return true;
290         }
291
292
293         bool timed_lock(boost::system_time const& wait_until)
294         {
295             for(;;)
296             {
297                 state_data old_state=state;
298
299                 for(;;)
300                 {
301                     state_data new_state=old_state;
302                     if(new_state.shared_count || new_state.exclusive)
303                     {
304                         ++new_state.exclusive_waiting;
305                         if(!new_state.exclusive_waiting)
306                         {
307                             boost::throw_exception(boost::lock_error());
308                         }
309                         
310                         new_state.exclusive_waiting_blocked=true;
311                     }
312                     else
313                     {
314                         new_state.exclusive=true;
315                     }
316
317                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
318                     if(current_state==old_state)
319                     {
320                         break;
321                     }
322                     old_state=current_state;
323                 }
324
325                 if(!old_state.shared_count && !old_state.exclusive)
326                 {
327                     return true;
328                 }
329                 unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
330                 if(wait_res==detail::win32::timeout)
331                 {
332                     for(;;)
333                     {
334                         state_data new_state=old_state;
335                         if(new_state.shared_count || new_state.exclusive)
336                         {
337                             if(new_state.exclusive_waiting)
338                             {
339                                 if(!--new_state.exclusive_waiting)
340                                 {
341                                     new_state.exclusive_waiting_blocked=false;
342                                 }
343                             }
344                         }
345                         else
346                         {
347                             new_state.exclusive=true;
348                         }
349
350                         state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
351                         if(current_state==old_state)
352                         {
353                             break;
354                         }
355                         old_state=current_state;
356                     }
357                     if(!old_state.shared_count && !old_state.exclusive)
358                     {
359                         return true;
360                     }
361                     return false;
362                 }
363                 BOOST_ASSERT(wait_res<2);
364             }
365         }
366
367         void unlock()
368         {
369             state_data old_state=state;
370             for(;;)
371             {
372                 state_data new_state=old_state;
373                 new_state.exclusive=false;
374                 if(new_state.exclusive_waiting)
375                 {
376                     --new_state.exclusive_waiting;
377                     new_state.exclusive_waiting_blocked=false;
378                 }
379                 new_state.shared_waiting=0;
380
381                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
382                 if(current_state==old_state)
383                 {
384                     break;
385                 }
386                 old_state=current_state;
387             }
388             release_waiters(old_state);
389         }
390
391         void lock_upgrade()
392         {
393             for(;;)
394             {
395                 state_data old_state=state;
396                 for(;;)
397                 {
398                     state_data new_state=old_state;
399                     if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
400                     {
401                         ++new_state.shared_waiting;
402                         if(!new_state.shared_waiting)
403                         {
404                             boost::throw_exception(boost::lock_error());
405                         }
406                     }
407                     else
408                     {
409                         ++new_state.shared_count;
410                         if(!new_state.shared_count)
411                         {
412                             boost::throw_exception(boost::lock_error());
413                         }
414                         new_state.upgrade=true;
415                     }
416
417                     state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
418                     if(current_state==old_state)
419                     {
420                         break;
421                     }
422                     old_state=current_state;
423                 }
424
425                 if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
426                 {
427                     return;
428                 }
429                     
430                 BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
431             }
432         }
433
434         bool try_lock_upgrade()
435         {
436             state_data old_state=state;
437             for(;;)
438             {
439                 state_data new_state=old_state;
440                 if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
441                 {
442                     return false;
443                 }
444                 else
445                 {
446                     ++new_state.shared_count;
447                     if(!new_state.shared_count)
448                     {
449                         return false;
450                     }
451                     new_state.upgrade=true;
452                 }
453                 
454                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
455                 if(current_state==old_state)
456                 {
457                     break;
458                 }
459                 old_state=current_state;
460             }
461             return true;
462         }
463
464         void unlock_upgrade()
465         {
466             state_data old_state=state;
467             for(;;)
468             {
469                 state_data new_state=old_state;
470                 new_state.upgrade=false;
471                 bool const last_reader=!--new_state.shared_count;
472                 
473                 if(last_reader)
474                 {
475                     if(new_state.exclusive_waiting)
476                     {
477                         --new_state.exclusive_waiting;
478                         new_state.exclusive_waiting_blocked=false;
479                     }
480                     new_state.shared_waiting=0;
481                 }
482                 
483                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
484                 if(current_state==old_state)
485                 {
486                     if(last_reader)
487                     {
488                         release_waiters(old_state);
489                     }
490                     break;
491                 }
492                 old_state=current_state;
493             }
494         }
495
496         void unlock_upgrade_and_lock()
497         {
498             state_data old_state=state;
499             for(;;)
500             {
501                 state_data new_state=old_state;
502                 bool const last_reader=!--new_state.shared_count;
503                 
504                 if(last_reader)
505                 {
506                     new_state.upgrade=false;
507                     new_state.exclusive=true;
508                 }
509                 
510                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
511                 if(current_state==old_state)
512                 {
513                     if(!last_reader)
514                     {
515                         BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
516                     }
517                     break;
518                 }
519                 old_state=current_state;
520             }
521         }
522
523         void unlock_and_lock_upgrade()
524         {
525             state_data old_state=state;
526             for(;;)
527             {
528                 state_data new_state=old_state;
529                 new_state.exclusive=false;
530                 new_state.upgrade=true;
531                 ++new_state.shared_count;
532                 if(new_state.exclusive_waiting)
533                 {
534                     --new_state.exclusive_waiting;
535                     new_state.exclusive_waiting_blocked=false;
536                 }
537                 new_state.shared_waiting=0;
538
539                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
540                 if(current_state==old_state)
541                 {
542                     break;
543                 }
544                 old_state=current_state;
545             }
546             release_waiters(old_state);
547         }
548         
549         void unlock_and_lock_shared()
550         {
551             state_data old_state=state;
552             for(;;)
553             {
554                 state_data new_state=old_state;
555                 new_state.exclusive=false;
556                 ++new_state.shared_count;
557                 if(new_state.exclusive_waiting)
558                 {
559                     --new_state.exclusive_waiting;
560                     new_state.exclusive_waiting_blocked=false;
561                 }
562                 new_state.shared_waiting=0;
563
564                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
565                 if(current_state==old_state)
566                 {
567                     break;
568                 }
569                 old_state=current_state;
570             }
571             release_waiters(old_state);
572         }
573         
574         void unlock_upgrade_and_lock_shared()
575         {
576             state_data old_state=state;
577             for(;;)
578             {
579                 state_data new_state=old_state;
580                 new_state.upgrade=false;
581                 if(new_state.exclusive_waiting)
582                 {
583                     --new_state.exclusive_waiting;
584                     new_state.exclusive_waiting_blocked=false;
585                 }
586                 new_state.shared_waiting=0;
587
588                 state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
589                 if(current_state==old_state)
590                 {
591                     break;
592                 }
593                 old_state=current_state;
594             }
595             release_waiters(old_state);
596         }
597         
598     };
599 }
600
601 #include <boost/config/abi_suffix.hpp>
602
603 #endif