]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/spin_rw_mutex.h
(no commit message)
[casparcg] / tbb30_20100406oss / include / tbb / spin_rw_mutex.h
1 /*
2     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB_spin_rw_mutex_H
30 #define __TBB_spin_rw_mutex_H
31
32 #include "tbb_stddef.h"
33 #include "tbb_machine.h"
34 #include "tbb_profiling.h"
35
36 namespace tbb {
37
38 class spin_rw_mutex_v3;
39 typedef spin_rw_mutex_v3 spin_rw_mutex;
40
41 //! Fast, unfair, spinning reader-writer lock with backoff and writer-preference
42 /** @ingroup synchronization */
43 class spin_rw_mutex_v3 {
44     //! @cond INTERNAL
45
46     //! Internal acquire write lock.
47     bool __TBB_EXPORTED_METHOD internal_acquire_writer();
48
49     //! Out of line code for releasing a write lock.  
50     /** This code is has debug checking and instrumentation for Intel(R) Thread Checker and Intel(R) Thread Profiler. */
51     void __TBB_EXPORTED_METHOD internal_release_writer();
52
53     //! Internal acquire read lock.
54     void __TBB_EXPORTED_METHOD internal_acquire_reader();
55
56     //! Internal upgrade reader to become a writer.
57     bool __TBB_EXPORTED_METHOD internal_upgrade();
58
59     //! Out of line code for downgrading a writer to a reader.   
60     /** This code is has debug checking and instrumentation for Intel(R) Thread Checker and Intel(R) Thread Profiler. */
61     void __TBB_EXPORTED_METHOD internal_downgrade();
62
63     //! Internal release read lock.
64     void __TBB_EXPORTED_METHOD internal_release_reader();
65
66     //! Internal try_acquire write lock.
67     bool __TBB_EXPORTED_METHOD internal_try_acquire_writer();
68
69     //! Internal try_acquire read lock.
70     bool __TBB_EXPORTED_METHOD internal_try_acquire_reader();
71
72     //! @endcond
73 public:
74     //! Construct unacquired mutex.
75     spin_rw_mutex_v3() : state(0) {
76 #if TBB_USE_THREADING_TOOLS
77         internal_construct();
78 #endif
79     }
80
81 #if TBB_USE_ASSERT
82     //! Destructor asserts if the mutex is acquired, i.e. state is zero.
83     ~spin_rw_mutex_v3() {
84         __TBB_ASSERT( !state, "destruction of an acquired mutex");
85     };
86 #endif /* TBB_USE_ASSERT */
87
88     //! The scoped locking pattern
89     /** It helps to avoid the common problem of forgetting to release lock.
90         It also nicely provides the "node" for queuing locks. */
91     class scoped_lock : internal::no_copy {
92     public:
93         //! Construct lock that has not acquired a mutex.
94         /** Equivalent to zero-initialization of *this. */
95         scoped_lock() : mutex(NULL), is_writer(false) {}
96
97         //! Acquire lock on given mutex.
98         scoped_lock( spin_rw_mutex& m, bool write = true ) : mutex(NULL) {
99             acquire(m, write);
100         }
101
102         //! Release lock (if lock is held).
103         ~scoped_lock() {
104             if( mutex ) release();
105         }
106
107         //! Acquire lock on given mutex.
108         void acquire( spin_rw_mutex& m, bool write = true ) {
109             __TBB_ASSERT( !mutex, "holding mutex already" );
110             is_writer = write; 
111             mutex = &m;
112             if( write ) mutex->internal_acquire_writer();
113             else        mutex->internal_acquire_reader();
114         }
115
116         //! Upgrade reader to become a writer.
117         /** Returns true if the upgrade happened without re-acquiring the lock and false if opposite */
118         bool upgrade_to_writer() {
119             __TBB_ASSERT( mutex, "lock is not acquired" );
120             __TBB_ASSERT( !is_writer, "not a reader" );
121             is_writer = true; 
122             return mutex->internal_upgrade();
123         }
124
125         //! Release lock.
126         void release() {
127             __TBB_ASSERT( mutex, "lock is not acquired" );
128             spin_rw_mutex *m = mutex; 
129             mutex = NULL;
130 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
131             if( is_writer ) m->internal_release_writer();
132             else            m->internal_release_reader();
133 #else
134             if( is_writer ) __TBB_AtomicAND( &m->state, READERS ); 
135             else            __TBB_FetchAndAddWrelease( &m->state, -(intptr_t)ONE_READER);
136 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
137         }
138
139         //! Downgrade writer to become a reader.
140         bool downgrade_to_reader() {
141 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
142             __TBB_ASSERT( mutex, "lock is not acquired" );
143             __TBB_ASSERT( is_writer, "not a writer" );
144             mutex->internal_downgrade();
145 #else
146             __TBB_FetchAndAddW( &mutex->state, ((intptr_t)ONE_READER-WRITER));
147 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
148             is_writer = false;
149
150             return true;
151         }
152
153         //! Try acquire lock on given mutex.
154         bool try_acquire( spin_rw_mutex& m, bool write = true ) {
155             __TBB_ASSERT( !mutex, "holding mutex already" );
156             bool result;
157             is_writer = write; 
158             result = write? m.internal_try_acquire_writer()
159                           : m.internal_try_acquire_reader();
160             if( result ) 
161                 mutex = &m;
162             return result;
163         }
164
165     private:
166         //! The pointer to the current mutex that is held, or NULL if no mutex is held.
167         spin_rw_mutex* mutex;
168
169         //! If mutex!=NULL, then is_writer is true if holding a writer lock, false if holding a reader lock.
170         /** Not defined if not holding a lock. */
171         bool is_writer;
172     };
173
174     // Mutex traits
175     static const bool is_rw_mutex = true;
176     static const bool is_recursive_mutex = false;
177     static const bool is_fair_mutex = false;
178
179     // ISO C++0x compatibility methods
180
181     //! Acquire writer lock
182     void lock() {internal_acquire_writer();}
183
184     //! Try acquiring writer lock (non-blocking)
185     /** Return true if lock acquired; false otherwise. */
186     bool try_lock() {return internal_try_acquire_writer();}
187
188     //! Release lock
189     void unlock() {
190 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
191         if( state&WRITER ) internal_release_writer();
192         else               internal_release_reader();
193 #else
194         if( state&WRITER ) __TBB_AtomicAND( &state, READERS ); 
195         else               __TBB_FetchAndAddWrelease( &state, -(intptr_t)ONE_READER);
196 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
197     }
198
199     // Methods for reader locks that resemble ISO C++0x compatibility methods.
200
201     //! Acquire reader lock
202     void lock_read() {internal_acquire_reader();}
203
204     //! Try acquiring reader lock (non-blocking)
205     /** Return true if reader lock acquired; false otherwise. */
206     bool try_lock_read() {return internal_try_acquire_reader();}
207
208 private:
209     typedef intptr_t state_t;
210     static const state_t WRITER = 1;
211     static const state_t WRITER_PENDING = 2;
212     static const state_t READERS = ~(WRITER | WRITER_PENDING);
213     static const state_t ONE_READER = 4;
214     static const state_t BUSY = WRITER | READERS;
215     //! State of lock
216     /** Bit 0 = writer is holding lock
217         Bit 1 = request by a writer to acquire lock (hint to readers to wait)
218         Bit 2..N = number of readers holding lock */
219     state_t state;
220
221     void __TBB_EXPORTED_METHOD internal_construct();
222 };
223
224 __TBB_DEFINE_PROFILING_SET_NAME(spin_rw_mutex)
225
226 } // namespace tbb
227
228 #endif /* __TBB_spin_rw_mutex_H */