| 101 | } |
| 102 | |
| 103 | static inline int rwlock_unrdlock(bthread_rwlock_t* rwlock) { |
| 104 | int reader_count = ((butil::atomic<int>*)&rwlock->reader_count) |
| 105 | ->fetch_add(-1, butil::memory_order_relaxed) - 1; |
| 106 | // Fast path. |
| 107 | if (reader_count >= 0) { |
| 108 | return 0; |
| 109 | } |
| 110 | // Slow path. |
| 111 | |
| 112 | if (BAIDU_UNLIKELY(reader_count + 1 == 0 || reader_count + 1 == -RWLockMaxReaders)) { |
| 113 | CHECK(false) << "rwlock_unrdlock of unlocked rwlock"; |
| 114 | return EINVAL; |
| 115 | } |
| 116 | |
| 117 | // A writer is pending. |
| 118 | int reader_wait = ((butil::atomic<int>*)&rwlock->reader_wait) |
| 119 | ->fetch_add(-1, butil::memory_order_relaxed) - 1; |
| 120 | if (reader_wait != 0) { |
| 121 | return 0; |
| 122 | } |
| 123 | |
| 124 | // The last reader unblocks the writer. |
| 125 | |
| 126 | if (NULL == bthread::g_cp) { |
| 127 | bthread_sem_post(&rwlock->writer_sema); |
| 128 | return 0; |
| 129 | } |
| 130 | // Ask Collector if this (contended) locking should be sampled. |
| 131 | const size_t sampling_range = bvar::is_collectable(&bthread::g_cp_sl); |
| 132 | if (!sampling_range) { // Don't sample |
| 133 | bthread_sem_post(&rwlock->writer_sema); |
| 134 | return 0; |
| 135 | } |
| 136 | |
| 137 | // Sampling. |
| 138 | const int64_t start_ns = butil::cpuwide_time_ns(); |
| 139 | bthread_sem_post(&rwlock->writer_sema); |
| 140 | const int64_t end_ns = butil::cpuwide_time_ns(); |
| 141 | const bthread_contention_site_t csite{end_ns - start_ns, sampling_range}; |
| 142 | // Submit `csite' for each reader immediately after |
| 143 | // releasing rdlock to avoid the contention of `csite'. |
| 144 | bthread::submit_contention(csite, end_ns); |
| 145 | return 0; |
| 146 | } |
| 147 | |
| 148 | #define DO_CSITE_IF_NEED \ |
| 149 | do { \ |
no test coverage detected