NCBI C++ ToolKit
ncbimtx.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbimtx.cpp 99780 2023-05-10 17:43:40Z vasilche $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Denis Vakatov, Aleksey Grichenko, Eugene Vasilchenko
27  *
28  * File Description:
29  * Multi-threading -- fast mutexes
30  *
31  * MUTEX:
32  * CInternalMutex -- platform-dependent mutex functionality
33  *
34  */
35 
36 #include <ncbi_pch.hpp>
37 #include <corelib/ncbimtx.hpp>
38 #include <corelib/ncbi_limits.h>
39 #include <corelib/obj_pool.hpp>
40 #include "ncbidbg_p.hpp"
41 #include <stdio.h>
42 #include <algorithm>
43 #include <chrono>
44 
45 //#define LOG_MUTEX_EVENTS
46 
47 #ifdef NCBI_POSIX_THREADS
48 # include <sys/time.h> // for gettimeofday()
49 # include <sched.h> // for sched_yield()
50 #endif
51 
52 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
53 
54 #include <corelib/ncbifile.hpp>
55 #include <fcntl.h>
56 # if defined(NCBI_OS_MSWIN)
57 # include <io.h>
58 # else
59 # include <unistd.h>
60 # endif
61 
62 #endif
63 
64 #include <corelib/error_codes.hpp>
65 
66 #define STACK_THRESHOLD (1024)
67 
68 #define NCBI_USE_ERRCODE_X Corelib_Mutex
69 
70 
72 
73 
74 /////////////////////////////////////////////////////////////////////////////
75 //
76 // Log mutex events if LOG_MUTEX_EVENTS is defined.
77 //
78 // The mutex events (create/destroy/lock/unlock) are logged into
79 // ./mutex_events.log or the one specified in MUTEX_EVENTS_LOG_FILE
80 // env. variable.
81 //
82 
83 
84 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
85 
86 // Logging function, prints pointer to the mutex, system thread ID
87 // and the message.
88 static void s_WriteMutexEvent(void* mutex_ptr, const char* message);
89 # define WRITE_MUTEX_EVENT(mutex, message) s_WriteMutexEvent(mutex, message)
90 
91 #else
92 
93 # define WRITE_MUTEX_EVENT(mutex, message) ((void)0)
94 
95 #endif
96 
97 
98 
99 #if defined(_DEBUG) && defined(LOG_MUTEX_EVENTS)
100 
101 void s_WriteMutexEvent(void* mutex_ptr, const char* message)
102 {
103  static const int mode = O_WRONLY | O_APPEND | O_CREAT;
104  static const mode_t perm = CDirEntry::MakeModeT(
108  0);
109  static const char* file_name = getenv("MUTEX_EVENTS_LOG_FILE"); /*This can
110  lead to multiple opens of a file in multithreaded mode, but left so by
111  intention, because:
112  1) with C++11-compatible compiler problem will be gone,
113  while any modification makes it worse adapted to C++11;
114  2) You cannot use mutexes in the function that is called by any mutex
115  create/delete/lock/unlock;
116  3) File is opened without O_TRUNC, so any write()'s to file will be saved
117  even if write()'s are made with different handles
118  4) This is a debug-only function. */
119  static int handle = open(file_name ? file_name : "mutex_events.log",
120  mode, perm);
121  CNcbiOstrstream str_os;
122  str_os << mutex_ptr << " "
123  << GetCurrentThreadSystemID() << " "
124  << message << "\n";
125  write(handle, str_os.str(), str_os.pcount());
126  str_os.rdbuf()->freeze(false);
127 }
128 
129 #endif
130 
131 
132 /////////////////////////////////////////////////////////////////////////////
133 // CInternalMutex::
134 //
135 
136 void SSystemFastMutex::InitializeHandle(void)
137 {
138  WRITE_MUTEX_EVENT(this, "SSystemFastMutex::InitializeHandle()");
139 
140  // Create platform-dependent mutex handle
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);
146 # else
148  (m_Handle = CreateMutex(NULL, FALSE, NULL)) != NULL,
149  "Mutex creation failed");
150 # endif
151 #elif defined(NCBI_POSIX_THREADS)
152 # if defined(NCBI_OS_CYGWIN)
153  if (pthread_mutex_init(&m_Handle, 0) != 0) {
154  // On Cygwin, there was an attempt to check the mutex state,
155  // which in some cases (uninitialized memory) could cause
156  // a fake EBUSY error. This bug seems to have been fixed
157  // (just looked at the source code; never tested) in the early 2006.
158  memset(&m_Handle, 0, sizeof(m_Handle));
159 # endif /* NCBI_OS_CYGWIN */
160  xncbi_ValidatePthread(pthread_mutex_init(&m_Handle, 0), 0,
161  "Mutex creation failed");
162 # if defined(NCBI_OS_CYGWIN)
163  }
164 # endif /* NCBI_OS_CYGWIN */
165 #endif
166 }
167 
168 void SSystemFastMutex::DestroyHandle(void)
169 {
170  WRITE_MUTEX_EVENT(this, "SSystemFastMutex::DestroyHandle()");
171 
172  // Destroy system mutex handle
173 #if defined(NCBI_WIN32_THREADS)
174 # if defined(NCBI_FASTMUTEX_USE_NEW)
175 // noop
176 # elif defined(NCBI_USE_CRITICAL_SECTION)
177  DeleteCriticalSection(&m_Handle);
178 # else
179  xncbi_VerifyAndErrorReport(CloseHandle(m_Handle) != 0);
180 # endif
181 #elif defined(NCBI_POSIX_THREADS)
182  xncbi_VerifyAndErrorReport(pthread_mutex_destroy(&m_Handle) == 0);
183 #endif
184 }
185 
186 void SSystemFastMutex::InitializeStatic(void)
187 {
188 #if !defined(NCBI_NO_THREADS)
189  switch ( m_Magic ) {
190  case eMutexUninitialized: // ok
191  break;
192  case eMutexInitialized:
193  xncbi_Validate(0, "Double initialization of mutex");
194  break;
195  default:
196  xncbi_Validate(0, "SSystemFastMutex::m_Magic contains invalid value");
197  break;
198  }
199 
200  InitializeHandle();
201 #endif
202 
203  m_Magic = eMutexInitialized;
204 }
205 
206 
207 void SSystemFastMutex::InitializeDynamic(void)
208 {
209 #if !defined(NCBI_NO_THREADS)
210  InitializeHandle();
211 #endif
212 
213  m_Magic = eMutexInitialized;
214 }
215 
216 
217 void SSystemFastMutex::Destroy(void)
218 {
219 #if !defined(NCBI_NO_THREADS)
220  xncbi_Validate(IsInitialized(), "Destruction of uninitialized mutex");
221 #endif
222 
223  m_Magic = eMutexUninitialized;
224 
225  DestroyHandle();
226 }
227 
228 void SSystemFastMutex::ThrowUninitialized(void)
229 {
230  NCBI_THROW(CMutexException, eUninitialized, "Mutex uninitialized");
231 }
232 
233 void SSystemFastMutex::ThrowLockFailed(void)
234 {
235  NCBI_THROW(CMutexException, eLock, "Mutex lock failed");
236 }
237 
238 void SSystemFastMutex::ThrowUnlockFailed(void)
239 {
240  NCBI_THROW(CMutexException, eUnlock, "Mutex unlock failed");
241 }
242 
243 void SSystemFastMutex::ThrowTryLockFailed(void)
244 {
245  NCBI_THROW(CMutexException, eTryLock,
246  "Mutex check (TryLock) failed");
247 }
248 
249 void SSystemMutex::Destroy(void)
250 {
251  xncbi_Validate(m_Count == 0, "Destruction of locked mutex");
252  m_Mutex.Destroy();
253 }
254 
255 #if !defined(NCBI_NO_THREADS)
256 void SSystemFastMutex::Lock(ELockSemantics lock /*= eNormal*/)
257 {
258  WRITE_MUTEX_EVENT(this, "SSystemFastMutex::Lock()");
259 
260  // check
261  CheckInitialized();
262  if (lock != eNormal) {
263  return;
264  }
265 
266  // Acquire system mutex
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);
272 # else
273  if (WaitForSingleObject(m_Handle, INFINITE) != WAIT_OBJECT_0) {
274  ThrowLockFailed();
275  }
276 # endif
277 # elif defined(NCBI_POSIX_THREADS)
278  if ( pthread_mutex_lock(&m_Handle) != 0 ) { // error
279  ThrowLockFailed();
280  }
281 # endif
282 }
283 
284 bool SSystemFastMutex::TryLock(void)
285 {
286  WRITE_MUTEX_EVENT(this, "SSystemFastMutex::TryLock()");
287 
288  // check
289  CheckInitialized();
290 
291  // Check if the system mutex is acquired.
292  // If not, acquire for the current thread.
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;
298 # else
299  DWORD status = WaitForSingleObject(m_Handle, 0);
300  if (status == WAIT_OBJECT_0) { // ok
301  return true;
302  }
303  else {
304  if (status != WAIT_TIMEOUT) { // error
305  ThrowTryLockFailed();
306  }
307  return false;
308  }
309 # endif
310 # elif defined(NCBI_POSIX_THREADS)
311  int status = pthread_mutex_trylock(&m_Handle);
312  if (status == 0) { // ok
313  return true;
314  }
315  else {
316  if (status != EBUSY) { // error
317  ThrowTryLockFailed();
318  }
319  return false;
320  }
321 # endif
322 }
323 
324 void SSystemFastMutex::Unlock(ELockSemantics lock /*= eNormal*/)
325 {
326  WRITE_MUTEX_EVENT(this, "SSystemFastMutex::Unlock()");
327 
328  // check
329  CheckInitialized();
330  if (lock != eNormal) {
331  return;
332  }
333 
334  // Release system mutex
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);
340 # else
341  if ( !ReleaseMutex(m_Handle) ) { // error
342  ThrowUnlockFailed();
343  }
344 # endif
345 # elif defined(NCBI_POSIX_THREADS)
346  if ( pthread_mutex_unlock(&m_Handle) != 0 ) { // error
347  ThrowUnlockFailed();
348  }
349 # endif
350 }
351 
352 void SSystemMutex::Lock(SSystemFastMutex::ELockSemantics lock)
353 {
354  m_Mutex.CheckInitialized();
355 
357  auto count = m_Count.load(memory_order_acquire);
358  if ( count > 0 && m_Owner.load(memory_order_relaxed) == owner ) {
359  // Don't lock twice, just increase the counter
360  m_Count.store(++count, memory_order_release);
361  return;
362  }
363 
364  // Lock the mutex and remember the owner
365  m_Mutex.Lock(lock);
366  assert(m_Count == 0);
367  m_Owner.store(owner, memory_order_relaxed);
368  m_Count.store(1, memory_order_release);
369 }
370 
371 bool SSystemMutex::TryLock(void)
372 {
373  m_Mutex.CheckInitialized();
374 
376  auto count = m_Count.load(memory_order_acquire);
377  if ( count > 0 && m_Owner.load(memory_order_relaxed) == owner ) {
378  // Don't lock twice, just increase the counter
379  m_Count.store(++count, memory_order_release);
380  return true;
381  }
382 
383  // If TryLock is successful, remember the owner
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);
388  return true;
389  }
390 
391  // Cannot lock right now
392  return false;
393 }
394 
395 void SSystemMutex::Unlock(SSystemFastMutex::ELockSemantics lock)
396 {
397  m_Mutex.CheckInitialized();
398 
399  // No unlocks by threads other than owner.
400  // This includes no unlocks of unlocked mutex.
402  auto count = m_Count.load(memory_order_acquire);
403  if ( count == 0 || m_Owner.load(memory_order_relaxed) != owner ) {
404  ThrowNotOwned();
405  }
406 
407  // No real unlocks if counter > 1, just decrease it
408  m_Count.store(--count, memory_order_release);
409  if ( count > 0 ) {
410  return;
411  }
412 
413  // This was the last lock - clear the owner and unlock the mutex
414  m_Mutex.Unlock(lock);
415 }
416 #endif
417 
418 void SSystemMutex::ThrowNotOwned(void)
419 {
420  NCBI_THROW(CMutexException, eOwner,
421  "Mutex is not owned by current thread");
422 }
423 
424 
425 #if defined(NEED_AUTO_INITIALIZE_MUTEX)
426 //#define USE_STATIC_INIT_MUTEX_HANDLE 1
427 
428 static const char* kInitMutexName = "NCBI_CAutoInitializeStaticMutex";
429 
430 #ifdef USE_STATIC_INIT_MUTEX_HANDLE
431 
432 static volatile TSystemMutex s_InitMutexHandle = 0;
433 static TSystemMutex s_GetInitMutexHandle(void)
434 {
435  TSystemMutex init_mutex = s_InitMutexHandle;
436  if ( !init_mutex ) {
437  init_mutex = CreateMutex(NULL, FALSE, kInitMutexName);
438  xncbi_VerifyAndErrorReport(init_mutex);
439  assert(!s_InitMutexHandle || s_InitMutexHandle == init_mutex);
440  s_InitMutexHandle = init_mutex;
441  }
442  return init_mutex;
443 }
444 
445 static inline void s_ReleaseInitMutexHandle(TSystemMutex _DEBUG_ARG(mutex))
446 {
447  assert(mutex == s_InitMutexHandle);
448 }
449 
450 #else
451 
452 static inline HANDLE s_GetInitMutexHandle(void)
453 {
454  HANDLE init_mutex = CreateMutexA(NULL, FALSE, kInitMutexName);
455  xncbi_VerifyAndErrorReport(init_mutex);
456  return init_mutex;
457 }
458 
459 static inline void s_ReleaseInitMutexHandle(HANDLE mutex)
460 {
461  CloseHandle(mutex);
462 }
463 
464 #endif
465 
466 void CAutoInitializeStaticFastMutex::Initialize(void)
467 {
468  if ( m_Mutex.IsInitialized() ) {
469  return;
470  }
471  HANDLE init_mutex = s_GetInitMutexHandle();
473  WaitForSingleObject(init_mutex, INFINITE) == WAIT_OBJECT_0);
474  if ( !m_Mutex.IsInitialized() ) {
475  m_Mutex.InitializeStatic();
476  }
477  xncbi_VerifyAndErrorReport(ReleaseMutex(init_mutex));
478  assert(m_Mutex.IsInitialized());
479  s_ReleaseInitMutexHandle(init_mutex);
480 }
481 
482 void CAutoInitializeStaticMutex::Initialize(void)
483 {
484  if ( m_Mutex.IsInitialized() ) {
485  return;
486  }
487  HANDLE init_mutex = s_GetInitMutexHandle();
489  WaitForSingleObject(init_mutex, INFINITE) == WAIT_OBJECT_0);
490  if ( !m_Mutex.IsInitialized() ) {
491  m_Mutex.InitializeStatic();
492  }
493  xncbi_VerifyAndErrorReport(ReleaseMutex(init_mutex));
494  assert(m_Mutex.IsInitialized());
495  s_ReleaseInitMutexHandle(init_mutex);
496 }
497 
498 #endif
499 
500 const char* CMutexException::GetErrCodeString(void) const
501 {
502  switch (GetErrCode()) {
503  case eLock: return "eLock";
504  case eUnlock: return "eUnlock";
505  case eTryLock: return "eTryLock";
506  case eOwner: return "eOwner";
507  case eUninitialized: return "eUninitialized";
508  default: return CException::GetErrCodeString();
509  }
510 }
511 
512 /////////////////////////////////////////////////////////////////////////////
513 // CInternalRWLock::
514 //
515 
516 #if defined(NCBI_WIN32_THREADS) && !NCBI_SRWLOCK_USE_NEW
517 
518 class CWindowsHandle
519 {
520 public:
521  CWindowsHandle(HANDLE h = NULL) : m_Handle(h) {}
522  CWindowsHandle(HANDLE h, const char* errorMessage) : m_Handle(h)
523  {
524  xncbi_Validate(h != NULL, errorMessage);
525  }
526  ~CWindowsHandle(void) { Close(); }
527 
528  void Close(void)
529  {
530  if ( m_Handle != NULL ) {
531  CloseHandle(m_Handle);
532  m_Handle = NULL;
533  }
534  }
535 
536  void Set(HANDLE h)
537  {
538  Close();
539  m_Handle = h;
540  }
541  void Set(HANDLE h, const char* errorMessage)
542  {
543  xncbi_Validate(h != NULL, errorMessage);
544  Set(h);
545  }
546 
547  HANDLE GetHandle(void) const { return m_Handle; }
548  operator HANDLE(void) const { return m_Handle; }
549 
550 protected:
551  HANDLE m_Handle;
552 
553 private:
554  CWindowsHandle(const CWindowsHandle& h);
555  CWindowsHandle& operator=(const CWindowsHandle& h);
556 };
557 
558 class CWindowsSemaphore : public CWindowsHandle
559 {
560 public:
561  CWindowsSemaphore(LONG initialCount = 0, LONG maximumCount = INFINITE)
562  : CWindowsHandle(CreateSemaphore(NULL,
563  initialCount, maximumCount,
564  NULL),
565  "CreateSemaphore() failed")
566  {
567  }
568 
569  LONG Release(LONG add = 1)
570  {
571  LONG prev_sema;
572  xncbi_ValidateAndErrnoReport(ReleaseSemaphore(*this, add, &prev_sema),
573  "CWindowsSemaphore::Release() failed");
574  return prev_sema;
575  }
576 };
577 
578 #endif
579 
580 #if defined(NCBI_POSIX_THREADS)
581 
583 {
584 public:
586  : m_Initialized(pthread_cond_init(&m_Handle, 0) != 0)
587  {
588  }
590  {
591  if ( m_Initialized ) {
592  pthread_cond_destroy(&m_Handle);
593  }
594  }
595 
596  operator pthread_cond_t*(void) { return &m_Handle; }
597  operator pthread_cond_t&(void) { return m_Handle; }
598 
599 protected:
600  pthread_cond_t m_Handle;
602 };
603 
604 #endif
605 
606 #if !NCBI_SRWLOCK_USE_NEW
608 {
609 public:
610  CInternalRWLock(void);
611 
612  // Platform-dependent RW-lock data
613 #if defined(NCBI_WIN32_THREADS)
614  CWindowsSemaphore m_Rsema; // down when locked for writing
615  CWindowsSemaphore m_Rsema2; // down when writers are waiting
616  CWindowsSemaphore m_Wsema; // down when locked for reading OR writing
617 # if defined(NCBI_USE_CRITICAL_SECTION)
618  CWindowsHandle m_Mutex;
619 # else
621 # endif
622 #elif defined(NCBI_POSIX_THREADS)
626 #endif
627 };
628 
629 inline
631 #if defined(NCBI_WIN32_THREADS)
632  : m_Rsema(1, 1), m_Rsema2(1, 1), m_Wsema(1, 1)
633 #endif
634 {
635 #if defined(NCBI_USE_CRITICAL_SECTION)
636  m_Mutex.Set(CreateMutex(NULL, FALSE, NULL));
637 #endif
638 }
639 #endif
640 /////////////////////////////////////////////////////////////////////////////
641 // CRWLock::
642 //
643 
644 #if NCBI_SRWLOCK_USE_NEW
645 CRWLock::CRWLock(TFlags flags)
646  : m_Owner(0), m_Count(0), m_WaitingWriters(0), m_TrackReaders(false)
647 {
648 #if defined(_DEBUG)
649  m_TrackReaders = true;
650  m_FavorWriters = (flags & fFavorWriters) != 0;
651 #else
652  m_TrackReaders = m_FavorWriters = (flags & fFavorWriters) != 0;
653 #endif
654  if (m_TrackReaders) {
655  m_Readers.reserve(16);
656  }
657 }
658 #else
660  : m_Flags(flags),
661  m_RW(new CInternalRWLock),
662  m_Count(0),
663  m_WaitingWriters(0)
664 {
665 #if defined(_DEBUG)
667 #else
668  if (m_Flags & fFavorWriters) {
670  }
671 #endif
672  if (m_Flags & fTrackReaders) {
673  m_Readers.reserve(16);
674  }
675 }
676 #endif
677 
678 
680 {
681  _ASSERT(m_Count == 0);
682 }
683 
684 
685 #if NCBI_SRWLOCK_USE_NEW
686 inline
687 vector<TThreadSystemID>::const_iterator
688 CRWLock::x_FindReader(TThreadSystemID self_id)
689 {
690  return find(m_Readers.begin(), m_Readers.end(), self_id);
691 }
692 
693 inline
694 bool
695 CRWLock::x_HasReader(TThreadSystemID self_id)
696 {
697  return m_Readers.empty() ? false : x_FindReader(self_id) != m_Readers.end();
698 }
699 
700 inline
702 {
703  return (m_WaitingWriters == 0 && m_Count >= 0) || (m_TrackReaders && x_HasReader(self_id));
704 }
705 
706 inline
707 bool CRWLock::x_TryWriteLock()
708 {
709  long expected = 0;
710  return m_Count.compare_exchange_strong(expected, expected-1);
711 }
712 
713 inline
714 bool CRWLock::x_TryReadLock()
715 {
716  long expected = 0;
717  do {
718  if (m_Count.compare_exchange_weak(expected, expected+1)) {
719  return true;
720  }
721  } while (expected >= 0);
722  return false;
723 }
724 #else
726 {
727  _ASSERT(self_id == GetCurrentThreadSystemID());
728  if (m_Count < 0) { // locked for writing, possibly by self
729  // return m_Owner.Is(self_id);
730  return false; // allow special handling of self-locked cases
731  } else if ( !(m_Flags & fFavorWriters) ) {
732  return true; // no other concerns
733  } else if (find(m_Readers.begin(), m_Readers.end(), self_id)
734  != m_Readers.end()) {
735  return true; // allow recursive read locks
736  } else {
737  return !m_WaitingWriters;
738  }
739 }
740 #endif
741 
742 
743 #if defined(NCBI_USE_CRITICAL_SECTION) && !NCBI_SRWLOCK_USE_NEW
744 
745 // Need special guard for system handle since mutex uses critical section
746 class CWin32MutexHandleGuard
747 {
748 public:
749  CWin32MutexHandleGuard(HANDLE mutex);
750  ~CWin32MutexHandleGuard(void);
751 private:
752  HANDLE m_Handle;
753 };
754 
755 
756 inline
757 CWin32MutexHandleGuard::CWin32MutexHandleGuard(HANDLE mutex)
758  : m_Handle(mutex)
759 {
760  WaitForSingleObject(m_Handle, INFINITE);
761 }
762 
763 
764 inline
765 CWin32MutexHandleGuard::~CWin32MutexHandleGuard(void)
766 {
767  ReleaseMutex(m_Handle);
768 }
769 #endif
770 
771 
772 // Helper functions for changing readers/writers counter without
773 // locking the mutex. Most of the functions check a condition
774 // and return false if it's not met before the new value is set.
775 
776 inline void interlocked_set(volatile long* val, long new_val)
777 {
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) {
782  break;
783  }
784  }
785 #else
786  *val = new_val;
787 #endif
788 }
789 
790 
791 inline bool interlocked_inc_min(volatile long* val, long min)
792 {
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) {
798  return true;
799  }
800  }
801  return false;
802 #else
803  (*val)++;
804  return true;
805 #endif
806 }
807 
808 
809 inline bool interlocked_inc_max(volatile long* val, long max)
810 {
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) {
816  return true;
817  }
818  }
819  return false;
820 #else
821  (*val)++;
822  return true;
823 #endif
824 }
825 
826 
827 inline bool interlocked_dec_max(volatile long* val, long max)
828 {
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) {
834  return true;
835  }
836  }
837  return false;
838 #else
839  (*val)--;
840  return true;
841 #endif
842 }
843 
844 
845 inline bool interlocked_dec_min(volatile long* val, long min)
846 {
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) {
852  return true;
853  }
854  }
855  return false;
856 #else
857  (*val)--;
858  return true;
859 #endif
860 }
861 
862 
864 {
865 #if defined(NCBI_NO_THREADS)
866  return;
867 #else
868 
869 #if NCBI_SRWLOCK_USE_NEW
871  if (m_Owner == self_id) {
872  --m_Count;
873  } else {
874  if (!m_TrackReaders && x_TryReadLock()) {
875  return;
876  }
877  unique_lock<mutex> lck( m_Mtx);
878  do {
879  if ( !x_MayAcquireForReading(self_id) ) {
880  while (m_WaitingWriters > 0 || m_Count < 0) {
881  m_Cv.wait(lck);
882  }
883  }
884  } while (!x_TryReadLock());
885  if (m_TrackReaders) {
886  m_Readers.push_back(self_id);
887  }
888  }
889 #else
890 
891 #if defined(NCBI_WIN32_THREADS)
892  if ((m_Flags & fTrackReaders) == 0) {
893  // Try short way if there are other readers.
894  if (interlocked_inc_min(&m_Count, 0)) return;
895  }
896 #endif
897 
899 
900  // Lock mutex now, unlock before exit.
901  // (in fact, it will be unlocked by the waiting function for a while)
902 #if defined(NCBI_USE_CRITICAL_SECTION)
903  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
904 #else
905  CFastMutexGuard guard(m_RW->m_Mutex);
906 #endif
907  if ( !x_MayAcquireForReading(self_id) ) {
908  if (m_Count < 0 && m_Owner == self_id) {
910  }
911  else {
912  // (due to be) W-locked by another thread
913 #if defined(NCBI_WIN32_THREADS)
914  HANDLE obj[3];
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");
921  DWORD wait_res =
922  WaitForMultipleObjects(3, obj, TRUE, INFINITE)-WAIT_OBJECT_0;
923  xncbi_Validate(wait_res < 3,
924  "CRWLock::ReadLock() - R-lock waiting error");
925  // Success, check the semaphore
926  xncbi_Validate(m_RW->m_Rsema.Release() == 0
927  && m_RW->m_Rsema2.Release() == 0,
928  "CRWLock::ReadLock() - invalid R-semaphore state");
929  if (m_Count == 0) {
930  xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema,
931  0) == WAIT_OBJECT_0,
932  "CRWLock::ReadLock() - "
933  "failed to lock W-semaphore");
934  }
935 #elif defined(NCBI_POSIX_THREADS)
936  while ( !x_MayAcquireForReading(self_id) ) {
938  pthread_cond_wait(m_RW->m_Rcond,
939  m_RW->m_Mutex.GetHandle()), 0,
940  "CRWLock::ReadLock() - R-lock waiting error");
941  }
942 #else
943  // Can not be already W-locked by another thread without MT
944  xncbi_Validate(0,
945  "CRWLock::ReadLock() - "
946  "weird R-lock error in non-MT mode");
947 #endif
948  xncbi_Validate(m_Count >= 0,
949  "CRWLock::ReadLock() - invalid readers counter");
951  }
952  }
953  else {
954 #if defined(NCBI_WIN32_THREADS)
955  if (m_Count == 0) {
956  // Unlocked
957  // Lock against writers
958  xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0)
959  == WAIT_OBJECT_0,
960  "CRWLock::ReadLock() - "
961  "can not lock W-semaphore");
962  }
963 #endif
965  }
966 
967  // Remember new reader
968  if ((m_Flags & fTrackReaders) != 0 && m_Count > 0) {
969  m_Readers.push_back(self_id);
970  }
971 #endif
972 #endif
973 }
974 
975 
977 {
978 #if defined(NCBI_NO_THREADS)
979  return true;
980 #else
981 
982 #if NCBI_SRWLOCK_USE_NEW
984  if (m_Owner == self_id) {
985  --m_Count;
986  } else {
987  if (!m_TrackReaders && x_TryReadLock()) {
988  return true;
989  }
990  unique_lock<mutex> lck( m_Mtx);
991  if (!x_MayAcquireForReading(self_id)) {
992  return false;
993  }
994  if (!x_TryReadLock()) {
995  return false;
996  }
997  if (m_TrackReaders) {
998  m_Readers.push_back(self_id);
999  }
1000  }
1001  return true;
1002 #else
1003 
1004 #if defined(NCBI_WIN32_THREADS)
1005  if ((m_Flags & fTrackReaders) == 0) {
1006  if (interlocked_inc_min(&m_Count, 0)) return true;
1007  }
1008 #endif
1009 
1011 
1012 #if defined(NCBI_USE_CRITICAL_SECTION)
1013  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1014 #else
1015  CFastMutexGuard guard(m_RW->m_Mutex);
1016 #endif
1017 
1018  if ( !x_MayAcquireForReading(self_id) ) {
1019  if (m_Count >= 0 || m_Owner != self_id) {
1020  // (due to be) W-locked by another thread
1021  return false;
1022  }
1023  else {
1024  // W-locked, try to set R after W if in the same thread
1026  return true;
1027  }
1028  }
1029 
1030  // Unlocked - do R-lock
1031 #if defined(NCBI_WIN32_THREADS)
1032  if (m_Count == 0) {
1033  // Lock W-semaphore in MSWIN
1034  xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0)
1035  == WAIT_OBJECT_0,
1036  "CRWLock::TryReadLock() - "
1037  "can not lock W-semaphore");
1038  }
1039 #endif
1041  if (m_Flags & fTrackReaders) {
1042  m_Readers.push_back(self_id);
1043  }
1044  return true;
1045 #endif
1046 #endif
1047 }
1048 
1049 
1050 bool CRWLock::TryReadLock(const CTimeout& timeout)
1051 {
1052 #if defined(NCBI_NO_THREADS)
1053  return true;
1054 #else
1055 
1056  if ( timeout.IsInfinite() ) {
1057  ReadLock();
1058  return true;
1059  }
1060  if ( timeout.IsZero() ) {
1061  return TryReadLock();
1062  }
1063 
1064 #if NCBI_SRWLOCK_USE_NEW
1066  if (m_Owner == self_id) {
1067  --m_Count;
1068  } else {
1069  if (!m_TrackReaders && x_TryReadLock()) {
1070  return true;
1071  }
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;
1076  bool ok = true;
1077 
1078  unique_lock<mutex> lck( m_Mtx);
1079  do {
1080  if (res == cv_status::timeout) {
1081  return false;
1082  }
1083  if (!x_MayAcquireForReading(self_id)) {
1084  while (!(ok = m_WaitingWriters == 0 && m_Count >= 0) && res == cv_status::no_timeout) {
1085  res = m_Cv.wait_until(lck, to);
1086  }
1087  }
1088  if (!ok) {
1089  return false;
1090  }
1091  } while (!x_TryReadLock());
1092  if (m_TrackReaders) {
1093  m_Readers.push_back(self_id);
1094  }
1095  }
1096  return true;
1097 #else
1098 
1099 #if defined(NCBI_WIN32_THREADS)
1100  if ((m_Flags & fTrackReaders) == 0) {
1101  // Try short way if there are other readers.
1102  if (interlocked_inc_min(&m_Count, 0)) return true;
1103  }
1104 #endif
1105 
1107 
1108  // Lock mutex now, unlock before exit.
1109  // (in fact, it will be unlocked by the waiting function for a while)
1110 #if defined(NCBI_USE_CRITICAL_SECTION)
1111  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1112 #else
1113  CFastMutexGuard guard(m_RW->m_Mutex);
1114 #endif
1115  if ( !x_MayAcquireForReading(self_id) ) {
1116  if (m_Count < 0 && m_Owner == self_id) {
1118  }
1119  else {
1120  // (due to be) W-locked by another thread
1121 #if defined(NCBI_WIN32_THREADS)
1122  HANDLE obj[3];
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");
1129  DWORD timeout_msec = timeout.GetAsMilliSeconds();
1130  DWORD wait_res =
1131  WaitForMultipleObjects(3, obj, TRUE, timeout_msec);
1132  if (wait_res == WAIT_TIMEOUT) {
1133  return false;
1134  }
1135  wait_res -= WAIT_OBJECT_0;
1136  xncbi_Validate(wait_res < 3,
1137  "CRWLock::TryReadLock() - R-lock waiting error");
1138  // Success, check the semaphore
1139  xncbi_Validate(m_RW->m_Rsema.Release() == 0
1140  && m_RW->m_Rsema2.Release() == 0,
1141  "CRWLock::TryReadLock() - invalid R-semaphore state");
1142  if (m_Count == 0) {
1143  xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema,
1144  0) == WAIT_OBJECT_0,
1145  "CRWLock::TryReadLock() - "
1146  "failed to lock W-semaphore");
1147  }
1148 #elif defined(NCBI_POSIX_THREADS)
1149  CDeadline deadline(timeout);
1150  time_t s;
1151  unsigned int ns;
1152  deadline.GetExpirationTime(&s, &ns);
1153  struct timespec ts;
1154  ts.tv_sec = s;
1155  ts.tv_nsec = ns;
1156  int res = 0;
1157  while ( !x_MayAcquireForReading(self_id) && res != ETIMEDOUT ) {
1158  res = pthread_cond_timedwait(m_RW->m_Rcond,
1159  m_RW->m_Mutex.GetHandle(), &ts);
1160  }
1161  if (res == ETIMEDOUT) {
1162  return false;
1163  }
1164  xncbi_Validate(res == 0,
1165  "CRWLock::TryReadLock() - R-lock waiting error");
1166 #else
1167  // Can not be already W-locked by another thread without MT
1168  xncbi_Validate(0,
1169  "CRWLock::TryReadLock() - "
1170  "weird R-lock error in non-MT mode");
1171 #endif
1172  xncbi_Validate(m_Count >= 0,
1173  "CRWLock::TryReadLock() - invalid readers counter");
1175  }
1176  }
1177  else {
1178 #if defined(NCBI_WIN32_THREADS)
1179  if (m_Count == 0) {
1180  // Unlocked
1181  // Lock against writers
1182  xncbi_Validate(WaitForSingleObject(m_RW->m_Wsema, 0)
1183  == WAIT_OBJECT_0,
1184  "CRWLock::TryReadLock() - "
1185  "can not lock W-semaphore");
1186  }
1187 #endif
1189  }
1190 
1191  // Remember new reader
1192  if ((m_Flags & fTrackReaders) != 0 && m_Count > 0) {
1193  m_Readers.push_back(self_id);
1194  }
1195  return true;
1196 #endif
1197 #endif
1198 }
1199 
1200 
1202 {
1203 #if defined(NCBI_NO_THREADS)
1204  return;
1205 #else
1206 
1207 #if NCBI_SRWLOCK_USE_NEW
1209  if (m_Owner == self_id) {
1210  --m_Count;
1211  } else {
1212  if (x_TryWriteLock()) {
1213  m_Owner = self_id;
1214  return;
1215  }
1216  unique_lock<mutex> lck( m_Mtx);
1217  _ASSERT(!m_TrackReaders || !x_HasReader(self_id));
1218  if (m_FavorWriters) {
1219  ++m_WaitingWriters;
1220  }
1221  while (!x_TryWriteLock()) {
1222  m_Cv.wait(lck);
1223  }
1224  m_Owner = self_id;
1225  if (m_FavorWriters) {
1226  --m_WaitingWriters;
1227  }
1228  }
1229 #else
1230 
1232 
1233 #if defined(NCBI_USE_CRITICAL_SECTION)
1234  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1235 #else
1236  CFastMutexGuard guard(m_RW->m_Mutex);
1237 #endif
1238 
1239  if ( m_Count < 0 && m_Owner == self_id ) {
1240  // W-locked by the same thread
1242  }
1243  else {
1244  // Unlocked or RW-locked by another thread
1245  // Look in readers - must not be there
1246  xncbi_Validate(find(m_Readers.begin(), m_Readers.end(), self_id)
1247  == m_Readers.end(),
1248  "CRWLock::WriteLock() - "
1249  "attempt to set W-after-R lock");
1250 
1251 #if defined(NCBI_WIN32_THREADS)
1252  HANDLE obj[3];
1253  obj[0] = m_RW->m_Rsema;
1254  obj[1] = m_RW->m_Wsema;
1255  obj[2] = m_RW->m_Mutex.GetHandle();
1256  if (m_Count == 0) {
1257  // Unlocked - lock both semaphores
1258  DWORD wait_res =
1259  WaitForMultipleObjects(2, obj, TRUE, 0)-WAIT_OBJECT_0;
1260  xncbi_Validate(wait_res < 2,
1261  "CRWLock::WriteLock() - "
1262  "error locking R&W-semaphores");
1263  }
1264  else {
1265  // Locked by another thread - wait for unlock
1266  if (m_Flags & fFavorWriters) {
1267  if (++m_WaitingWriters == 1) {
1268  // First waiting writer - lock out readers
1269  xncbi_Validate(WaitForSingleObject(m_RW->m_Rsema2, 0)
1270  == WAIT_OBJECT_0,
1271  "CRWLock::WriteLock() - "
1272  "error locking R-semaphore 2");
1273  }
1274  }
1276  ReleaseMutex(m_RW->m_Mutex.GetHandle()),
1277  "CRWLock::WriteLock() - release mutex error");
1278  DWORD wait_res =
1279  WaitForMultipleObjects(3, obj, TRUE, INFINITE)-WAIT_OBJECT_0;
1280  xncbi_Validate(wait_res < 3,
1281  "CRWLock::WriteLock() - "
1282  "error locking R&W-semaphores");
1283  if (m_Flags & fFavorWriters) {
1284  if (--m_WaitingWriters == 0) {
1285  xncbi_Validate(m_RW->m_Rsema2.Release() == 0,
1286  "CRWLock::WriteLock() - "
1287  "invalid R-semaphore 2 state");
1288  // Readers still won't be able to proceed, but releasing
1289  // the semaphore here simplifies bookkeeping.
1290  }
1291  }
1292  }
1293 #elif defined(NCBI_POSIX_THREADS)
1294  if (m_Flags & fFavorWriters) {
1295  ++m_WaitingWriters;
1296  }
1297  while (m_Count != 0) {
1299  pthread_cond_wait(m_RW->m_Wcond,
1300  m_RW->m_Mutex.GetHandle()), 0,
1301  "CRWLock::WriteLock() - error locking R&W-conditionals");
1302  }
1303  if (m_Flags & fFavorWriters) {
1304  --m_WaitingWriters;
1305  }
1306 #endif
1307  xncbi_Validate(m_Count >= 0,
1308  "CRWLock::WriteLock() - invalid readers counter");
1309  interlocked_set(&m_Count, -1);
1310  m_Owner = self_id;
1311  }
1312 
1313  // No readers allowed
1314  _ASSERT(m_Readers.empty());
1315 #endif
1316 #endif
1317 }
1318 
1319 
1321 {
1322 #if defined(NCBI_NO_THREADS)
1323  return true;
1324 #else
1325 
1326 #if NCBI_SRWLOCK_USE_NEW
1328  if (m_Owner == self_id) {
1329  --m_Count;
1330  } else {
1331  if (!x_TryWriteLock()) {
1332  return false;
1333  }
1334  m_Owner = self_id;
1335  }
1336  return true;
1337 #else
1338 
1340 
1341 #if defined(NCBI_USE_CRITICAL_SECTION)
1342  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1343 #else
1344  CFastMutexGuard guard(m_RW->m_Mutex);
1345 #endif
1346 
1347  if ( m_Count < 0 ) {
1348  // W-locked
1349  if ( m_Owner != self_id ) {
1350  // W-locked by another thread
1351  return false;
1352  }
1353  // W-locked by same thread
1355  }
1356  else if ( m_Count > 0 ) {
1357  // R-locked
1358  return false;
1359  }
1360  else {
1361  // Unlocked - do W-lock
1362 #if defined(NCBI_WIN32_THREADS)
1363  // In MSWIN lock semaphores
1364  HANDLE obj[2];
1365  obj[0] = m_RW->m_Rsema;
1366  obj[1] = m_RW->m_Wsema;
1367  DWORD wait_res =
1368  WaitForMultipleObjects(2, obj, TRUE, 0) - WAIT_OBJECT_0;
1369  xncbi_Validate(wait_res < 2,
1370  "CRWLock::TryWriteLock() - "
1371  "error locking R&W-semaphores");
1372 #endif
1373  interlocked_set(&m_Count, -1);
1374  m_Owner = self_id;
1375  }
1376 
1377  // No readers allowed
1378  _ASSERT(m_Readers.empty());
1379 
1380  return true;
1381 #endif
1382 #endif
1383 }
1384 
1385 
1386 bool CRWLock::TryWriteLock(const CTimeout& timeout)
1387 {
1388 #if defined(NCBI_NO_THREADS)
1389  return true;
1390 #else
1391 
1392  if ( timeout.IsInfinite() ) {
1393  WriteLock();
1394  return true;
1395  }
1396  if ( timeout.IsZero() ) {
1397  return TryWriteLock();
1398  }
1399 
1400 #if NCBI_SRWLOCK_USE_NEW
1402  if (m_Owner == self_id) {
1403  --m_Count;
1404  } else {
1405  if (x_TryWriteLock()) {
1406  m_Owner = self_id;
1407  return true;
1408  }
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;
1413  bool ok = true;
1414 
1415  unique_lock<mutex> lck( m_Mtx);
1416  do {
1417  if (res == cv_status::timeout) {
1418  return false;
1419  }
1420  if (m_FavorWriters) {
1421  ++m_WaitingWriters;
1422  }
1423  while (!(ok = m_Count == 0) && res == cv_status::no_timeout) {
1424  res = m_Cv.wait_until(lck, to);
1425  }
1426  if (m_FavorWriters) {
1427  --m_WaitingWriters;
1428  }
1429  if (!ok) {
1430  return false;
1431  }
1432  } while (!x_TryWriteLock());
1433  m_Owner = self_id;
1434  }
1435  return true;
1436 #else
1438 
1439 #if defined(NCBI_USE_CRITICAL_SECTION)
1440  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1441 #else
1442  CFastMutexGuard guard(m_RW->m_Mutex);
1443 #endif
1444 
1445  if ( m_Count < 0 && m_Owner == self_id ) {
1446  // W-locked by the same thread
1448  }
1449  else {
1450  // Unlocked or RW-locked by another thread
1451  // Look in readers - must not be there
1452  xncbi_Validate(find(m_Readers.begin(), m_Readers.end(), self_id)
1453  == m_Readers.end(),
1454  "CRWLock::TryWriteLock() - "
1455  "attempt to set W-after-R lock");
1456 
1457 #if defined(NCBI_WIN32_THREADS)
1458  HANDLE obj[3];
1459  obj[0] = m_RW->m_Rsema;
1460  obj[1] = m_RW->m_Wsema;
1461  obj[2] = m_RW->m_Mutex.GetHandle();
1462  if (m_Count == 0) {
1463  // Unlocked - lock both semaphores
1464  DWORD wait_res =
1465  WaitForMultipleObjects(2, obj, TRUE, 0)-WAIT_OBJECT_0;
1466  xncbi_Validate(wait_res < 2,
1467  "CRWLock::TryWriteLock() - "
1468  "error locking R&W-semaphores");
1469  }
1470  else {
1471  // Locked by another thread - wait for unlock
1472  if (m_Flags & fFavorWriters) {
1473  if (++m_WaitingWriters == 1) {
1474  // First waiting writer - lock out readers
1475  xncbi_Validate(WaitForSingleObject(m_RW->m_Rsema2, 0)
1476  == WAIT_OBJECT_0,
1477  "CRWLock::TryWriteLock() - "
1478  "error locking R-semaphore 2");
1479  }
1480  }
1482  ReleaseMutex(m_RW->m_Mutex.GetHandle()),
1483  "CRWLock::TryWriteLock() - release mutex error");
1484  DWORD timeout_msec = timeout.GetAsMilliSeconds();
1485  DWORD wait_res =
1486  WaitForMultipleObjects(3, obj, TRUE, timeout_msec);
1487  if (wait_res == WAIT_TIMEOUT) {
1488  if (m_Flags & fFavorWriters) {
1489  // Need temp lock to synchronize the counter and the semaphore.
1490  CWin32MutexHandleGuard counter_guard(m_RW->m_Mutex);
1491  if (--m_WaitingWriters == 0) {
1492  xncbi_Validate(m_RW->m_Rsema2.Release() == 0,
1493  "CRWLock::TryWriteLock() - "
1494  "invalid R-semaphore 2 state");
1495  // Readers still won't be able to proceed, but releasing
1496  // the semaphore here simplifies bookkeeping.
1497  }
1498  }
1499  return false;
1500  }
1501  wait_res -= WAIT_OBJECT_0;
1502  xncbi_Validate(wait_res < 3,
1503  "CRWLock::TryWriteLock() - "
1504  "error locking R&W-semaphores");
1505  if (m_Flags & fFavorWriters) {
1506  if (--m_WaitingWriters == 0) {
1507  xncbi_Validate(m_RW->m_Rsema2.Release() == 0,
1508  "CRWLock::TryWriteLock() - "
1509  "invalid R-semaphore 2 state");
1510  // Readers still won't be able to proceed, but releasing
1511  // the semaphore here simplifies bookkeeping.
1512  }
1513  }
1514  }
1515 #elif defined(NCBI_POSIX_THREADS)
1516  if (m_Flags & fFavorWriters) {
1517  ++m_WaitingWriters;
1518  }
1519  CDeadline deadline(timeout);
1520  time_t s;
1521  unsigned int ns;
1522  deadline.GetExpirationTime(&s, &ns);
1523  struct timespec ts;
1524  ts.tv_sec = s;
1525  ts.tv_nsec = ns;
1526  int res = 0;
1527  while (m_Count != 0 && res != ETIMEDOUT ) {
1528  res = pthread_cond_timedwait(m_RW->m_Wcond,
1529  m_RW->m_Mutex.GetHandle(), &ts);
1530  }
1531  if (res == ETIMEDOUT) {
1532  if (m_Flags & fFavorWriters) {
1533  --m_WaitingWriters;
1534  }
1535  return false;
1536  }
1537  xncbi_Validate(res == 0,
1538  "CRWLock::TryWriteLock() - "
1539  "error locking R&W-conditionals");
1540  if (m_Flags & fFavorWriters) {
1541  --m_WaitingWriters;
1542  }
1543 #endif
1544  xncbi_Validate(m_Count >= 0,
1545  "CRWLock::TryWriteLock() - invalid readers counter");
1546  interlocked_set(&m_Count, -1);
1547  m_Owner = self_id;
1548  }
1549 
1550  // No readers allowed
1551  _ASSERT(m_Readers.empty());
1552  return true;
1553 #endif
1554 #endif
1555 }
1556 
1557 
1559 {
1560 #if defined(NCBI_NO_THREADS)
1561  return;
1562 #else
1563 
1564 #if NCBI_SRWLOCK_USE_NEW
1566  if (m_Owner == self_id && m_Count < -1) {
1567  ++m_Count;
1568  return;
1569  }
1570  unique_lock<mutex> lck( m_Mtx/*, defer_lock*/);
1571  if (m_Owner == self_id) {
1572  m_Owner = 0;
1573  ++m_Count;
1574 // lck.lock();
1575  } else {
1576  long cnt = --m_Count;
1577  if (m_TrackReaders) {
1578 // lck.lock();
1579  m_Readers.erase( x_FindReader(self_id) );
1580  } else if (cnt != 0) {
1581  return;
1582  }
1583  }
1584  m_Cv.notify_all();
1585 #else
1586 
1587 #if defined(NCBI_WIN32_THREADS)
1588  if ((m_Flags & fTrackReaders) == 0) {
1589  if (interlocked_dec_min(&m_Count, 1)) return;
1590  }
1591 #endif
1592 
1594 
1595 #if defined(NCBI_USE_CRITICAL_SECTION)
1596  CWin32MutexHandleGuard guard(m_RW->m_Mutex);
1597 #else
1598  CFastMutexGuard guard(m_RW->m_Mutex);
1599 #endif
1600 
1601  if (m_Count < 0) {
1602  // Check it is R-locked or W-locked by the same thread
1603  xncbi_Validate(m_Owner == self_id,
1604  "CRWLock::Unlock() - "
1605  "RWLock is locked by another thread");
1607  if ( m_Count == 0 ) {
1608  // Unlock the last W-lock
1609 #if defined(NCBI_WIN32_THREADS)
1610  xncbi_Validate(m_RW->m_Rsema.Release() == 0,
1611  "CRWLock::Unlock() - invalid R-semaphore state");
1612  xncbi_Validate(m_RW->m_Wsema.Release() == 0,
1613  "CRWLock::Unlock() - invalid R-semaphore state");
1614 #elif defined(NCBI_POSIX_THREADS)
1615  if ( !m_WaitingWriters ) {
1617  pthread_cond_broadcast(m_RW->m_Rcond), 0,
1618  "CRWLock::Unlock() - error signalling unlock");
1619  }
1621  pthread_cond_signal(m_RW->m_Wcond), 0,
1622  "CRWLock::Unlock() - error signalling unlock");
1623 #endif
1624  }
1625  if (m_Flags & fTrackReaders) {
1626  // Check if the unlocking thread is in the owners list
1627  _ASSERT(find(m_Readers.begin(), m_Readers.end(), self_id)
1628  == m_Readers.end());
1629  }
1630  }
1631  else {
1632  xncbi_Validate(m_Count != 0,
1633  "CRWLock::Unlock() - RWLock is not locked");
1635  if ( m_Count == 0 ) {
1636  // Unlock the last R-lock
1637 #if defined(NCBI_WIN32_THREADS)
1638  xncbi_Validate(m_RW->m_Wsema.Release() == 0,
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");
1644 #endif
1645  }
1646  if (m_Flags & fTrackReaders) {
1647  // Check if the unlocking thread is in the owners list
1648  vector<TThreadSystemID>::iterator found =
1649  find(m_Readers.begin(), m_Readers.end(), self_id);
1650  _ASSERT(found != m_Readers.end());
1651  m_Readers.erase(found);
1652  if ( m_Count == 0 ) {
1653  _ASSERT(m_Readers.empty());
1654  }
1655  }
1656  }
1657 #endif
1658 #endif
1659 }
1660 
1661 
1662 
1663 
1664 /////////////////////////////////////////////////////////////////////////////
1665 // SEMAPHORE
1666 //
1667 
1668 
1669 // Platform-specific representation (or emulation) of semaphore
1671 {
1672 #if defined(NCBI_POSIX_THREADS)
1673  unsigned int max_count;
1674  atomic<unsigned int> count;
1675  atomic<unsigned int> wait_count; // # of threads currently waiting on the sema
1676  pthread_mutex_t mutex;
1677  pthread_cond_t cond;
1678 
1679 #elif defined(NCBI_WIN32_THREADS)
1680  HANDLE sem;
1681 #else
1682  unsigned int max_count;
1683  unsigned int count;
1684 #endif
1685 };
1686 
1687 
1688 #if NCBI_SEMAPHORE_USE_NEW
1689 CSemaphore::CSemaphore(unsigned int init_count, unsigned int max_count)
1690  : m_Max(max_count), m_Count(init_count)
1691 {
1692  _ASSERT(max_count != 0);
1693  _ASSERT(init_count <= max_count);
1694 }
1695 #else
1696 CSemaphore::CSemaphore(unsigned int init_count, unsigned int max_count)
1697 {
1698 #if defined(NCBI_WIN32_THREADS)
1699  // On Windows max_count is LONG and can not exceed LONG_MAX.
1700  max_count = min(max_count, (unsigned int)LONG_MAX);
1701 #endif
1702  xncbi_Validate(max_count != 0,
1703  "CSemaphore::CSemaphore() - max_count passed zero");
1704  xncbi_Validate(init_count <= max_count,
1705  "CSemaphore::CSemaphore() - init_count "
1706  "greater than max_count");
1707 
1708  m_Sem = new SSemaphore;
1709  unique_ptr<SSemaphore> auto_sem(m_Sem);
1710 
1711 #if defined(NCBI_POSIX_THREADS)
1712  m_Sem->max_count = max_count;
1713  m_Sem->count = init_count;
1714  m_Sem->wait_count = 0;
1715 
1716 # if defined(NCBI_OS_CYGWIN)
1717  if (pthread_mutex_init(&m_Sem->mutex, 0) != 0) {
1718  memset(&m_Sem->mutex, 0, sizeof(m_Sem->mutex));
1719 # endif /* NCBI_OS_CYGWIN */
1721  pthread_mutex_init(&m_Sem->mutex, 0), 0,
1722  "CSemaphore::CSemaphore() - pthread_mutex_init() failed");
1723 # if defined(NCBI_OS_CYGWIN)
1724  }
1725 # endif /* NCBI_OS_CYGWIN */
1726 
1727 # if defined(NCBI_OS_CYGWIN)
1728  if (pthread_cond_init(&m_Sem->cond, 0) != 0) {
1729  memset(&m_Sem->cond, 0, sizeof(m_Sem->cond));
1730 # endif /* NCBI_OS_CYGWIN */
1732  pthread_cond_init(&m_Sem->cond, 0), 0,
1733  "CSemaphore::CSemaphore() - pthread_cond_init() failed");
1734 # if defined(NCBI_OS_CYGWIN)
1735  }
1736 # endif /* NCBI_OS_CYGWIN */
1737 
1738 #elif defined(NCBI_WIN32_THREADS)
1739  m_Sem->sem = CreateSemaphore(NULL, init_count, max_count, NULL);
1740 #ifdef _DEBUG
1741  if (m_Sem->sem == NULL) {
1742  DWORD dwErr = GetLastError();
1743  ERR_POST(Error << "GetLastError returns " << dwErr);
1744  }
1745 #endif
1746  xncbi_Validate(m_Sem->sem != NULL,
1747  "CSemaphore::CSemaphore() - CreateSemaphore() failed");
1748 #else
1749  m_Sem->max_count = max_count;
1750  m_Sem->count = init_count;
1751 #endif
1752 
1753  auto_sem.release();
1754 }
1755 #endif
1756 
1757 
1759 {
1760 #if NCBI_SEMAPHORE_USE_NEW
1761 #else
1762 #if defined(NCBI_POSIX_THREADS)
1763  _ASSERT(m_Sem->wait_count == 0);
1764  xncbi_VerifyAndErrorReport(pthread_mutex_destroy(&m_Sem->mutex) == 0);
1765  xncbi_VerifyAndErrorReport(pthread_cond_destroy(&m_Sem->cond) == 0);
1766 
1767 #elif defined(NCBI_WIN32_THREADS)
1768  xncbi_VerifyAndErrorReport( CloseHandle(m_Sem->sem) );
1769 #endif
1770 
1771  delete m_Sem;
1772 #endif
1773 }
1774 
1775 #if NCBI_SEMAPHORE_USE_NEW
1776 inline
1777 bool CSemaphore::x_TryAcquire(void)
1778 {
1779  if (m_Count > 0) {
1780  --m_Count;
1781  return true;
1782  }
1783  return false;
1784 }
1785 #endif
1786 
1788 {
1789 #if NCBI_SEMAPHORE_USE_NEW
1790  unique_lock<mutex> lck(m_Mtx);
1791  while (!x_TryAcquire()) {
1792  m_Cv.wait(lck);
1793  }
1794 #else
1795 #if defined(NCBI_POSIX_THREADS)
1797  pthread_mutex_lock(&m_Sem->mutex), 0,
1798  "CSemaphore::Wait() - pthread_mutex_lock() failed");
1799 
1800  if (m_Sem->count != 0) {
1801  m_Sem->count--;
1802  }
1803  else {
1804  m_Sem->wait_count++;
1805  do {
1806  int status = pthread_cond_wait(&m_Sem->cond, &m_Sem->mutex);
1807  if (status != 0 && status != EINTR) {
1809  pthread_mutex_unlock(&m_Sem->mutex), 0,
1810  "CSemaphore::Wait() - pthread_cond_wait() and "
1811  "pthread_mutex_unlock() failed");
1812  xncbi_Validate(0,
1813  "CSemaphore::Wait() - "
1814  "pthread_cond_wait() failed");
1815  }
1816  } while (m_Sem->count == 0);
1817  m_Sem->wait_count--;
1818  m_Sem->count--;
1819  }
1820 
1822  pthread_mutex_unlock(&m_Sem->mutex), 0,
1823  "CSemaphore::Wait() - pthread_mutex_unlock() failed");
1824 
1825 #elif defined(NCBI_WIN32_THREADS)
1826  xncbi_Validate(WaitForSingleObject(m_Sem->sem, INFINITE) == WAIT_OBJECT_0,
1827  "CSemaphore::Wait() - WaitForSingleObject() failed");
1828 
1829 #else
1830  xncbi_Validate(m_Sem->count != 0,
1831  "CSemaphore::Wait() - "
1832  "wait with zero count in one-thread mode(?!)");
1833  m_Sem->count--;
1834 #endif
1835 #endif
1836 }
1837 
1838 #if defined(NCBI_NO_THREADS)
1839 # define NCBI_THREADS_ARG(arg)
1840 #else
1841 # define NCBI_THREADS_ARG(arg) arg
1842 #endif
1843 
1844 bool CSemaphore::TryWait(unsigned int NCBI_THREADS_ARG(timeout_sec),
1845  unsigned int NCBI_THREADS_ARG(timeout_nsec))
1846 {
1847 #if NCBI_SEMAPHORE_USE_NEW
1848  unique_lock<mutex> lck(m_Mtx);
1849 #if defined(NCBI_NO_THREADS)
1850  return x_TryAcquire();
1851 #else
1852  if (x_TryAcquire()) {
1853  return true;
1854  }
1855  if (timeout_sec == 0 && timeout_nsec == 0) {
1856  return x_TryAcquire();
1857  }
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) {
1863  return false;
1864  }
1865  }
1866  return true;
1867 #endif
1868 #else
1869 #if defined(NCBI_POSIX_THREADS)
1871  pthread_mutex_lock(&m_Sem->mutex), 0,
1872  "CSemaphore::TryWait() - pthread_mutex_lock() failed");
1873 
1874  bool retval = false;
1875  if (m_Sem->count != 0) {
1876  m_Sem->count--;
1877  retval = true;
1878  }
1879  else if (timeout_sec > 0 || timeout_nsec > 0) {
1880 # ifdef NCBI_OS_SOLARIS
1881  // arbitrary limit of 100Ms (~3.1 years) -- supposedly only for
1882  // native threads, but apparently also for POSIX threads :-/
1883  if (timeout_sec >= 100 * 1000 * 1000) {
1884  timeout_sec = 100 * 1000 * 1000;
1885  timeout_nsec = 0;
1886  }
1887 # endif
1888  static const unsigned int kBillion = 1000 * 1000 * 1000;
1889  struct timeval now;
1890  struct timespec timeout = { 0, 0 };
1891  gettimeofday(&now, 0);
1892  // timeout_sec added below to avoid overflow
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;
1898  }
1899  if (timeout_sec > (unsigned int)(kMax_Int - timeout.tv_sec)) {
1900  // Max out rather than overflowing
1901  timeout.tv_sec = kMax_Int;
1902  timeout.tv_nsec = kBillion - 1;
1903  } else {
1904  timeout.tv_sec += timeout_sec;
1905  }
1906 
1907  m_Sem->wait_count++;
1908  do {
1909  int status = pthread_cond_timedwait(&m_Sem->cond, &m_Sem->mutex,
1910  &timeout);
1911  if (status == ETIMEDOUT) {
1912  break;
1913  } else if (status != 0 && status != EINTR) {
1914  // EINVAL, presumably?
1916  pthread_mutex_unlock(&m_Sem->mutex), 0,
1917  "CSemaphore::TryWait() - pthread_cond_timedwait() and "
1918  "pthread_mutex_unlock() failed");
1919  xncbi_Validate(0, "CSemaphore::TryWait() - "
1920  "pthread_cond_timedwait() failed");
1921  }
1922  } while (m_Sem->count == 0);
1923  m_Sem->wait_count--;
1924  if (m_Sem->count != 0) {
1925  m_Sem->count--;
1926  retval = true;
1927  }
1928  }
1929 
1931  pthread_mutex_unlock(&m_Sem->mutex), 0,
1932  "CSemaphore::TryWait() - pthread_mutex_unlock() failed");
1933 
1934  return retval;
1935 
1936 #elif defined(NCBI_WIN32_THREADS)
1937  DWORD timeout_msec; // DWORD == unsigned long
1938  if (timeout_sec >= kMax_ULong / 1000) {
1939  timeout_msec = kMax_ULong;
1940  } else {
1941  timeout_msec = timeout_sec * 1000 + timeout_nsec / (1000 * 1000);
1942  }
1943  DWORD res = WaitForSingleObject(m_Sem->sem, timeout_msec);
1944  xncbi_Validate(res == WAIT_OBJECT_0 || res == WAIT_TIMEOUT,
1945  "CSemaphore::TryWait() - WaitForSingleObject() failed");
1946  return (res == WAIT_OBJECT_0);
1947 
1948 #else
1949  if (m_Sem->count == 0)
1950  return false;
1951  m_Sem->count--;
1952  return true;
1953 #endif
1954 #endif
1955 }
1956 
1957 
1958 bool CSemaphore::TryWait(const CTimeout& timeout)
1959 {
1960  if (timeout.IsInfinite()) {
1961  Wait();
1962  return true;
1963  }
1964 
1965  unsigned int s, ns;
1966  timeout.GetNano(&s, &ns);
1967  return TryWait(s, ns);
1968 }
1969 
1970 
1971 void CSemaphore::Post(unsigned int count)
1972 {
1973  if (count == 0)
1974  return;
1975 
1976 #if NCBI_SEMAPHORE_USE_NEW
1977  unique_lock<mutex> lck( m_Mtx);
1978  xncbi_Validate(m_Count <= kMax_UInt - count && m_Count + count <= m_Max,
1979  "CSemaphore::Post() - attempt to exceed max_count");
1980  m_Count += count;
1981  m_Cv.notify_all();
1982 #else
1983 #if defined (NCBI_POSIX_THREADS)
1985  pthread_mutex_lock(&m_Sem->mutex), 0,
1986  "CSemaphore::Post() - pthread_mutex_lock() failed");
1987 
1988  if (m_Sem->count > kMax_UInt - count ||
1989  m_Sem->count + count > m_Sem->max_count) {
1991  pthread_mutex_unlock(&m_Sem->mutex), 0,
1992  "CSemaphore::Post() - attempt to exceed max_count and "
1993  "pthread_mutex_unlock() failed");
1994  xncbi_Validate(false,
1995  "CSemaphore::Post() - attempt to exceed max_count");
1996  }
1997 
1998  // Signal some (or all) of the threads waiting on this semaphore
1999  int err_code = 0;
2000  if (m_Sem->count + count >= m_Sem->wait_count) {
2001  err_code = pthread_cond_broadcast(&m_Sem->cond);
2002  } else {
2003  // Do not use broadcast here to avoid waking up more threads
2004  // than really needed...
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);
2009  break;
2010  }
2011  }
2012  }
2013 
2014  // Success
2015  if (err_code == 0) {
2016  m_Sem->count += count;
2018  pthread_mutex_unlock(&m_Sem->mutex), 0,
2019  "CSemaphore::Post() - pthread_mutex_unlock() failed");
2020  return;
2021  }
2022 
2023  // Error
2025  pthread_mutex_unlock(&m_Sem->mutex), 0,
2026  "CSemaphore::Post() - pthread_cond_signal/broadcast() and "
2027  "pthread_mutex_unlock() failed");
2028  xncbi_Validate(0,
2029  "CSemaphore::Post() - "
2030  "pthread_cond_signal/broadcast() failed");
2031 
2032 #elif defined(NCBI_WIN32_THREADS)
2034  ReleaseSemaphore(m_Sem->sem, count, NULL),
2035  "CSemaphore::Post() - ReleaseSemaphore() failed");
2036 
2037 #else
2038  xncbi_Validate(m_Sem->count + count <= m_Sem->max_count,
2039  "CSemaphore::Post() - attempt to exceed max_count");
2040  m_Sem->count += count;
2041 #endif
2042 #endif
2043 }
2044 
2045 
2046 // All methods must be not inline to avoid unwanted optimizations by compiler
2047 void
2049 {
2050 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2051  AcquireSRWLockShared(&m_Lock);
2052 #else
2053  while (m_LockCount.Add(1) > kWriteLockValue) {
2054  m_LockCount.Add(-1);
2055  m_WriteLock.Lock();
2056  m_WriteLock.Unlock();
2057  }
2058 #endif
2059 }
2060 
2061 void
2063 {
2064 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2065  ReleaseSRWLockShared(&m_Lock);
2066 #else
2067  m_LockCount.Add(-1);
2068 #endif
2069 }
2070 
2071 void
2073 {
2074 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2075  AcquireSRWLockExclusive(&m_Lock);
2076 #else
2077  m_WriteLock.Lock();
2079  while (m_LockCount.Get() != kWriteLockValue) {
2080  NCBI_SCHED_YIELD();
2081  }
2082 #endif
2083 }
2084 
2085 void
2087 {
2088 #if defined(NCBI_WIN32_THREADS) && defined(NCBI_FASTRWLOCK_USE_NEW)
2089  ReleaseSRWLockExclusive(&m_Lock);
2090 #else
2092  m_WriteLock.Unlock();
2093 #endif
2094 }
2095 
2096 
2098 {}
2099 
2101 {}
2102 
2103 
2105 {
2106  if (m_Lock) {
2107  ReleaseLock();
2108  }
2109 }
2110 
2111 void
2113 {
2114  m_Factory->DeleteHolder(this);
2115 }
2116 
2117 void
2119 {
2120  TListenersList listeners;
2121 
2122  m_ObjLock.Lock();
2123  listeners = m_Listeners;
2124  m_ObjLock.Unlock();
2125 
2126  NON_CONST_ITERATE(TListenersList, it, listeners) {
2127  TRWLockHolder_ListenerRef lstn(it->Lock());
2128  if (lstn.NotNull()) {
2129  lstn->OnLockAcquired(this);
2130  }
2131  }
2132 }
2133 
2134 void
2136 {
2137  TListenersList listeners;
2138 
2139  m_ObjLock.Lock();
2140  listeners = m_Listeners;
2141  m_ObjLock.Unlock();
2142 
2143  NON_CONST_ITERATE(TListenersList, it, listeners) {
2144  TRWLockHolder_ListenerRef lstn(it->Lock());
2145  if (lstn.NotNull()) {
2146  lstn->OnLockReleased(this);
2147  }
2148  }
2149 }
2150 
2151 
2152 /// Default implementation of IRWLockHolder_Factory.
2153 /// Essentially pool of CRWLockHolder objects.
2155 {
2156 public:
2157  CRWLockHolder_Pool(void);
2158  virtual ~CRWLockHolder_Pool(void);
2159 
2160  /// Obtain new CRWLockHolder object for given CYieldingRWLock and
2161  /// necessary lock type.
2163  ERWLockType typ);
2164 
2165  /// Free unnecessary (and unreferenced by anybody) CRWLockHolder object
2166  virtual void DeleteHolder(CRWLockHolder* holder);
2167 
2168 private:
2172 
2173  /// Implementation of CRWLockHolder objects pool
2175 };
2176 
2177 
2178 inline
2180  : m_Pool(THolderPoolFactory(this))
2181 {}
2182 
2184 {}
2185 
2188 {
2189  CRWLockHolder* holder = m_Pool.Get();
2190  holder->Init(lock, typ);
2191  return holder;
2192 }
2193 
2194 void
2196 {
2197  _ASSERT(!holder->Referenced());
2198 
2199  holder->Reset();
2200  m_Pool.Return(holder);
2201 }
2202 
2203 
2204 /// Default CRWLockHolder pool used in CYieldingRWLock
2206 
2207 
2209  : m_Factory(factory)
2210 {
2211  if (!m_Factory) {
2212  m_Factory = &s_RWHolderPool.Get();
2213  }
2215 }
2216 
2218 {
2219 #ifdef _DEBUG
2220 # define RWLockFatal Fatal
2221 #else
2222 # define RWLockFatal Critical
2223 #endif
2224 
2225  CSpinGuard guard(m_ObjLock);
2226 
2227  if (m_Locks[eReadLock] + m_Locks[eWriteLock] != 0) {
2229  << "Destroying YieldingRWLock with unreleased locks");
2230  }
2231  if (!m_LockWaits.empty()) {
2233  << "Destroying YieldingRWLock with "
2234  "some locks waiting to acquire");
2235  }
2236 
2237 #undef RWLockFatal
2238 }
2239 
2242 {
2243  int other_type = 1 - lock_type;
2244  TRWLockHolderRef holder(m_Factory->CreateHolder(this, lock_type));
2245 
2246  {{
2247  CSpinGuard guard(m_ObjLock);
2248 
2249  if (m_Locks[other_type] != 0 || !m_LockWaits.empty()
2250  || (lock_type == eWriteLock && m_Locks[lock_type] != 0))
2251  {
2252  m_LockWaits.push_back(holder);
2253  return holder;
2254  }
2255 
2256  ++m_Locks[lock_type];
2257  holder->m_LockAcquired = true;
2258  }}
2259 
2260  holder->x_OnLockAcquired();
2261  return holder;
2262 }
2263 
2264 void
2266 {
2267  // Extract one lock holder from next_holders to avoid unnecessary memory
2268  // allocations in deque in case when we grant lock to only one next holder
2269  // (the majority of cases).
2270  TRWLockHolderRef first_next;
2271  THoldersList next_holders;
2272  bool save_acquired;
2273 
2274  {{
2275  CSpinGuard guard(m_ObjLock);
2276 
2277  save_acquired = holder->m_LockAcquired;
2278  if (save_acquired) {
2279  --m_Locks[holder->m_Type];
2280  holder->m_LockAcquired = false;
2281 
2282  if (m_Locks[eReadLock] + m_Locks[eWriteLock] == 0
2283  && !m_LockWaits.empty())
2284  {
2285  first_next = m_LockWaits.front();
2286  m_LockWaits.pop_front();
2287  ERWLockType next_type = first_next->m_Type;
2288  first_next->m_LockAcquired = true;
2289  ++m_Locks[next_type];
2290 
2291  while (next_type == eReadLock && !m_LockWaits.empty()) {
2292  TRWLockHolderRef next_hldr = m_LockWaits.front();
2293  if (next_hldr->m_Type != next_type)
2294  break;
2295 
2296  next_hldr->m_LockAcquired = true;
2297  ++m_Locks[next_type];
2298  next_holders.push_back(next_hldr);
2299  m_LockWaits.pop_front();
2300  }
2301  }
2302  }
2303  else {
2304  THoldersList::iterator it
2305  = find(m_LockWaits.begin(), m_LockWaits.end(), holder);
2306  if (it != m_LockWaits.end()) {
2307  m_LockWaits.erase(it);
2308  }
2309  }
2310  }}
2311 
2312  if (save_acquired) {
2313  holder->x_OnLockReleased();
2314  }
2315  if (first_next.NotNull()) {
2316  first_next->x_OnLockAcquired();
2317  }
2318  NON_CONST_ITERATE(THoldersList, it, next_holders) {
2319  (*it)->x_OnLockAcquired();
2320  }
2321 }
2322 
2323 
2324 // All methods must be not inline to avoid unwanted optimizations by compiler
2325 void
2327 {
2328 retry:
2329  while (m_Value != NULL)
2330  NCBI_SCHED_YIELD();
2331  if (SwapPointers(&m_Value, (void*)1) != NULL)
2332  goto retry;
2333 }
2334 
2335 bool
2337 {
2338  return SwapPointers(&m_Value, (void*)1) == NULL;
2339 }
2340 
2341 void
2343 {
2344 #ifdef _DEBUG
2346 #else
2347  m_Value = NULL;
2348 #endif
2349 }
2350 
2351 
2352 
2353 
2354 /////////////////////////////////////////////////////////////////////////////
2355 // CONDITION VARIABLE
2356 //
2357 
2359 {
2360  return true;
2361 }
2362 
2363 
2365 #if defined(NCBI_THREADS)
2366  : m_WaitCounter(0),
2367  m_WaitMutex(NULL)
2368 #endif // defined(NCBI_THREADS)
2369 {
2370 #if defined(NCBI_THREADS)
2371 #if defined(NCBI_OS_MSWIN)
2372  InitializeConditionVariable(&m_ConditionVar);
2373 #else
2374  int res = pthread_cond_init(&m_ConditionVar, NULL);
2375  switch (res) {
2376  case 0:
2377  break;
2378  case EAGAIN:
2379  NCBI_THROW(CConditionVariableException, eInvalidValue,
2380  "CConditionVariable: not enough resources");
2381  case ENOMEM:
2382  NCBI_THROW(CConditionVariableException, eInvalidValue,
2383  "CConditionVariable: not enough memory");
2384  case EBUSY:
2385  NCBI_THROW(CConditionVariableException, eInvalidValue,
2386  "CConditionVariable: attempt to reinitialize"
2387  " already used variable");
2388  case EINVAL:
2389  NCBI_THROW(CConditionVariableException, eInvalidValue,
2390  "CConditionVariable: invalid attribute value");
2391  default:
2392  NCBI_THROW(CConditionVariableException, eInvalidValue,
2393  "CConditionVariable: unknown error");
2394  }
2395 #endif
2396 #endif // defined(NCBI_THREADS)
2397 }
2398 
2399 
2401 {
2402 #if defined(NCBI_THREADS)
2403 #if !defined(NCBI_OS_MSWIN)
2404  int res = pthread_cond_destroy(&m_ConditionVar);
2405  switch (res) {
2406  case 0:
2407  return;
2408  case EBUSY:
2409  ERR_POST(Critical <<
2410  "~CConditionVariable: attempt to destroy variable that"
2411  " is currently in use");
2412  break;
2413  case EINVAL:
2414  ERR_POST(Critical <<
2415  "~CConditionVariable: invalid condition variable");
2416  break;
2417  default:
2418  ERR_POST(Critical <<
2419  "~CConditionVariable: unknown error");
2420  }
2421  NCBI_TROUBLE("CConditionVariable: pthread_cond_destroy() failed");
2422 #endif
2423 #endif // defined(NCBI_THREADS)
2424 }
2425 
2426 
2427 #if defined(NCBI_THREADS)
2428 template <class T>
2430 {
2431 public:
2432  typedef T* TPointer;
2433 
2435  TPointer volatile& guarded_ptr,
2436  TPointer new_ptr)
2437  : m_AtomicCounter (atomic_counter),
2438  m_GuardedPtr (guarded_ptr),
2439  m_SavedPtr (new_ptr)
2440  {
2441  _ASSERT(new_ptr != NULL);
2442  m_AtomicCounter.Add(1);
2443  // If two threads enter the guard simultaneously, and with different
2444  // pointers, then we may not detect this. There is chance however that
2445  // we 'll detect it -- in DEBUG mode only -- in dtor. And if not, then:
2446  // Oh well. We don't promise 100% protection. It is good enough
2447  // though, and what's important -- no false negatives.
2448  m_GuardedPtr = new_ptr;
2449  }
2450 
2452  {
2453  if ((m_SavedPtr == NULL) ||
2455  NCBI_TROUBLE("Different pointers detected");
2456  m_SavedPtr = NULL;
2457  return true;
2458  }
2459  return false;
2460  }
2461 
2464  if (m_AtomicCounter.Add(-1) == 0) {
2465  // If other thread goes into the guard at this very moment, then
2466  // this thread can NULL up the protection, and won't detect
2467  // any same-ptr cases until after the counter goes back to zero.
2468  // Oh well. We don't promise 100% protection. It is good enough
2469  // though, and what's important -- no false negatives.
2470  m_GuardedPtr = NULL;
2471  }
2472  }
2473 
2474 private:
2478 };
2479 
2480 
2483 {
2484  if ( mutex_guard.DetectedDifferentPointers() ) {
2485  NCBI_THROW(CConditionVariableException, eMutexDifferent,
2486  "WaitForSignal called with different mutexes");
2487  }
2488 }
2489 
2490 
2492 (SSystemFastMutex& mutex, const CDeadline& deadline)
2493 {
2495  (m_WaitCounter, m_WaitMutex, &mutex);
2496  s_ThrowIfDifferentMutexes(mutex_guard);
2497 
2498 #if defined(NCBI_OS_MSWIN)
2499  DWORD timeout_msec = deadline.IsInfinite() ?
2500  INFINITE : deadline.GetRemainingTime().GetAsMilliSeconds();
2501 #if defined(NCBI_FASTMUTEX_USE_NEW)
2502  BOOL res = SleepConditionVariableSRW(&m_ConditionVar, &mutex.m_Handle, timeout_msec, 0);
2503 #else
2504  BOOL res = SleepConditionVariableCS(&m_ConditionVar, &mutex.m_Handle, timeout_msec);
2505 #endif
2506  s_ThrowIfDifferentMutexes(mutex_guard);
2507 
2508  if ( res )
2509  return true;
2510 
2511  DWORD err_code = GetLastError();
2512  if (err_code == ERROR_TIMEOUT || err_code == WAIT_TIMEOUT)
2513  return false;
2514 
2515  NCBI_THROW(CConditionVariableException, eInvalidValue,
2516  "WaitForSignal failed");
2517 #else
2518  int res;
2519  if (deadline.IsInfinite()) {
2520  res = pthread_cond_wait(&m_ConditionVar, &mutex.m_Handle);
2521  } else {
2522  struct timespec ts;
2523  time_t s;
2524  unsigned int ns;
2525  deadline.GetExpirationTime(&s, &ns);
2526  ts.tv_sec = s;
2527  ts.tv_nsec = ns;
2528  res = pthread_cond_timedwait(&m_ConditionVar, &mutex.m_Handle, &ts);
2529  }
2530  s_ThrowIfDifferentMutexes(mutex_guard);
2531 
2532  if (res != 0) {
2533  switch (res) {
2534  case ETIMEDOUT:
2535  return false;
2536  case EINVAL:
2537  NCBI_THROW(CConditionVariableException, eInvalidValue,
2538  "WaitForSignal failed: invalid paramater");
2539  case EPERM:
2541  "WaitForSignal: mutex not owned by the current thread");
2542  default:
2543  NCBI_THROW(CConditionVariableException, eInvalidValue,
2544  "WaitForSignal failed: unknown error");
2545  }
2546  }
2547 #endif
2548 
2549  return true;
2550 }
2551 #endif // defined(NCBI_THREADS)
2552 
2553 
2555  const CDeadline& deadline)
2556 {
2557 #if defined(NCBI_THREADS)
2558  SSystemMutex& sys_mtx = mutex;
2559  if (sys_mtx.m_Count != 1) {
2560  NCBI_THROW(CConditionVariableException, eMutexLockCount,
2561  "WaitForSignal: mutex lock count not 1");
2562  }
2563 #if defined(NCBI_OS_MSWIN)
2564  if ( sys_mtx.m_Owner != GetCurrentThreadSystemID() ) {
2566  "WaitForSignal: mutex not owned by the current thread");
2567  }
2568 #endif
2569  sys_mtx.Unlock(SSystemFastMutex::ePseudo);
2570  bool res = x_WaitForSignal(sys_mtx.m_Mutex, deadline);
2571  sys_mtx.Lock(SSystemFastMutex::ePseudo);
2572  return res;
2573 #else
2574  return true;
2575 #endif // defined(NCBI_THREADS)
2576 }
2577 
2578 
2580  const CDeadline& deadline)
2581 {
2582 #if defined(NCBI_THREADS)
2583  SSystemFastMutex& sys_mtx = mutex;
2584  sys_mtx.Unlock(SSystemFastMutex::ePseudo);
2585  bool res = x_WaitForSignal(sys_mtx, deadline);
2586  sys_mtx.Lock(SSystemFastMutex::ePseudo);
2587  return res;
2588 #else
2589  return true;
2590 #endif // defined(NCBI_THREADS)
2591 }
2592 
2593 
2595 {
2596 #if defined(NCBI_THREADS)
2597 #if defined(NCBI_OS_MSWIN)
2598  WakeConditionVariable(&m_ConditionVar);
2599 #else
2600  int res = pthread_cond_signal(&m_ConditionVar);
2601  if (res != 0) {
2602  switch (res) {
2603  case EINVAL:
2604  NCBI_THROW(CConditionVariableException, eInvalidValue,
2605  "SignalSome failed: invalid paramater");
2606  default:
2607  NCBI_THROW(CConditionVariableException, eInvalidValue,
2608  "SignalSome failed: unknown error");
2609  }
2610  }
2611 #endif
2612 #endif // defined(NCBI_THREADS)
2613 }
2614 
2615 
2617 {
2618 #if defined(NCBI_THREADS)
2619 #if defined(NCBI_OS_MSWIN)
2620  WakeAllConditionVariable(&m_ConditionVar);
2621 #else
2622  int res = pthread_cond_broadcast(&m_ConditionVar);
2623  if (res != 0) {
2624  switch (res) {
2625  case EINVAL:
2626  NCBI_THROW(CConditionVariableException, eInvalidValue,
2627  "SignalAll failed: invalid paramater");
2628  default:
2629  NCBI_THROW(CConditionVariableException, eInvalidValue,
2630  "SignalAll failed: unknown error");
2631  }
2632  }
2633 #endif
2634 #endif // defined(NCBI_THREADS)
2635 }
2636 
2637 
2639 {
2640  switch ( GetErrCode() ) {
2641  case eInvalidValue: return "eInvalidValue";
2642  case eMutexLockCount: return "eMutexLockCount";
2643  case eMutexOwner: return "eMutexOwner";
2644  case eMutexDifferent: return "eMutexDifferent";
2645  case eUnsupported: return "eUnsupported";
2646  default: return CException::GetErrCodeString();
2647  }
2648 }
2649 
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CConditionVariableException –.
Definition: ncbimtx.hpp:1525
CDeadline.
Definition: ncbitime.hpp:1830
CFastMutex –.
Definition: ncbimtx.hpp:667
CFastMutex m_Mutex
Definition: ncbimtx.cpp:625
CPthreadCond m_Rcond
Definition: ncbimtx.cpp:623
CPthreadCond m_Wcond
Definition: ncbimtx.cpp:624
CInternalRWLock(void)
Definition: ncbimtx.cpp:630
CMutexException –.
Definition: ncbimtx.hpp:230
CMutex –.
Definition: ncbimtx.hpp:749
Object factory for simple creation and deletion of the object with one parameter passed to object's c...
Definition: obj_pool.hpp:324
~CPthreadCond(void)
Definition: ncbimtx.cpp:589
CPthreadCond(void)
Definition: ncbimtx.cpp:585
bool m_Initialized
Definition: ncbimtx.cpp:601
pthread_cond_t m_Handle
Definition: ncbimtx.cpp:600
volatile TPointer & m_GuardedPtr
Definition: ncbimtx.cpp:2476
CAtomicCounter & m_AtomicCounter
Definition: ncbimtx.cpp:2475
CQuickAndDirtySamePointerGuard(CAtomicCounter &atomic_counter, TPointer volatile &guarded_ptr, TPointer new_ptr)
Definition: ncbimtx.cpp:2434
Default implementation of IRWLockHolder_Factory.
Definition: ncbimtx.cpp:2155
CRWLockHolder_Pool(void)
Definition: ncbimtx.cpp:2179
THolderPool m_Pool
Implementation of CRWLockHolder objects pool.
Definition: ncbimtx.cpp:2174
CObjFactory_NewParam< CRWLockHolder, CRWLockHolder_Pool * > THolderPoolFactory
Definition: ncbimtx.cpp:2170
virtual ~CRWLockHolder_Pool(void)
Definition: ncbimtx.cpp:2183
CObjPool< CRWLockHolder, THolderPoolFactory > THolderPool
Definition: ncbimtx.cpp:2171
virtual void DeleteHolder(CRWLockHolder *holder)
Free unnecessary (and unreferenced by anybody) CRWLockHolder object.
Definition: ncbimtx.cpp:2195
virtual CRWLockHolder * CreateHolder(CYieldingRWLock *lock, ERWLockType typ)
Obtain new CRWLockHolder object for given CYieldingRWLock and necessary lock type.
Definition: ncbimtx.cpp:2187
Holder of the lock inside CYieldingRWLock.
Definition: ncbimtx.hpp:1230
CRef –.
Definition: ncbiobj.hpp:618
CSafeStatic<>::
CTimeout – Timeout interval.
Definition: ncbitime.hpp:1693
Read/write lock without blocking calls.
Definition: ncbimtx.hpp:1316
Interface for factory creating CRWLockHolder objects.
Definition: ncbimtx.hpp:1210
static uch flags
#define T(s)
Definition: common.h:230
const char * file_name[]
#define false
Definition: bool.h:36
static const char * expected[]
Definition: bcp.c:42
int BOOL
Definition: sybdb.h:150
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:278
TValue Get(void) const THROWS_NONE
Get atomic counter value.
Definition: ncbicntr.hpp:168
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
#define NCBI_TROUBLE(mess)
Definition: ncbidbg.hpp:129
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
void Critical(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1203
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
TErrCode GetErrCode(void) const
Definition: ncbiexpt.hpp:1493
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
static mode_t MakeModeT(TMode user_mode, TMode group_mode, TMode other_mode, TSpecialModeBits special)
Construct mode_t value from permission modes.
Definition: ncbifile.cpp:1193
unsigned int mode_t
Definition: ncbifile.hpp:84
@ fRead
Read permission.
Definition: ncbifile.hpp:1153
@ fWrite
Write permission.
Definition: ncbifile.hpp:1152
bool NotNull(void) const THROWS_NONE
Check if pointer is not null – same effect as NotEmpty().
Definition: ncbiobj.hpp:744
bool Referenced(void) const THROWS_NONE
Check if object is referenced.
Definition: ncbiobj.hpp:468
#define kMax_Int
Definition: ncbi_limits.h:184
#define kMax_UInt
Definition: ncbi_limits.h:185
void Return(TObjType *obj)
Return object to the pool for future use.
Definition: obj_pool.hpp:121
TObjType * Get(void)
Get object from the pool, create if necessary.
Definition: obj_pool.hpp:101
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define NCBI_SCHED_YIELD()
volatile unsigned int m_WaitingWriters
Number of writers waiting; zero if not keeping track.
Definition: ncbimtx.hpp:1047
CConditionVariable(void)
Definition: ncbimtx.cpp:2364
ERWLockType
Type of locking provided by CYieldingRWLock.
Definition: ncbimtx.hpp:1180
ELockSemantics
This is for condition variables.
Definition: ncbimtx.hpp:288
unique_ptr< CInternalRWLock > m_RW
Platform-dependent RW-lock data.
Definition: ncbimtx.hpp:1044
struct SSemaphore * m_Sem
System-specific semaphore data.
Definition: ncbimtx.hpp:1418
bool TryLock(void)
Attempt to lock the mutex and return TRUE if it succeeded or FALSE if mutex is locked by other thread...
Definition: ncbimtx.cpp:2336
CSemaphore(unsigned int init_count, unsigned int max_count)
Constructor.
Definition: ncbimtx.cpp:1696
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.
Definition: ncbimtx.cpp:500
void ReadUnlock(void)
Release read lock.
Definition: ncbimtx.cpp:2062
virtual ~CRWLockHolder(void)
Definition: ncbimtx.cpp:2104
~CConditionVariable(void)
Definition: ncbimtx.cpp:2400
void SignalSome(void)
Wake at least one of the threads that are currently waiting on this condition variable (if any thread...
Definition: ncbimtx.cpp:2594
ERWLockType m_Type
Type of lock held.
Definition: ncbimtx.hpp:1290
static bool IsSupported(void)
Definition: ncbimtx.cpp:2358
void Wait(void)
Wait on semaphore.
Definition: ncbimtx.cpp:1787
CFastMutex m_WriteLock
Mutex implementing write lock.
Definition: ncbimtx.hpp:1169
void ReadLock(void)
Read lock.
Definition: ncbimtx.cpp:863
bool TryReadLock(void)
Try read lock.
Definition: ncbimtx.cpp:976
void Reset(void)
Reset holder to be able to use it later (after calling Init() )
CSpinLock m_ObjLock
Main locking mutex for object operations.
Definition: ncbimtx.hpp:1359
TFlags m_Flags
Configuration flags.
Definition: ncbimtx.hpp:1043
void WriteUnlock(void)
Release write lock.
Definition: ncbimtx.cpp:2086
TRWLockHolderRef AcquireLock(ERWLockType lock_type)
General method to request read or write lock.
Definition: ncbimtx.cpp:2241
THoldersList m_LockWaits
Queue for waiting lock requests.
Definition: ncbimtx.hpp:1363
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.
Definition: ncbimtx.hpp:1048
volatile long m_Count
Number of readers (if >0) or writers (if <0)
Definition: ncbimtx.hpp:1046
SSystemFastMutex *volatile m_WaitMutex
Definition: ncbimtx.hpp:1506
IRWLockHolder_Factory * m_Factory
Factory created the holder.
Definition: ncbimtx.hpp:1286
bool TryWriteLock(void)
Try write lock.
Definition: ncbimtx.cpp:1320
bool x_MayAcquireForReading(TThreadSystemID self_id)
Definition: ncbimtx.cpp:725
bool x_WaitForSignal(SSystemFastMutex &mutex, const CDeadline &timeout)
Definition: ncbimtx.cpp:2492
virtual void DeleteThis(void)
"Delete" this holder after last reference was removed.
Definition: ncbimtx.cpp:2112
TListenersList m_Listeners
List of holder listeners.
Definition: ncbimtx.hpp:1296
IRWLockHolder_Factory * m_Factory
Factory creating CRWLockHolder objects.
Definition: ncbimtx.hpp:1357
void x_OnLockReleased(void)
Callback called at the moment when lock is released.
Definition: ncbimtx.cpp:2135
bool WaitForSignal(CMutex &mutex, const CDeadline &deadline=CDeadline::eInfinite)
Release mutex and lock the calling thread until the condition variable is signalled.
Definition: ncbimtx.cpp:2554
void SignalAll(void)
Wake all threads that are currently waiting on the condition variable.
Definition: ncbimtx.cpp:2616
pthread_mutex_t TSystemMutex
Define a platform independent system mutex.
Definition: ncbimtx.hpp:119
CAtomicCounter_WithAutoInit m_WaitCounter
Definition: ncbimtx.hpp:1505
CRWLock(TFlags flags=0)
Constructor.
Definition: ncbimtx.cpp:659
volatile TThreadSystemID m_Owner
Writer ID, one of the readers ID.
Definition: ncbimtx.hpp:1045
void Init(CYieldingRWLock *lock, ERWLockType typ)
Initialize holder for given CYieldingRWLock and necessary lock type.
void Unlock(void)
Unlock the mutex.
Definition: ncbimtx.cpp:2342
void ReadLock(void)
Acquire read lock.
Definition: ncbimtx.cpp:2048
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.
Definition: ncbimtx.hpp:1167
void x_ReleaseLock(CRWLockHolder *holder)
Main implementation releasing lock.
Definition: ncbimtx.cpp:2265
deque< TRWLockHolderRef > THoldersList
Definition: ncbimtx.hpp:1350
void Lock(void)
Lock the mutex.
Definition: ncbimtx.cpp:2326
list< TRWLockHolder_ListenerWeakRef > TListenersList
Definition: ncbimtx.hpp:1283
void x_OnLockAcquired(void)
Callback called at the moment when lock is granted.
Definition: ncbimtx.cpp:2118
void WriteLock(void)
Write lock.
Definition: ncbimtx.cpp:1201
int m_Locks[2]
Number of locks granted on this object by type.
Definition: ncbimtx.hpp:1361
CYieldingRWLock * m_Lock
Lock object the holder is assigned to.
Definition: ncbimtx.hpp:1288
void WriteLock(void)
Acquire write lock.
Definition: ncbimtx.cpp:2072
CONDITION_VARIABLE m_ConditionVar
Definition: ncbimtx.hpp:1501
pthread_t TThreadSystemID
Define platform-dependent thread ID type.
~CYieldingRWLock(void)
It is fatal error to destroy the object while some locks are pending.
Definition: ncbimtx.cpp:2217
bool TryWait(unsigned int timeout_sec=0, unsigned int timeout_nsec=0)
Timed wait.
Definition: ncbimtx.cpp:1844
virtual ~IRWLockHolder_Factory(void)
Definition: ncbimtx.cpp:2100
~CSemaphore(void)
Destructor.
Definition: ncbimtx.cpp:1758
void Post(unsigned int count=1)
Increment the semaphore by "count".
Definition: ncbimtx.cpp:1971
CSpinLock m_ObjLock
Mutex for operating listeners.
Definition: ncbimtx.hpp:1294
int TFlags
binary OR of EFlags
Definition: ncbimtx.hpp:961
CYieldingRWLock(IRWLockHolder_Factory *factory=NULL)
Create read/write lock with custom holders factory.
Definition: ncbimtx.cpp:2208
~CRWLock(void)
Destructor.
Definition: ncbimtx.cpp:679
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbimtx.cpp:2638
void *volatile m_Value
Flag showing if mutex is locked (non-NULL value) or unlocked (NULL value).
Definition: ncbimtx.hpp:876
void Unlock(void)
Release mutex with no owner or nesting checks.
bool m_LockAcquired
Flag if lock was acquired.
Definition: ncbimtx.hpp:1292
static TThreadSystemID GetCurrentThreadSystemID(void)
Get the current thread ID.
Definition: ncbimtx.hpp:152
void Unlock(void)
Release the RW-lock.
Definition: ncbimtx.cpp:1558
virtual ~IRWLockHolder_Listener(void)
Definition: ncbimtx.cpp:2097
@ eWriteLock
Definition: ncbimtx.hpp:1182
@ eReadLock
Definition: ncbimtx.hpp:1181
@ fFavorWriters
Forbid further readers from acquiring the lock if any writers are waiting for it, to keep would-be wr...
Definition: ncbimtx.hpp:959
@ eMutexLockCount
Mutex passed to WaitForSignal is not owned by the current thread.
Definition: ncbimtx.hpp:1532
@ eMutexOwner
Different mutexes were supplied for concurrent WaitForSignal operations on this condition variable.
Definition: ncbimtx.hpp:1534
@ eMutexDifferent
Condition variable is not supported on this platform.
Definition: ncbimtx.hpp:1537
@ eInvalidValue
Parameter of WaitForSignal function is invalid.
Definition: ncbimtx.hpp:1530
@ fTrackReaders
Keep track of which threads have read locks.
Definition: ncbimtx.hpp:1041
@ kWriteLockValue
Number in lock count showing that write lock is acquired.
Definition: ncbimtx.hpp:1159
@ eUninitialized
Uninitialized error.
Definition: ncbimtx.hpp:238
@ eTryLock
Attempted lock error.
Definition: ncbimtx.hpp:236
@ eUnlock
Unlock error.
Definition: ncbimtx.hpp:235
@ eLock
Lock error.
Definition: ncbimtx.hpp:234
@ eOwner
Not owned error.
Definition: ncbimtx.hpp:237
CNanoTimeout GetRemainingTime(void) const
Get time left to the expiration.
Definition: ncbitime.cpp:3858
bool IsInfinite() const
Definition: ncbitime.hpp:2730
bool IsZero() const
Definition: ncbitime.cpp:3475
void GetNano(unsigned int *sec, unsigned int *nanosec) const
Get timeout in seconds and nanoseconds.
Definition: ncbitime.cpp:3560
unsigned long GetAsMilliSeconds(void) const
Get as number of milliseconds.
Definition: ncbitime.cpp:3489
bool IsInfinite(void) const
Check if the deadline is infinite.
Definition: ncbitime.hpp:1853
void GetExpirationTime(time_t *sec, unsigned int *nanosec) const
Get the number of seconds and nanoseconds (since 1/1/1970).
Definition: ncbitime.cpp:3841
#define HANDLE
An abstraction for a file handle.
Definition: mdb.c:383
Definition of all error codes used in corelib (xncbi.lib).
mdb_mode_t mode
Definition: lmdb++.h:38
#define TRUE
bool replacment for C indicating true.
Definition: ncbi_std.h:97
#define FALSE
bool replacment for C indicating false.
Definition: ncbi_std.h:101
void * SwapPointers(void *volatile *location, void *new_value)
Definition: ncbiatomic.hpp:47
#define xncbi_ValidateAndErrnoReport(expression, message)
Definition: ncbidbg_p.hpp:60
#define xncbi_VerifyAndErrorReport(expression)
Definition: ncbidbg_p.hpp:101
#define xncbi_ValidatePthread(expression, expected_value, message)
Definition: ncbidbg_p.hpp:77
#define xncbi_Validate(expression, message)
Definition: ncbidbg_p.hpp:53
@ eUninitialized
Definition: ncbidiag.cpp:898
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
#define RWLockFatal
void interlocked_set(volatile long *val, long new_val)
Definition: ncbimtx.cpp:776
#define WRITE_MUTEX_EVENT(mutex, message)
Definition: ncbimtx.cpp:93
bool interlocked_dec_min(volatile long *val, long min)
Definition: ncbimtx.cpp:845
bool interlocked_dec_max(volatile long *val, long max)
Definition: ncbimtx.cpp:827
void s_ThrowIfDifferentMutexes(CQuickAndDirtySamePointerGuard< SSystemFastMutex > &mutex_guard)
Definition: ncbimtx.cpp:2482
#define NCBI_THREADS_ARG(arg)
Definition: ncbimtx.cpp:1841
bool interlocked_inc_max(volatile long *val, long max)
Definition: ncbimtx.cpp:809
bool interlocked_inc_min(volatile long *val, long min)
Definition: ncbimtx.cpp:791
static CSafeStatic< CRWLockHolder_Pool > s_RWHolderPool
Default CRWLockHolder pool used in CYieldingRWLock.
Definition: ncbimtx.cpp:2205
Multi-threading – mutexes; rw-locks; semaphore.
T max(T x_, T y_)
T min(T x_, T y_)
static unsigned cnt[256]
unsigned int DWORD
Definition: sqltypes.h:98
#define assert(x)
Definition: srv_diag.hpp:58
pthread_mutex_t mutex
Definition: ncbimtx.cpp:1676
pthread_cond_t cond
Definition: ncbimtx.cpp:1677
atomic< unsigned int > count
Definition: ncbimtx.cpp:1674
unsigned int max_count
Definition: ncbimtx.cpp:1673
atomic< unsigned int > wait_count
Definition: ncbimtx.cpp:1675
#define _ASSERT
Modified on Sun Apr 14 05:25:04 2024 by modify_doxy.py rev. 669887