47 #ifdef NCBI_POSIX_THREADS
48 # include <sys/time.h>
52 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
56 # if defined(NCBI_OS_MSWIN)
66 #define STACK_THRESHOLD (1024)
68 #define NCBI_USE_ERRCODE_X Corelib_Mutex
84 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
88 static void s_WriteMutexEvent(
void* mutex_ptr,
const char* message);
89 # define WRITE_MUTEX_EVENT(mutex, message) s_WriteMutexEvent(mutex, message)
93 # define WRITE_MUTEX_EVENT(mutex, message) ((void)0)
99 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
101 void s_WriteMutexEvent(
void* mutex_ptr,
const char* message)
103 static const int mode = O_WRONLY | O_APPEND | O_CREAT;
109 static const char*
file_name = getenv(
"MUTEX_EVENTS_LOG_FILE");
122 str_os << mutex_ptr <<
" "
125 write(handle, str_os.str(), str_os.pcount());
126 str_os.rdbuf()->freeze(
false);
136 void SSystemFastMutex::InitializeHandle(
void)
141 #if defined(NCBI_WIN32_THREADS)
142 # if defined(NCBI_FASTMUTEX_USE_NEW)
143 InitializeSRWLock(&m_Handle);
144 # elif defined(NCBI_USE_CRITICAL_SECTION)
145 InitializeCriticalSection(&m_Handle);
149 "Mutex creation failed");
151 #elif defined(NCBI_POSIX_THREADS)
152 # if defined(NCBI_OS_CYGWIN)
153 if (pthread_mutex_init(&m_Handle, 0) != 0) {
158 memset(&m_Handle, 0,
sizeof(m_Handle));
161 "Mutex creation failed");
162 # if defined(NCBI_OS_CYGWIN)
168 void SSystemFastMutex::DestroyHandle(
void)
173 #if defined(NCBI_WIN32_THREADS)
174 # if defined(NCBI_FASTMUTEX_USE_NEW)
176 # elif defined(NCBI_USE_CRITICAL_SECTION)
177 DeleteCriticalSection(&m_Handle);
181 #elif defined(NCBI_POSIX_THREADS)
186 void SSystemFastMutex::InitializeStatic(
void)
188 #if !defined(NCBI_NO_THREADS)
190 case eMutexUninitialized:
192 case eMutexInitialized:
196 xncbi_Validate(0,
"SSystemFastMutex::m_Magic contains invalid value");
203 m_Magic = eMutexInitialized;
207 void SSystemFastMutex::InitializeDynamic(
void)
209 #if !defined(NCBI_NO_THREADS)
213 m_Magic = eMutexInitialized;
217 void SSystemFastMutex::Destroy(
void)
219 #if !defined(NCBI_NO_THREADS)
220 xncbi_Validate(IsInitialized(),
"Destruction of uninitialized mutex");
223 m_Magic = eMutexUninitialized;
228 void SSystemFastMutex::ThrowUninitialized(
void)
233 void SSystemFastMutex::ThrowLockFailed(
void)
238 void SSystemFastMutex::ThrowUnlockFailed(
void)
243 void SSystemFastMutex::ThrowTryLockFailed(
void)
246 "Mutex check (TryLock) failed");
249 void SSystemMutex::Destroy(
void)
255 #if !defined(NCBI_NO_THREADS)
262 if (lock != eNormal) {
267 # if defined(NCBI_WIN32_THREADS)
268 # if defined(NCBI_FASTMUTEX_USE_NEW)
269 AcquireSRWLockExclusive(&m_Handle);
270 # elif defined(NCBI_USE_CRITICAL_SECTION)
271 EnterCriticalSection(&m_Handle);
273 if (WaitForSingleObject(m_Handle, INFINITE) != WAIT_OBJECT_0) {
277 # elif defined(NCBI_POSIX_THREADS)
278 if ( pthread_mutex_lock(&m_Handle) != 0 ) {
284 bool SSystemFastMutex::TryLock(
void)
293 # if defined(NCBI_WIN32_THREADS)
294 # if defined(NCBI_FASTMUTEX_USE_NEW)
295 return TryAcquireSRWLockExclusive(&m_Handle) != 0;
296 # elif defined(NCBI_USE_CRITICAL_SECTION)
297 return TryEnterCriticalSection(&m_Handle) != 0;
299 DWORD status = WaitForSingleObject(m_Handle, 0);
300 if (status == WAIT_OBJECT_0) {
304 if (status != WAIT_TIMEOUT) {
305 ThrowTryLockFailed();
310 # elif defined(NCBI_POSIX_THREADS)
311 int status = pthread_mutex_trylock(&m_Handle);
316 if (status != EBUSY) {
317 ThrowTryLockFailed();
330 if (lock != eNormal) {
335 # if defined(NCBI_WIN32_THREADS)
336 # if defined(NCBI_FASTMUTEX_USE_NEW)
337 ReleaseSRWLockExclusive(&m_Handle);
338 # elif defined(NCBI_USE_CRITICAL_SECTION)
339 LeaveCriticalSection(&m_Handle);
341 if ( !ReleaseMutex(m_Handle) ) {
345 # elif defined(NCBI_POSIX_THREADS)
346 if ( pthread_mutex_unlock(&m_Handle) != 0 ) {
354 m_Mutex.CheckInitialized();
357 auto count = m_Count.load(memory_order_acquire);
358 if (
count > 0 && m_Owner.load(memory_order_relaxed) == owner ) {
360 m_Count.store(++
count, memory_order_release);
367 m_Owner.store(owner, memory_order_relaxed);
368 m_Count.store(1, memory_order_release);
371 bool SSystemMutex::TryLock(
void)
373 m_Mutex.CheckInitialized();
376 auto count = m_Count.load(memory_order_acquire);
377 if (
count > 0 && m_Owner.load(memory_order_relaxed) == owner ) {
379 m_Count.store(++
count, memory_order_release);
384 if ( m_Mutex.TryLock() ) {
385 assert(m_Count.load(memory_order_relaxed) == 0);
386 m_Owner.store(owner, memory_order_relaxed);
387 m_Count.store(1, memory_order_release);
397 m_Mutex.CheckInitialized();
402 auto count = m_Count.load(memory_order_acquire);
403 if (
count == 0 || m_Owner.load(memory_order_relaxed) != owner ) {
408 m_Count.store(--
count, memory_order_release);
414 m_Mutex.Unlock(lock);
418 void SSystemMutex::ThrowNotOwned(
void)
421 "Mutex is not owned by current thread");
425 #if defined(NEED_AUTO_INITIALIZE_MUTEX)
428 static const char* kInitMutexName =
"NCBI_CAutoInitializeStaticMutex";
430 #ifdef USE_STATIC_INIT_MUTEX_HANDLE
437 init_mutex = CreateMutex(
NULL,
FALSE, kInitMutexName);
439 assert(!s_InitMutexHandle || s_InitMutexHandle == init_mutex);
440 s_InitMutexHandle = init_mutex;
447 assert(mutex == s_InitMutexHandle);
452 static inline HANDLE s_GetInitMutexHandle(
void)
459 static inline void s_ReleaseInitMutexHandle(
HANDLE mutex)
466 void CAutoInitializeStaticFastMutex::Initialize(
void)
468 if ( m_Mutex.IsInitialized() ) {
471 HANDLE init_mutex = s_GetInitMutexHandle();
473 WaitForSingleObject(init_mutex, INFINITE) == WAIT_OBJECT_0);
474 if ( !m_Mutex.IsInitialized() ) {
475 m_Mutex.InitializeStatic();
478 assert(m_Mutex.IsInitialized());
479 s_ReleaseInitMutexHandle(init_mutex);
482 void CAutoInitializeStaticMutex::Initialize(
void)
484 if ( m_Mutex.IsInitialized() ) {
487 HANDLE init_mutex = s_GetInitMutexHandle();
489 WaitForSingleObject(init_mutex, INFINITE) == WAIT_OBJECT_0);
490 if ( !m_Mutex.IsInitialized() ) {
491 m_Mutex.InitializeStatic();
494 assert(m_Mutex.IsInitialized());
495 s_ReleaseInitMutexHandle(init_mutex);
503 case eLock:
return "eLock";
504 case eUnlock:
return "eUnlock";
506 case eOwner:
return "eOwner";
516 #if defined(NCBI_WIN32_THREADS) && !NCBI_SRWLOCK_USE_NEW
521 CWindowsHandle(
HANDLE h =
NULL) : m_Handle(h) {}
522 CWindowsHandle(
HANDLE h,
const char* errorMessage) : m_Handle(h)
526 ~CWindowsHandle(
void) { Close(); }
530 if ( m_Handle !=
NULL ) {
531 CloseHandle(m_Handle);
541 void Set(
HANDLE h,
const char* errorMessage)
547 HANDLE GetHandle(
void)
const {
return m_Handle; }
548 operator HANDLE(
void)
const {
return m_Handle; }
554 CWindowsHandle(
const CWindowsHandle& h);
555 CWindowsHandle& operator=(
const CWindowsHandle& h);
558 class CWindowsSemaphore :
public CWindowsHandle
561 CWindowsSemaphore(LONG initialCount = 0, LONG maximumCount = INFINITE)
562 : CWindowsHandle(CreateSemaphore(
NULL,
563 initialCount, maximumCount,
565 "CreateSemaphore() failed")
569 LONG Release(LONG add = 1)
573 "CWindowsSemaphore::Release() failed");
580 #if defined(NCBI_POSIX_THREADS)
596 operator pthread_cond_t*(void) {
return &
m_Handle; }
597 operator pthread_cond_t&(void) {
return m_Handle; }
606 #if !NCBI_SRWLOCK_USE_NEW
613 #if defined(NCBI_WIN32_THREADS)
614 CWindowsSemaphore m_Rsema;
615 CWindowsSemaphore m_Rsema2;
616 CWindowsSemaphore m_Wsema;
617 # if defined(NCBI_USE_CRITICAL_SECTION)
622 #elif defined(NCBI_POSIX_THREADS)
631 #if defined(NCBI_WIN32_THREADS)
632 : m_Rsema(1, 1), m_Rsema2(1, 1), m_Wsema(1, 1)
635 #if defined(NCBI_USE_CRITICAL_SECTION)
644 #if NCBI_SRWLOCK_USE_NEW
646 : m_Owner(0), m_Count(0), m_WaitingWriters(0), m_TrackReaders(
false)
649 m_TrackReaders =
true;
650 m_FavorWriters = (
flags & fFavorWriters) != 0;
652 m_TrackReaders = m_FavorWriters = (
flags & fFavorWriters) != 0;
654 if (m_TrackReaders) {
655 m_Readers.reserve(16);
685 #if NCBI_SRWLOCK_USE_NEW
687 vector<TThreadSystemID>::const_iterator
707 bool CRWLock::x_TryWriteLock()
714 bool CRWLock::x_TryReadLock()
743 #if defined(NCBI_USE_CRITICAL_SECTION) && !NCBI_SRWLOCK_USE_NEW
746 class CWin32MutexHandleGuard
749 CWin32MutexHandleGuard(
HANDLE mutex);
750 ~CWin32MutexHandleGuard(
void);
757 CWin32MutexHandleGuard::CWin32MutexHandleGuard(
HANDLE mutex)
760 WaitForSingleObject(m_Handle, INFINITE);
765 CWin32MutexHandleGuard::~CWin32MutexHandleGuard(
void)
767 ReleaseMutex(m_Handle);
778 #if defined(NCBI_WIN32_THREADS)
779 for (
long old_val = *
val; ; old_val = *
val) {
780 long cur_val = InterlockedCompareExchange(
val, new_val, old_val);
781 if (cur_val == old_val) {
793 #if defined(NCBI_WIN32_THREADS)
794 for (
long old_val = *
val; old_val >
min; old_val = *
val) {
795 long new_val = old_val + 1;
796 long cur_val = InterlockedCompareExchange(
val, new_val, old_val);
797 if (cur_val == old_val) {
811 #if defined(NCBI_WIN32_THREADS)
812 for (
long old_val = *
val; old_val <
max; old_val = *
val) {
813 long new_val = old_val + 1;
814 long cur_val = InterlockedCompareExchange(
val, new_val, old_val);
815 if (cur_val == old_val) {
829 #if defined(NCBI_WIN32_THREADS)
830 for (
long old_val = *
val; old_val <
max; old_val = *
val) {
831 long new_val = old_val - 1;
832 long cur_val = InterlockedCompareExchange(
val, new_val, old_val);
833 if (cur_val == old_val) {
847 #if defined(NCBI_WIN32_THREADS)
848 for (
long old_val = *
val; old_val >
min; old_val = *
val) {
849 long new_val = old_val - 1;
850 long cur_val = InterlockedCompareExchange(
val, new_val, old_val);
851 if (cur_val == old_val) {
865 #if defined(NCBI_NO_THREADS)
869 #if NCBI_SRWLOCK_USE_NEW
874 if (!m_TrackReaders && x_TryReadLock()) {
877 unique_lock<mutex> lck( m_Mtx);
884 }
while (!x_TryReadLock());
885 if (m_TrackReaders) {
891 #if defined(NCBI_WIN32_THREADS)
902 #if defined(NCBI_USE_CRITICAL_SECTION)
903 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
913 #if defined(NCBI_WIN32_THREADS)
915 obj[0] =
m_RW->m_Mutex.GetHandle();
916 obj[1] =
m_RW->m_Rsema;
917 obj[2] =
m_RW->m_Rsema2;
919 ReleaseMutex(
m_RW->m_Mutex.GetHandle()),
920 "CRWLock::ReadLock() - release mutex error");
922 WaitForMultipleObjects(3, obj,
TRUE, INFINITE)-WAIT_OBJECT_0;
924 "CRWLock::ReadLock() - R-lock waiting error");
927 &&
m_RW->m_Rsema2.Release() == 0,
928 "CRWLock::ReadLock() - invalid R-semaphore state");
932 "CRWLock::ReadLock() - "
933 "failed to lock W-semaphore");
935 #elif defined(NCBI_POSIX_THREADS)
938 pthread_cond_wait(
m_RW->m_Rcond,
939 m_RW->m_Mutex.GetHandle()), 0,
940 "CRWLock::ReadLock() - R-lock waiting error");
945 "CRWLock::ReadLock() - "
946 "weird R-lock error in non-MT mode");
949 "CRWLock::ReadLock() - invalid readers counter");
954 #if defined(NCBI_WIN32_THREADS)
960 "CRWLock::ReadLock() - "
961 "can not lock W-semaphore");
978 #if defined(NCBI_NO_THREADS)
982 #if NCBI_SRWLOCK_USE_NEW
987 if (!m_TrackReaders && x_TryReadLock()) {
990 unique_lock<mutex> lck( m_Mtx);
994 if (!x_TryReadLock()) {
997 if (m_TrackReaders) {
1004 #if defined(NCBI_WIN32_THREADS)
1012 #if defined(NCBI_USE_CRITICAL_SECTION)
1013 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1031 #if defined(NCBI_WIN32_THREADS)
1036 "CRWLock::TryReadLock() - "
1037 "can not lock W-semaphore");
1052 #if defined(NCBI_NO_THREADS)
1060 if ( timeout.
IsZero() ) {
1064 #if NCBI_SRWLOCK_USE_NEW
1069 if (!m_TrackReaders && x_TryReadLock()) {
1072 unsigned int sec=0, nanosec=0;
1073 timeout.
GetNano(&sec, &nanosec);
1074 chrono::time_point<chrono::steady_clock> to = chrono::steady_clock::now() + chrono::seconds(sec) + chrono::nanoseconds(nanosec);
1075 cv_status res = cv_status::no_timeout;
1078 unique_lock<mutex> lck( m_Mtx);
1080 if (res == cv_status::timeout) {
1085 res = m_Cv.wait_until(lck, to);
1091 }
while (!x_TryReadLock());
1092 if (m_TrackReaders) {
1099 #if defined(NCBI_WIN32_THREADS)
1110 #if defined(NCBI_USE_CRITICAL_SECTION)
1111 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1121 #if defined(NCBI_WIN32_THREADS)
1123 obj[0] =
m_RW->m_Mutex.GetHandle();
1124 obj[1] =
m_RW->m_Rsema;
1125 obj[2] =
m_RW->m_Rsema2;
1127 ReleaseMutex(
m_RW->m_Mutex.GetHandle()),
1128 "CRWLock::TryReadLock() - release mutex error");
1131 WaitForMultipleObjects(3, obj,
TRUE, timeout_msec);
1132 if (wait_res == WAIT_TIMEOUT) {
1135 wait_res -= WAIT_OBJECT_0;
1137 "CRWLock::TryReadLock() - R-lock waiting error");
1140 &&
m_RW->m_Rsema2.Release() == 0,
1141 "CRWLock::TryReadLock() - invalid R-semaphore state");
1144 0) == WAIT_OBJECT_0,
1145 "CRWLock::TryReadLock() - "
1146 "failed to lock W-semaphore");
1148 #elif defined(NCBI_POSIX_THREADS)
1158 res = pthread_cond_timedwait(
m_RW->m_Rcond,
1159 m_RW->m_Mutex.GetHandle(), &ts);
1161 if (res == ETIMEDOUT) {
1165 "CRWLock::TryReadLock() - R-lock waiting error");
1169 "CRWLock::TryReadLock() - "
1170 "weird R-lock error in non-MT mode");
1173 "CRWLock::TryReadLock() - invalid readers counter");
1178 #if defined(NCBI_WIN32_THREADS)
1184 "CRWLock::TryReadLock() - "
1185 "can not lock W-semaphore");
1203 #if defined(NCBI_NO_THREADS)
1207 #if NCBI_SRWLOCK_USE_NEW
1212 if (x_TryWriteLock()) {
1216 unique_lock<mutex> lck( m_Mtx);
1217 _ASSERT(!m_TrackReaders || !x_HasReader(self_id));
1218 if (m_FavorWriters) {
1221 while (!x_TryWriteLock()) {
1225 if (m_FavorWriters) {
1233 #if defined(NCBI_USE_CRITICAL_SECTION)
1234 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1248 "CRWLock::WriteLock() - "
1249 "attempt to set W-after-R lock");
1251 #if defined(NCBI_WIN32_THREADS)
1253 obj[0] =
m_RW->m_Rsema;
1254 obj[1] =
m_RW->m_Wsema;
1255 obj[2] =
m_RW->m_Mutex.GetHandle();
1259 WaitForMultipleObjects(2, obj,
TRUE, 0)-WAIT_OBJECT_0;
1261 "CRWLock::WriteLock() - "
1262 "error locking R&W-semaphores");
1271 "CRWLock::WriteLock() - "
1272 "error locking R-semaphore 2");
1276 ReleaseMutex(
m_RW->m_Mutex.GetHandle()),
1277 "CRWLock::WriteLock() - release mutex error");
1279 WaitForMultipleObjects(3, obj,
TRUE, INFINITE)-WAIT_OBJECT_0;
1281 "CRWLock::WriteLock() - "
1282 "error locking R&W-semaphores");
1286 "CRWLock::WriteLock() - "
1287 "invalid R-semaphore 2 state");
1293 #elif defined(NCBI_POSIX_THREADS)
1299 pthread_cond_wait(
m_RW->m_Wcond,
1300 m_RW->m_Mutex.GetHandle()), 0,
1301 "CRWLock::WriteLock() - error locking R&W-conditionals");
1308 "CRWLock::WriteLock() - invalid readers counter");
1322 #if defined(NCBI_NO_THREADS)
1326 #if NCBI_SRWLOCK_USE_NEW
1331 if (!x_TryWriteLock()) {
1341 #if defined(NCBI_USE_CRITICAL_SECTION)
1342 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1362 #if defined(NCBI_WIN32_THREADS)
1365 obj[0] =
m_RW->m_Rsema;
1366 obj[1] =
m_RW->m_Wsema;
1368 WaitForMultipleObjects(2, obj,
TRUE, 0) - WAIT_OBJECT_0;
1370 "CRWLock::TryWriteLock() - "
1371 "error locking R&W-semaphores");
1388 #if defined(NCBI_NO_THREADS)
1396 if ( timeout.
IsZero() ) {
1400 #if NCBI_SRWLOCK_USE_NEW
1405 if (x_TryWriteLock()) {
1409 unsigned int sec=0, nanosec=0;
1410 timeout.
GetNano(&sec, &nanosec);
1411 chrono::time_point<chrono::steady_clock> to = chrono::steady_clock::now() + chrono::seconds(sec) + chrono::nanoseconds(nanosec);
1412 cv_status res = cv_status::no_timeout;
1415 unique_lock<mutex> lck( m_Mtx);
1417 if (res == cv_status::timeout) {
1420 if (m_FavorWriters) {
1423 while (!(
ok =
m_Count == 0) && res == cv_status::no_timeout) {
1424 res = m_Cv.wait_until(lck, to);
1426 if (m_FavorWriters) {
1432 }
while (!x_TryWriteLock());
1439 #if defined(NCBI_USE_CRITICAL_SECTION)
1440 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1454 "CRWLock::TryWriteLock() - "
1455 "attempt to set W-after-R lock");
1457 #if defined(NCBI_WIN32_THREADS)
1459 obj[0] =
m_RW->m_Rsema;
1460 obj[1] =
m_RW->m_Wsema;
1461 obj[2] =
m_RW->m_Mutex.GetHandle();
1465 WaitForMultipleObjects(2, obj,
TRUE, 0)-WAIT_OBJECT_0;
1467 "CRWLock::TryWriteLock() - "
1468 "error locking R&W-semaphores");
1477 "CRWLock::TryWriteLock() - "
1478 "error locking R-semaphore 2");
1482 ReleaseMutex(
m_RW->m_Mutex.GetHandle()),
1483 "CRWLock::TryWriteLock() - release mutex error");
1486 WaitForMultipleObjects(3, obj,
TRUE, timeout_msec);
1487 if (wait_res == WAIT_TIMEOUT) {
1490 CWin32MutexHandleGuard counter_guard(
m_RW->m_Mutex);
1493 "CRWLock::TryWriteLock() - "
1494 "invalid R-semaphore 2 state");
1501 wait_res -= WAIT_OBJECT_0;
1503 "CRWLock::TryWriteLock() - "
1504 "error locking R&W-semaphores");
1508 "CRWLock::TryWriteLock() - "
1509 "invalid R-semaphore 2 state");
1515 #elif defined(NCBI_POSIX_THREADS)
1527 while (
m_Count != 0 && res != ETIMEDOUT ) {
1528 res = pthread_cond_timedwait(
m_RW->m_Wcond,
1529 m_RW->m_Mutex.GetHandle(), &ts);
1531 if (res == ETIMEDOUT) {
1538 "CRWLock::TryWriteLock() - "
1539 "error locking R&W-conditionals");
1545 "CRWLock::TryWriteLock() - invalid readers counter");
1560 #if defined(NCBI_NO_THREADS)
1564 #if NCBI_SRWLOCK_USE_NEW
1570 unique_lock<mutex> lck( m_Mtx);
1577 if (m_TrackReaders) {
1579 m_Readers.erase( x_FindReader(self_id) );
1580 }
else if (
cnt != 0) {
1587 #if defined(NCBI_WIN32_THREADS)
1595 #if defined(NCBI_USE_CRITICAL_SECTION)
1596 CWin32MutexHandleGuard guard(
m_RW->m_Mutex);
1604 "CRWLock::Unlock() - "
1605 "RWLock is locked by another thread");
1609 #if defined(NCBI_WIN32_THREADS)
1611 "CRWLock::Unlock() - invalid R-semaphore state");
1613 "CRWLock::Unlock() - invalid R-semaphore state");
1614 #elif defined(NCBI_POSIX_THREADS)
1617 pthread_cond_broadcast(
m_RW->m_Rcond), 0,
1618 "CRWLock::Unlock() - error signalling unlock");
1621 pthread_cond_signal(
m_RW->m_Wcond), 0,
1622 "CRWLock::Unlock() - error signalling unlock");
1633 "CRWLock::Unlock() - RWLock is not locked");
1637 #if defined(NCBI_WIN32_THREADS)
1639 "CRWLock::Unlock() - invalid W-semaphore state");
1640 #elif defined(NCBI_POSIX_THREADS)
1642 pthread_cond_signal(
m_RW->m_Wcond), 0,
1643 "CRWLock::Unlock() - error signaling unlock");
1648 vector<TThreadSystemID>::iterator found =
1672 #if defined(NCBI_POSIX_THREADS)
1679 #elif defined(NCBI_WIN32_THREADS)
1688 #if NCBI_SEMAPHORE_USE_NEW
1690 : m_Max(max_count), m_Count(init_count)
1698 #if defined(NCBI_WIN32_THREADS)
1700 max_count =
min(max_count, (
unsigned int)LONG_MAX);
1703 "CSemaphore::CSemaphore() - max_count passed zero");
1705 "CSemaphore::CSemaphore() - init_count "
1706 "greater than max_count");
1709 unique_ptr<SSemaphore> auto_sem(
m_Sem);
1711 #if defined(NCBI_POSIX_THREADS)
1716 # if defined(NCBI_OS_CYGWIN)
1717 if (pthread_mutex_init(&
m_Sem->
mutex, 0) != 0) {
1722 "CSemaphore::CSemaphore() - pthread_mutex_init() failed");
1723 # if defined(NCBI_OS_CYGWIN)
1727 # if defined(NCBI_OS_CYGWIN)
1728 if (pthread_cond_init(&
m_Sem->
cond, 0) != 0) {
1733 "CSemaphore::CSemaphore() - pthread_cond_init() failed");
1734 # if defined(NCBI_OS_CYGWIN)
1738 #elif defined(NCBI_WIN32_THREADS)
1739 m_Sem->sem = CreateSemaphore(
NULL, init_count, max_count,
NULL);
1742 DWORD dwErr = GetLastError();
1747 "CSemaphore::CSemaphore() - CreateSemaphore() failed");
1760 #if NCBI_SEMAPHORE_USE_NEW
1762 #if defined(NCBI_POSIX_THREADS)
1767 #elif defined(NCBI_WIN32_THREADS)
1775 #if NCBI_SEMAPHORE_USE_NEW
1777 bool CSemaphore::x_TryAcquire(
void)
1789 #if NCBI_SEMAPHORE_USE_NEW
1790 unique_lock<mutex> lck(m_Mtx);
1791 while (!x_TryAcquire()) {
1795 #if defined(NCBI_POSIX_THREADS)
1798 "CSemaphore::Wait() - pthread_mutex_lock() failed");
1807 if (status != 0 && status != EINTR) {
1810 "CSemaphore::Wait() - pthread_cond_wait() and "
1811 "pthread_mutex_unlock() failed");
1813 "CSemaphore::Wait() - "
1814 "pthread_cond_wait() failed");
1823 "CSemaphore::Wait() - pthread_mutex_unlock() failed");
1825 #elif defined(NCBI_WIN32_THREADS)
1827 "CSemaphore::Wait() - WaitForSingleObject() failed");
1831 "CSemaphore::Wait() - "
1832 "wait with zero count in one-thread mode(?!)");
1838 #if defined(NCBI_NO_THREADS)
1839 # define NCBI_THREADS_ARG(arg)
1841 # define NCBI_THREADS_ARG(arg) arg
1847 #if NCBI_SEMAPHORE_USE_NEW
1848 unique_lock<mutex> lck(m_Mtx);
1849 #if defined(NCBI_NO_THREADS)
1850 return x_TryAcquire();
1852 if (x_TryAcquire()) {
1855 if (timeout_sec == 0 && timeout_nsec == 0) {
1856 return x_TryAcquire();
1858 chrono::time_point<chrono::steady_clock> to = chrono::steady_clock::now() + chrono::seconds(timeout_sec) + chrono::nanoseconds(timeout_nsec);
1859 cv_status res = cv_status::no_timeout;
1860 while (!x_TryAcquire()) {
1861 res = m_Cv.wait_until(lck, to);
1862 if (res == cv_status::timeout) {
1869 #if defined(NCBI_POSIX_THREADS)
1872 "CSemaphore::TryWait() - pthread_mutex_lock() failed");
1874 bool retval =
false;
1879 else if (timeout_sec > 0 || timeout_nsec > 0) {
1880 # ifdef NCBI_OS_SOLARIS
1883 if (timeout_sec >= 100 * 1000 * 1000) {
1884 timeout_sec = 100 * 1000 * 1000;
1888 static const unsigned int kBillion = 1000 * 1000 * 1000;
1890 struct timespec timeout = { 0, 0 };
1891 gettimeofday(&now, 0);
1893 timeout.tv_sec = now.tv_sec;
1894 timeout.tv_nsec = now.tv_usec * 1000 + timeout_nsec;
1895 if ((
unsigned int)timeout.tv_nsec >= kBillion) {
1896 timeout.tv_sec += timeout.tv_nsec / kBillion;
1897 timeout.tv_nsec %= kBillion;
1899 if (timeout_sec > (
unsigned int)(
kMax_Int - timeout.tv_sec)) {
1902 timeout.tv_nsec = kBillion - 1;
1904 timeout.tv_sec += timeout_sec;
1911 if (status == ETIMEDOUT) {
1913 }
else if (status != 0 && status != EINTR) {
1917 "CSemaphore::TryWait() - pthread_cond_timedwait() and "
1918 "pthread_mutex_unlock() failed");
1920 "pthread_cond_timedwait() failed");
1932 "CSemaphore::TryWait() - pthread_mutex_unlock() failed");
1936 #elif defined(NCBI_WIN32_THREADS)
1938 if (timeout_sec >= kMax_ULong / 1000) {
1939 timeout_msec = kMax_ULong;
1941 timeout_msec = timeout_sec * 1000 + timeout_nsec / (1000 * 1000);
1943 DWORD res = WaitForSingleObject(
m_Sem->sem, timeout_msec);
1945 "CSemaphore::TryWait() - WaitForSingleObject() failed");
1946 return (res == WAIT_OBJECT_0);
1976 #if NCBI_SEMAPHORE_USE_NEW
1977 unique_lock<mutex> lck( m_Mtx);
1979 "CSemaphore::Post() - attempt to exceed max_count");
1983 #if defined (NCBI_POSIX_THREADS)
1986 "CSemaphore::Post() - pthread_mutex_lock() failed");
1992 "CSemaphore::Post() - attempt to exceed max_count and "
1993 "pthread_mutex_unlock() failed");
1995 "CSemaphore::Post() - attempt to exceed max_count");
2001 err_code = pthread_cond_broadcast(&
m_Sem->
cond);
2005 for (
unsigned int n_sig = 0; n_sig <
count; n_sig++) {
2006 err_code = pthread_cond_signal(&
m_Sem->
cond);
2007 if (err_code != 0) {
2008 err_code = pthread_cond_broadcast(&
m_Sem->
cond);
2015 if (err_code == 0) {
2019 "CSemaphore::Post() - pthread_mutex_unlock() failed");
2026 "CSemaphore::Post() - pthread_cond_signal/broadcast() and "
2027 "pthread_mutex_unlock() failed");
2029 "CSemaphore::Post() - "
2030 "pthread_cond_signal/broadcast() failed");
2032 #elif defined(NCBI_WIN32_THREADS)
2035 "CSemaphore::Post() - ReleaseSemaphore() failed");
2039 "CSemaphore::Post() - attempt to exceed max_count");
2050 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2051 AcquireSRWLockShared(&m_Lock);
2064 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2065 ReleaseSRWLockShared(&m_Lock);
2074 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2075 AcquireSRWLockExclusive(&m_Lock);
2088 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2089 ReleaseSRWLockExclusive(&m_Lock);
2129 lstn->OnLockAcquired(
this);
2146 lstn->OnLockReleased(
this);
2190 holder->
Init(lock, typ);
2209 : m_Factory(factory)
2220 # define RWLockFatal Fatal
2222 # define RWLockFatal Critical
2229 <<
"Destroying YieldingRWLock with unreleased locks");
2233 <<
"Destroying YieldingRWLock with "
2234 "some locks waiting to acquire");
2243 int other_type = 1 - lock_type;
2257 holder->m_LockAcquired =
true;
2260 holder->x_OnLockAcquired();
2278 if (save_acquired) {
2288 first_next->m_LockAcquired =
true;
2293 if (next_hldr->m_Type != next_type)
2296 next_hldr->m_LockAcquired =
true;
2298 next_holders.push_back(next_hldr);
2304 THoldersList::iterator it
2312 if (save_acquired) {
2316 first_next->x_OnLockAcquired();
2319 (*it)->x_OnLockAcquired();
2365 #if defined(NCBI_THREADS)
2370 #if defined(NCBI_THREADS)
2371 #if defined(NCBI_OS_MSWIN)
2372 InitializeConditionVariable(&m_ConditionVar);
2374 int res = pthread_cond_init(&m_ConditionVar,
NULL);
2380 "CConditionVariable: not enough resources");
2383 "CConditionVariable: not enough memory");
2386 "CConditionVariable: attempt to reinitialize"
2387 " already used variable");
2390 "CConditionVariable: invalid attribute value");
2393 "CConditionVariable: unknown error");
2402 #if defined(NCBI_THREADS)
2403 #if !defined(NCBI_OS_MSWIN)
2410 "~CConditionVariable: attempt to destroy variable that"
2411 " is currently in use");
2415 "~CConditionVariable: invalid condition variable");
2419 "~CConditionVariable: unknown error");
2421 NCBI_TROUBLE(
"CConditionVariable: pthread_cond_destroy() failed");
2427 #if defined(NCBI_THREADS)
2486 "WaitForSignal called with different mutexes");
2492 (SSystemFastMutex& mutex,
const CDeadline& deadline)
2498 #if defined(NCBI_OS_MSWIN)
2501 #if defined(NCBI_FASTMUTEX_USE_NEW)
2502 BOOL res = SleepConditionVariableSRW(&
m_ConditionVar, &mutex.m_Handle, timeout_msec, 0);
2511 DWORD err_code = GetLastError();
2512 if (err_code == ERROR_TIMEOUT || err_code == WAIT_TIMEOUT)
2516 "WaitForSignal failed");
2528 res = pthread_cond_timedwait(&
m_ConditionVar, &mutex.m_Handle, &ts);
2538 "WaitForSignal failed: invalid paramater");
2541 "WaitForSignal: mutex not owned by the current thread");
2544 "WaitForSignal failed: unknown error");
2557 #if defined(NCBI_THREADS)
2558 SSystemMutex& sys_mtx = mutex;
2559 if (sys_mtx.m_Count != 1) {
2561 "WaitForSignal: mutex lock count not 1");
2563 #if defined(NCBI_OS_MSWIN)
2566 "WaitForSignal: mutex not owned by the current thread");
2569 sys_mtx.Unlock(SSystemFastMutex::ePseudo);
2571 sys_mtx.Lock(SSystemFastMutex::ePseudo);
2582 #if defined(NCBI_THREADS)
2583 SSystemFastMutex& sys_mtx = mutex;
2584 sys_mtx.
Unlock(SSystemFastMutex::ePseudo);
2586 sys_mtx.Lock(SSystemFastMutex::ePseudo);
2596 #if defined(NCBI_THREADS)
2597 #if defined(NCBI_OS_MSWIN)
2605 "SignalSome failed: invalid paramater");
2608 "SignalSome failed: unknown error");
2618 #if defined(NCBI_THREADS)
2619 #if defined(NCBI_OS_MSWIN)
2627 "SignalAll failed: invalid paramater");
2630 "SignalAll failed: unknown error");
CConditionVariableException –.
Object factory for simple creation and deletion of the object with one parameter passed to object's c...
~CQuickAndDirtySamePointerGuard()
bool DetectedDifferentPointers(void)
volatile TPointer & m_GuardedPtr
CAtomicCounter & m_AtomicCounter
CQuickAndDirtySamePointerGuard(CAtomicCounter &atomic_counter, TPointer volatile &guarded_ptr, TPointer new_ptr)
Default implementation of IRWLockHolder_Factory.
THolderPool m_Pool
Implementation of CRWLockHolder objects pool.
CObjFactory_NewParam< CRWLockHolder, CRWLockHolder_Pool * > THolderPoolFactory
virtual ~CRWLockHolder_Pool(void)
CObjPool< CRWLockHolder, THolderPoolFactory > THolderPool
virtual void DeleteHolder(CRWLockHolder *holder)
Free unnecessary (and unreferenced by anybody) CRWLockHolder object.
virtual CRWLockHolder * CreateHolder(CYieldingRWLock *lock, ERWLockType typ)
Obtain new CRWLockHolder object for given CYieldingRWLock and necessary lock type.
Holder of the lock inside CYieldingRWLock.
CTimeout – Timeout interval.
Read/write lock without blocking calls.
Interface for factory creating CRWLockHolder objects.
static const char * expected[]
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
TValue Get(void) const THROWS_NONE
Get atomic counter value.
#define NCBI_TROUBLE(mess)
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
void Critical(CExceptionArgs_Base &args)
void Error(CExceptionArgs_Base &args)
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
TErrCode GetErrCode(void) const
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
static mode_t MakeModeT(TMode user_mode, TMode group_mode, TMode other_mode, TSpecialModeBits special)
Construct mode_t value from permission modes.
@ fWrite
Write permission.
bool NotNull(void) const THROWS_NONE
Check if pointer is not null – same effect as NotEmpty().
bool Referenced(void) const THROWS_NONE
Check if object is referenced.
void Return(TObjType *obj)
Return object to the pool for future use.
TObjType * Get(void)
Get object from the pool, create if necessary.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
#define NCBI_SCHED_YIELD()
volatile unsigned int m_WaitingWriters
Number of writers waiting; zero if not keeping track.
ERWLockType
Type of locking provided by CYieldingRWLock.
ELockSemantics
This is for condition variables.
unique_ptr< CInternalRWLock > m_RW
Platform-dependent RW-lock data.
struct SSemaphore * m_Sem
System-specific semaphore data.
bool TryLock(void)
Attempt to lock the mutex and return TRUE if it succeeded or FALSE if mutex is locked by other thread...
CSemaphore(unsigned int init_count, unsigned int max_count)
Constructor.
void Lock(void)
Acquire mutex for the current thread with no nesting checks.
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
void ReadUnlock(void)
Release read lock.
virtual ~CRWLockHolder(void)
~CConditionVariable(void)
void SignalSome(void)
Wake at least one of the threads that are currently waiting on this condition variable (if any thread...
ERWLockType m_Type
Type of lock held.
static bool IsSupported(void)
void Wait(void)
Wait on semaphore.
CFastMutex m_WriteLock
Mutex implementing write lock.
void ReadLock(void)
Read lock.
bool TryReadLock(void)
Try read lock.
void Reset(void)
Reset holder to be able to use it later (after calling Init() )
CSpinLock m_ObjLock
Main locking mutex for object operations.
TFlags m_Flags
Configuration flags.
void WriteUnlock(void)
Release write lock.
TRWLockHolderRef AcquireLock(ERWLockType lock_type)
General method to request read or write lock.
THoldersList m_LockWaits
Queue for waiting lock requests.
virtual CRWLockHolder * CreateHolder(CYieldingRWLock *lock, ERWLockType typ)=0
Obtain new CRWLockHolder object for given CYieldingRWLock and necessary lock type.
vector< TThreadSystemID > m_Readers
List of all readers or writers.
volatile long m_Count
Number of readers (if >0) or writers (if <0)
SSystemFastMutex *volatile m_WaitMutex
IRWLockHolder_Factory * m_Factory
Factory created the holder.
bool TryWriteLock(void)
Try write lock.
bool x_MayAcquireForReading(TThreadSystemID self_id)
bool x_WaitForSignal(SSystemFastMutex &mutex, const CDeadline &timeout)
virtual void DeleteThis(void)
"Delete" this holder after last reference was removed.
TListenersList m_Listeners
List of holder listeners.
IRWLockHolder_Factory * m_Factory
Factory creating CRWLockHolder objects.
void x_OnLockReleased(void)
Callback called at the moment when lock is released.
bool WaitForSignal(CMutex &mutex, const CDeadline &deadline=CDeadline::eInfinite)
Release mutex and lock the calling thread until the condition variable is signalled.
void SignalAll(void)
Wake all threads that are currently waiting on the condition variable.
pthread_mutex_t TSystemMutex
Define a platform independent system mutex.
CAtomicCounter_WithAutoInit m_WaitCounter
CRWLock(TFlags flags=0)
Constructor.
volatile TThreadSystemID m_Owner
Writer ID, one of the readers ID.
void Init(CYieldingRWLock *lock, ERWLockType typ)
Initialize holder for given CYieldingRWLock and necessary lock type.
void Unlock(void)
Unlock the mutex.
void ReadLock(void)
Acquire read lock.
void ReleaseLock(void)
Release the lock held or cancel request for the lock.
virtual void DeleteHolder(CRWLockHolder *holder)=0
Free unnecessary (and unreferenced by anybody) CRWLockHolder object.
CAtomicCounter m_LockCount
Number of read locks acquired or value of kWriteLockValue if write lock was acquired.
void x_ReleaseLock(CRWLockHolder *holder)
Main implementation releasing lock.
deque< TRWLockHolderRef > THoldersList
void Lock(void)
Lock the mutex.
list< TRWLockHolder_ListenerWeakRef > TListenersList
void x_OnLockAcquired(void)
Callback called at the moment when lock is granted.
void WriteLock(void)
Write lock.
int m_Locks[2]
Number of locks granted on this object by type.
CYieldingRWLock * m_Lock
Lock object the holder is assigned to.
void WriteLock(void)
Acquire write lock.
CONDITION_VARIABLE m_ConditionVar
pthread_t TThreadSystemID
Define platform-dependent thread ID type.
~CYieldingRWLock(void)
It is fatal error to destroy the object while some locks are pending.
bool TryWait(unsigned int timeout_sec=0, unsigned int timeout_nsec=0)
Timed wait.
virtual ~IRWLockHolder_Factory(void)
~CSemaphore(void)
Destructor.
void Post(unsigned int count=1)
Increment the semaphore by "count".
CSpinLock m_ObjLock
Mutex for operating listeners.
int TFlags
binary OR of EFlags
CYieldingRWLock(IRWLockHolder_Factory *factory=NULL)
Create read/write lock with custom holders factory.
~CRWLock(void)
Destructor.
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
void *volatile m_Value
Flag showing if mutex is locked (non-NULL value) or unlocked (NULL value).
void Unlock(void)
Release mutex with no owner or nesting checks.
bool m_LockAcquired
Flag if lock was acquired.
static TThreadSystemID GetCurrentThreadSystemID(void)
Get the current thread ID.
void Unlock(void)
Release the RW-lock.
virtual ~IRWLockHolder_Listener(void)
@ fFavorWriters
Forbid further readers from acquiring the lock if any writers are waiting for it, to keep would-be wr...
@ eMutexLockCount
Mutex passed to WaitForSignal is not owned by the current thread.
@ eMutexOwner
Different mutexes were supplied for concurrent WaitForSignal operations on this condition variable.
@ eMutexDifferent
Condition variable is not supported on this platform.
@ eInvalidValue
Parameter of WaitForSignal function is invalid.
@ fTrackReaders
Keep track of which threads have read locks.
@ kWriteLockValue
Number in lock count showing that write lock is acquired.
@ eUninitialized
Uninitialized error.
@ eTryLock
Attempted lock error.
CNanoTimeout GetRemainingTime(void) const
Get time left to the expiration.
void GetNano(unsigned int *sec, unsigned int *nanosec) const
Get timeout in seconds and nanoseconds.
unsigned long GetAsMilliSeconds(void) const
Get as number of milliseconds.
bool IsInfinite(void) const
Check if the deadline is infinite.
void GetExpirationTime(time_t *sec, unsigned int *nanosec) const
Get the number of seconds and nanoseconds (since 1/1/1970).
#define HANDLE
An abstraction for a file handle.
Definition of all error codes used in corelib (xncbi.lib).
#define TRUE
bool replacment for C indicating true.
#define FALSE
bool replacment for C indicating false.
void * SwapPointers(void *volatile *location, void *new_value)
#define xncbi_ValidateAndErrnoReport(expression, message)
#define xncbi_VerifyAndErrorReport(expression)
#define xncbi_ValidatePthread(expression, expected_value, message)
#define xncbi_Validate(expression, message)
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
void interlocked_set(volatile long *val, long new_val)
#define WRITE_MUTEX_EVENT(mutex, message)
bool interlocked_dec_min(volatile long *val, long min)
bool interlocked_dec_max(volatile long *val, long max)
void s_ThrowIfDifferentMutexes(CQuickAndDirtySamePointerGuard< SSystemFastMutex > &mutex_guard)
#define NCBI_THREADS_ARG(arg)
bool interlocked_inc_max(volatile long *val, long max)
bool interlocked_inc_min(volatile long *val, long min)
static CSafeStatic< CRWLockHolder_Pool > s_RWHolderPool
Default CRWLockHolder pool used in CYieldingRWLock.
Multi-threading – mutexes; rw-locks; semaphore.
atomic< unsigned int > count
atomic< unsigned int > wait_count