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