Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:59

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #ifndef __TBB_queuing_rw_mutex_H
0018 #define __TBB_queuing_rw_mutex_H
0019 
0020 #define __TBB_queuing_rw_mutex_H_include_area
0021 #include "internal/_warning_suppress_enable_notice.h"
0022 
0023 #include <cstring>
0024 #include "atomic.h"
0025 #include "tbb_profiling.h"
0026 
0027 namespace tbb {
0028 
0029 //! Queuing reader-writer mutex with local-only spinning.
0030 /** Adapted from Krieger, Stumm, et al. pseudocode at
0031     http://www.eecg.toronto.edu/parallel/pubs_abs.html#Krieger_etal_ICPP93
0032     @ingroup synchronization */
0033 class queuing_rw_mutex : internal::mutex_copy_deprecated_and_disabled {
0034 public:
0035     //! Construct unacquired mutex.
0036     queuing_rw_mutex() {
0037         q_tail = NULL;
0038 #if TBB_USE_THREADING_TOOLS
0039         internal_construct();
0040 #endif
0041     }
0042 
0043     //! Destructor asserts if the mutex is acquired, i.e. q_tail is non-NULL
0044     ~queuing_rw_mutex() {
0045 #if TBB_USE_ASSERT
0046         __TBB_ASSERT( !q_tail, "destruction of an acquired mutex");
0047 #endif
0048     }
0049 
0050     //! The scoped locking pattern
0051     /** It helps to avoid the common problem of forgetting to release lock.
0052         It also nicely provides the "node" for queuing locks. */
0053     class scoped_lock: internal::no_copy {
0054         //! Initialize fields to mean "no lock held".
0055         void initialize() {
0056             my_mutex = NULL;
0057             my_internal_lock = 0;
0058             my_going = 0;
0059 #if TBB_USE_ASSERT
0060             my_state = 0xFF; // Set to invalid state
0061             internal::poison_pointer(my_next);
0062             internal::poison_pointer(my_prev);
0063 #endif /* TBB_USE_ASSERT */
0064         }
0065 
0066     public:
0067         //! Construct lock that has not acquired a mutex.
0068         /** Equivalent to zero-initialization of *this. */
0069         scoped_lock() {initialize();}
0070 
0071         //! Acquire lock on given mutex.
0072         scoped_lock( queuing_rw_mutex& m, bool write=true ) {
0073             initialize();
0074             acquire(m,write);
0075         }
0076 
0077         //! Release lock (if lock is held).
0078         ~scoped_lock() {
0079             if( my_mutex ) release();
0080         }
0081 
0082         //! Acquire lock on given mutex.
0083         void acquire( queuing_rw_mutex& m, bool write=true );
0084 
0085         //! Acquire lock on given mutex if free (i.e. non-blocking)
0086         bool try_acquire( queuing_rw_mutex& m, bool write=true );
0087 
0088         //! Release lock.
0089         void release();
0090 
0091         //! Upgrade reader to become a writer.
0092         /** Returns whether the upgrade happened without releasing and re-acquiring the lock */
0093         bool upgrade_to_writer();
0094 
0095         //! Downgrade writer to become a reader.
0096         bool downgrade_to_reader();
0097 
0098     private:
0099         //! The pointer to the mutex owned, or NULL if not holding a mutex.
0100         queuing_rw_mutex* my_mutex;
0101 
0102         //! The pointer to the previous and next competitors for a mutex
0103         scoped_lock *__TBB_atomic my_prev, *__TBB_atomic my_next;
0104 
0105         typedef unsigned char state_t;
0106 
0107         //! State of the request: reader, writer, active reader, other service states
0108         atomic<state_t> my_state;
0109 
0110         //! The local spin-wait variable
0111         /** Corresponds to "spin" in the pseudocode but inverted for the sake of zero-initialization */
0112         unsigned char __TBB_atomic my_going;
0113 
0114         //! A tiny internal lock
0115         unsigned char my_internal_lock;
0116 
0117         //! Acquire the internal lock
0118         void acquire_internal_lock();
0119 
0120         //! Try to acquire the internal lock
0121         /** Returns true if lock was successfully acquired. */
0122         bool try_acquire_internal_lock();
0123 
0124         //! Release the internal lock
0125         void release_internal_lock();
0126 
0127         //! Wait for internal lock to be released
0128         void wait_for_release_of_internal_lock();
0129 
0130         //! A helper function
0131         void unblock_or_wait_on_internal_lock( uintptr_t );
0132     };
0133 
0134     void __TBB_EXPORTED_METHOD internal_construct();
0135 
0136     // Mutex traits
0137     static const bool is_rw_mutex = true;
0138     static const bool is_recursive_mutex = false;
0139     static const bool is_fair_mutex = true;
0140 
0141 private:
0142     //! The last competitor requesting the lock
0143     atomic<scoped_lock*> q_tail;
0144 
0145 };
0146 
0147 __TBB_DEFINE_PROFILING_SET_NAME(queuing_rw_mutex)
0148 
0149 } // namespace tbb
0150 
0151 #include "internal/_warning_suppress_disable_notice.h"
0152 #undef __TBB_queuing_rw_mutex_H_include_area
0153 
0154 #endif /* __TBB_queuing_rw_mutex_H */