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

Go to the SVN repository for this file.

1 /* $Id: ncbithr.cpp 95296 2021-11-03 14:44:59Z grichenk $
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  * Author: Denis Vakatov, Aleksey Grichenko
27  *
28  * File Description:
29  * Multi-threading -- classes, functions, and features.
30  *
31  * TLS:
32  * CTlsBase -- TLS implementation (base class for CTls<>)
33  *
34  * THREAD:
35  * CThread -- thread wrapper class
36  *
37  * RW-LOCK:
38  * CInternalRWLock -- platform-dependent RW-lock structure (fwd-decl)
39  * CRWLock -- Read/Write lock related data and methods
40  *
41  */
42 
43 
44 #include <ncbi_pch.hpp>
45 #include <corelib/ncbi_param.hpp>
46 #include <corelib/request_ctx.hpp>
47 #include <corelib/ncbi_system.hpp>
48 #include <corelib/error_codes.hpp>
49 #ifdef NCBI_POSIX_THREADS
50 # include <sys/time.h> // for gettimeofday()
51 #endif
52 #ifdef NCBI_OS_LINUX
53 # include <sys/prctl.h>
54 #endif
55 
56 #include "ncbidbg_p.hpp"
57 
58 
59 #define NCBI_USE_ERRCODE_X Corelib_Threads
60 
62 
63 
64 /////////////////////////////////////////////////////////////////////////////
65 // CTlsBase::
66 //
67 
68 
69 DEFINE_STATIC_MUTEX(s_TlsCleanupMutex);
70 
71 
73 {
74 }
75 
76 
78 {
79 }
80 
81 
83 {
84  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
85  // Prevent double-destruction
86  CTlsBase* used_tls = NULL;
88  CTlsBase* tls = *it;
89  // Do not cleanup it now - this will cause infinite recursion
90  if (tls == &sm_UsedTlsBases.Get()) {
91  used_tls = tls;
92  continue;
93  }
94  // Prevent double-destruction
95  tls->x_DeleteTlsData(mode);
96  if (tls->m_AutoDestroy && tls->Referenced()) {
97  tls->RemoveReference();
98  }
99  }
100  m_UsedTls.clear();
101 
102  if (used_tls) {
103  used_tls->x_DeleteTlsData(mode);
104  if (used_tls->m_AutoDestroy && used_tls->Referenced()) {
105  used_tls->RemoveReference();
106  }
107  }
108 }
109 
110 
112 {
113  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
114  if ( m_UsedTls.insert(tls).second ) {
115  if (tls->m_AutoDestroy) {
116  tls->AddReference();
117  }
118  }
119 }
120 
121 
123 {
124  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
126  if (tls->m_AutoDestroy) {
127  tls->RemoveReference();
128  }
129 }
130 
131 
132 static void s_CleanupUsedTlsBases(CUsedTlsBases* tls, void*)
133 {
134  delete tls;
135 }
136 
138 {
139  tls.ClearAll();
140 }
141 
142 // Storage for used TLS sets
145 // Main thread needs a usual safe-static-ref for proper cleanup --
146 // there's no thread which can do it on destruction.
150 
152 {
153  if ( CThread::IsMain() )
154  {
155  return *s_MainUsedTlsBases;
156  }
157 
159  if ( !tls )
160  {
161  tls = new CUsedTlsBases();
163  }
164  return *tls;
165 }
166 
167 
169 {
171 }
172 
173 
175 {
176  if ( CUsedTlsBases* tls = sm_UsedTlsBases.GetValue() ) {
177  tls->ClearAll(mode);
178  }
179 }
180 
181 
183 {
185  if ( CThread::IsMain() ) return;
187  }
188 };
189 
190 
192 {
193  if (!data) return;
194  STlsData* tls_data = static_cast<STlsData*>(data);
195  if (!tls_data->m_Value || !tls_data->m_CleanupFunc) return;
196  if (mode == eCleanup_Native && tls_data->m_Native == eSkipCleanup) return;
197  tls_data->m_CleanupFunc(tls_data->m_Value, tls_data->m_CleanupData);
198 }
199 
200 
202 {
203  if (!data) return;
204  STlsData* tls_data = static_cast<STlsData*>(data);
206  delete tls_data;
207 }
208 
209 
211 {
213 }
214 
215 
217 {
218  // Create platform-dependent TLS key (index)
219 #if defined(NCBI_WIN32_THREADS)
220  xncbi_VerifyAndErrorReport((m_Key = TlsAlloc()) != DWORD(-1));
221 #elif defined(NCBI_POSIX_THREADS)
222  xncbi_VerifyAndErrorReport(pthread_key_create(&m_Key, x_CleanupThreadCallback) == 0);
223  // pthread_key_create does not reset the value to 0 if the key has been
224  // used and deleted.
225  xncbi_VerifyAndErrorReport(pthread_setspecific(m_Key, 0) == 0);
226 #else
227  m_Key = 0;
228 #endif
229 
230  m_Initialized = true;
231 }
232 
233 
235 {
236  x_Reset();
237  m_Initialized = false;
238 
239  // Destroy system TLS key
240 #if defined(NCBI_WIN32_THREADS)
241  if ( TlsFree(m_Key) ) {
242  m_Key = 0;
243  return;
244  }
245  assert(0);
246 #elif defined(NCBI_POSIX_THREADS)
247  if (pthread_key_delete(m_Key) == 0) {
248  m_Key = 0;
249  return;
250  }
251  assert(0);
252 #else
253  m_Key = 0;
254  return;
255 #endif
256 }
257 
258 
259 // Platform-specific TLS data storing
260 inline
261 void s_TlsSetValue(TTlsKey& key, void* data, const char* err_message)
262 {
263 #if defined(NCBI_WIN32_THREADS)
264  xncbi_Validate(TlsSetValue(key, data), err_message);
265 #elif defined(NCBI_POSIX_THREADS)
266  xncbi_ValidatePthread(pthread_setspecific(key, data), 0, err_message);
267 #else
268  key = data;
269  assert(err_message); // to get rid of the "unused variable" warning
270 #endif
271 }
272 
273 
275  FCleanupBase cleanup,
276  void* cleanup_data,
277  ENativeThreadCleanup native)
278 {
279  if ( !m_Initialized ) {
280  return;
281  }
282 
283  // Get previously stored data
284  STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData());
285 
286  // Create and initialize TLS structure, if it was not present
287  if ( !tls_data ) {
288  tls_data = new STlsData;
289  xncbi_Validate(tls_data != 0,
290  "CTlsBase::x_SetValue() -- cannot allocate "
291  "memory for TLS data");
292  tls_data->m_Value = 0;
293  tls_data->m_CleanupFunc = 0;
294  tls_data->m_CleanupData = 0;
295  tls_data->m_Native = eSkipCleanup;
296 
297 #ifdef NCBI_WIN32_THREADS
298  static thread_local SNativeThreadTlsCleanup s_NativeThreadTlsCleanup;
299 #endif
300  }
301 
302  // Cleanup
303  if (tls_data->m_Value != value) {
304  CleanupTlsData(tls_data);
305  }
306 
307  // Store the values
308  tls_data->m_Value = value;
309  tls_data->m_CleanupFunc = cleanup;
310  tls_data->m_CleanupData = cleanup_data;
311  tls_data->m_Native = native;
312 
313  // Store the structure in the TLS
314  s_TlsSetValue(m_Key, tls_data,
315  "CTlsBase::x_SetValue() -- error setting value");
316 
317  // Add to the used TLS list to cleanup data in the thread Exit()
319 }
320 
321 
323 {
324  if ( !m_Initialized ) {
325  return false;
326  }
327 
328  // Get previously stored data
329  STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData());
330  if ( !tls_data ) {
331  return false;
332  }
333 
334  // Cleanup & destroy
335  CleanupAndDeleteTlsData(tls_data, mode);
336 
337  // Store NULL in the TLS
338  s_TlsSetValue(m_Key, 0,
339  "CTlsBase::x_Reset() -- error cleaning-up TLS");
340 
341  return true;
342 }
343 
344 
346 {
347  if ( x_DeleteTlsData() ) {
348  // Deregister this TLS from the current thread
350  }
351 }
352 
353 
354 /////////////////////////////////////////////////////////////////////////////
355 // CExitThreadException::
356 //
357 // Exception used to terminate threads safely, cleaning up
358 // all the resources allocated.
359 //
360 
361 
363 {
364 public:
365  // Create new exception object, initialize counter.
366  CExitThreadException(void);
367 
368  // Create a copy of exception object, increase counter.
370 
371  // Destroy the object, decrease counter. If the counter is
372  // zero outside of CThread::Wrapper(), rethrow exception.
373  ~CExitThreadException(void);
374 
375  // Inform the object it has reached CThread::Wrapper().
376  void EnterWrapper(void)
377  {
378  *m_InWrapper = true;
379  }
380 private:
382  bool* m_InWrapper;
383 };
384 
385 
387  : m_RefCount(new int),
388  m_InWrapper(new bool)
389 {
390  *m_RefCount = 1;
391  *m_InWrapper = false;
392 }
393 
394 
396  : m_RefCount(prev.m_RefCount),
397  m_InWrapper(prev.m_InWrapper)
398 {
399  (*m_RefCount)++;
400 }
401 
402 
404 {
405  if (--(*m_RefCount) > 0) {
406  // Not the last object - continue to handle exceptions
407  return;
408  }
409 
410  bool tmp_in_wrapper = *m_InWrapper; // save the flag
411  delete m_RefCount;
412  delete m_InWrapper;
413 
414  if ( !tmp_in_wrapper ) {
415  // Something is wrong - terminate the thread
416  assert(((void)("CThread::Exit() -- cannot exit thread"), 0));
417 #if defined(NCBI_WIN32_THREADS)
418  ExitThread(0);
419 #elif defined(NCBI_POSIX_THREADS)
420  pthread_exit(0);
421 #endif
422  }
423 
424 }
425 
426 
427 
428 /////////////////////////////////////////////////////////////////////////////
429 // CThread::
430 //
431 
432 // Mutex to protect CThread members and to make sure that Wrapper() function
433 // will not proceed until after the appropriate Run() is finished.
435 
436 atomic<unsigned int> CThread::sm_ThreadsCount(0);
437 
438 
439 // Internal storage for thread objects and related variables/functions
440 static DECLARE_TLS_VAR(CThread*, sx_ThreadPtr);
441 static DECLARE_TLS_VAR(CThread::TID, sx_ThreadId);
442 static bool sm_MainThreadIdInitialized = false;
443 static const CThread::TID kMainThreadId = ~CThread::TID(0);
445 
446 
447 DEFINE_STATIC_FAST_MUTEX(s_MainThreadIdMutex);
448 
450 {
451  CFastMutexGuard guard(s_MainThreadIdMutex);
452  return sx_MainThreadId;
453 }
454 
455 
457 {
458  CFastMutexGuard guard(s_MainThreadIdMutex);
459  sx_MainThreadId = id;
460 }
461 
462 
463 static int sx_GetNextThreadId(void)
464 {
465  CFastMutexGuard guard(s_ThreadMutex);
466  static int s_ThreadCount = 0;
467  return ++s_ThreadCount;
468 }
469 
470 
472 {
473 #if defined(NCBI_THREADS)
474  _ASSERT(!sx_ThreadPtr);
475  _ASSERT(!sx_ThreadId);
476 #endif
477  sx_ThreadPtr = this;
478  sx_ThreadId = sx_GetNextThreadId();
479 }
480 
481 
483 {
484  // mark main thread
485 #if defined(NCBI_THREADS)
486  CFastMutexGuard guard(s_MainThreadIdMutex);
487 #endif
489  if (sx_ThreadId != sx_MainThreadId) {
490  ERR_POST("Can not change main thread ID");
491  }
492  return;
493  }
494 #if defined(NCBI_THREADS)
495  _ASSERT(!sx_ThreadPtr);
497 #endif
498  if ( !sx_ThreadId ) {
499  // Not yet assigned - use the default value.
500  sx_ThreadId = kMainThreadId;
501  }
502  sx_MainThreadId = sx_ThreadId;
503  sx_ThreadPtr = 0;
505 }
506 
507 
509 {
510  // Get pointer to the current thread object
511  return sx_ThreadPtr;
512 }
513 
514 
516 {
517  TID id = sx_ThreadId;
518  if ( !id ) {
519  // If main thread has not been set, consider current thread is the main one.
520  // Since sx_ThreadId is still zero, InitializeMainThreadId() will set it to
521  // kMainThreadId, so that the value returned by GetSelf() will be zero.
524  id = sx_ThreadId;
525  }
526  else {
527  sx_ThreadId = id = sx_GetNextThreadId();
528  }
529  }
530  // kMainThreadId is usually marker for main thread, but when using native threads
531  // and InitializeMainThreadId() to set main thread, the main thread id may be
532  // different and it's more reliable to use IsMain() rather than GetSelf() == 0.
533  return id == kMainThreadId ? 0 : id;
534 }
535 
536 
537 bool CThread::IsMain(void)
538 {
541  }
542  return sx_ThreadId == sx_GetMainThreadId();
543 }
544 
545 
546 NCBI_PARAM_DECL(bool, Thread, Catch_Unhandled_Exceptions);
547 NCBI_PARAM_DEF_EX(bool, Thread, Catch_Unhandled_Exceptions, true, 0,
548  THREAD_CATCH_UNHANDLED_EXCEPTIONS);
549 typedef NCBI_PARAM_TYPE(Thread, Catch_Unhandled_Exceptions) TParamThreadCatchExceptions;
550 
551 
553 {
554  // Get thread object and self ID
555  CThread* thread_obj = static_cast<CThread*>(arg);
556 
557  // Set Toolkit thread ID.
558  thread_obj->x_InitializeThreadId();
560  "CThread::Wrapper() -- error assigning thread ID");
561 
562 #if defined NCBI_THREAD_PID_WORKAROUND
563  // Store this thread's PID. Changed PID means forking of the thread.
564  thread_obj->m_ThreadPID =
565  CProcess::sx_GetPid(CProcess::ePID_GetThread);
566 #endif
567 
568  bool catch_all = TParamThreadCatchExceptions::GetDefault();
569 
570  // Check if parent request context should be used.
571  if ( thread_obj->m_ParentRequestContext ) {
573  }
574 
575  // Run user-provided thread main function here
576  if ( catch_all ) {
577  try {
578  thread_obj->m_ExitData = thread_obj->Main();
579  }
580  catch (CExitThreadException& e) {
581  e.EnterWrapper();
582  }
583 #if defined(NCBI_COMPILER_MSVC) && defined(_DEBUG)
584  // Microsoft promotes many common application errors to exceptions.
585  // This includes occurrences such as dereference of a NULL pointer and
586  // walking off of a dangling pointer. The catch-all is lifted only in
587  // debug mode to permit easy inspection of such error conditions, while
588  // maintaining safety of production, release-mode applications.
589  NCBI_CATCH_X(1, "CThread::Wrapper: CThread::Main() failed");
590 #else
591  NCBI_CATCH_ALL_X(2, "CThread::Wrapper: CThread::Main() failed");
592 #endif
593  }
594  else {
595  try {
596  thread_obj->m_ExitData = thread_obj->Main();
597  }
598  catch (CExitThreadException& e) {
599  e.EnterWrapper();
600  }
601  }
602 
603  // Call user-provided OnExit()
604  if ( catch_all ) {
605  try {
606  thread_obj->OnExit();
607  }
608 #if defined(NCBI_COMPILER_MSVC) && defined(_DEBUG)
609  // Microsoft promotes many common application errors to exceptions.
610  // This includes occurrences such as dereference of a NULL pointer and
611  // walking off of a dangling pointer. The catch-all is lifted only in
612  // debug mode to permit easy inspection of such error conditions, while
613  // maintaining safety of production, release-mode applications.
614  NCBI_CATCH_X(3, "CThread::Wrapper: CThread::OnExit() failed");
615 #else
616  NCBI_CATCH_ALL_X(4, "CThread::Wrapper: CThread::OnExit() failed");
617 #endif
618  }
619  else {
620  thread_obj->OnExit();
621  }
622 
623  // Cleanup local storages used by this thread
625 
626  {{
627  CFastMutexGuard state_guard(s_ThreadMutex);
628 
629  // Thread is terminated - decrement counter under mutex
630  --sm_ThreadsCount;
631 
632  // Indicate the thread is terminated
633  thread_obj->m_IsTerminated = true;
634 
635  // Schedule the thread object for destruction, if detached
636  if ( thread_obj->m_IsDetached ) {
637  thread_obj->m_SelfRef.Reset();
638  }
639  }}
640 
641  return 0;
642 }
643 
644 
646  : m_Handle(0), m_IsRun(false),
647  m_IsDetached(false),
648  m_IsJoined(false),
649  m_IsTerminated(false),
650  m_ExitData(0)
651 #if defined NCBI_THREAD_PID_WORKAROUND
652  , m_ThreadPID(0)
653 #endif
654 {
656 }
657 
658 
660 {
661 #if defined(NCBI_WIN32_THREADS)
662  // close handle if it's not yet closed
663 // CFastMutexGuard state_guard(s_ThreadMutex);
664  if ( m_IsRun && m_Handle != NULL ) {
665  CloseHandle(m_Handle);
666  m_Handle = NULL;
667  }
668 #endif
669 }
670 
671 
672 
674  return CThread::Wrapper(arg);
675 }
676 
677 #if defined(NCBI_POSIX_THREADS)
678 extern "C" {
680 
682  return ThreadWrapperCaller(arg);
683  }
684 }
685 #elif defined(NCBI_WIN32_THREADS)
686 extern "C" {
687  typedef TWrapperRes (WINAPI *FSystemWrapper)(TWrapperArg);
688 
689  static TWrapperRes WINAPI ThreadWrapperCallerImpl(TWrapperArg arg) {
690  return ThreadWrapperCaller(arg);
691  }
692 }
693 #endif
694 
695 
696 #if defined NCBI_THREAD_PID_WORKAROUND
697 TPid CThread::sx_GetThreadPid(void)
698 {
699  CThread* thread_ptr = GetCurrentThread();
700  return thread_ptr ? thread_ptr->m_ThreadPID : 0;
701 }
702 
703 
704 void CThread::sx_SetThreadPid(TPid pid)
705 {
706  CThread* thread_ptr = GetCurrentThread();
707  if ( thread_ptr ) {
708  thread_ptr->m_ThreadPID = pid;
709  }
710 }
711 #endif
712 
713 
714 #define NCBI_THREAD_VALIDATE(cond, error_code, message) \
715  if ( !(cond) ) NCBI_THROW(CThreadException, error_code, message)
716 
717 
718 // Stack size parameter, 2M by default.
719 NCBI_PARAM_DECL(size_t, Thread, StackSize);
720 NCBI_PARAM_DEF_EX(size_t, Thread, StackSize, 2048*1024, eParam_NoThread, THREAD_STACK_SIZE);
721 typedef NCBI_PARAM_TYPE(Thread, StackSize) TParamThreadStackSize;
722 
723 
725 {
727 
728  // Do not allow the new thread to run until m_Handle is set
729  CFastMutexGuard state_guard(s_ThreadMutex);
730 
731  // Check
732  NCBI_THREAD_VALIDATE(!m_IsRun, eRunError,
733  "CThread::Run() -- called for already started thread");
734 
735  m_IsDetached = (flags & fRunDetached) != 0;
736 
737 #if defined NCBI_THREAD_PID_WORKAROUND
738  CProcess::sx_GetPid(CProcess::ePID_GetCurrent);
739 #endif
740 
741  // Thread will run - increment counter under mutex
742  ++sm_ThreadsCount;
743  try {
744 
747  }
748 
749 #if defined(NCBI_WIN32_THREADS)
750  // We need this parameter in WinNT - can not use NULL instead!
751  DWORD thread_id;
752  // Suspend thread to adjust its priority
753  DWORD creation_flags = (flags & fRunNice) == 0 ? 0 : CREATE_SUSPENDED;
754  m_Handle = CreateThread(NULL, 0, ThreadWrapperCallerImpl,
755  this, creation_flags, &thread_id);
756  NCBI_THREAD_VALIDATE(m_Handle != NULL, eRunError,
757  "CThread::Run() -- error creating thread");
758  if (flags & fRunNice) {
759  // Adjust priority and resume the thread
760  SetThreadPriority(m_Handle, THREAD_PRIORITY_BELOW_NORMAL);
761  ResumeThread(m_Handle);
762  }
763  if ( m_IsDetached ) {
764  CloseHandle(m_Handle);
765  m_Handle = NULL;
766  }
767  else {
768  // duplicate handle to adjust security attributes
769  HANDLE oldHandle = m_Handle;
770  NCBI_THREAD_VALIDATE(DuplicateHandle(GetCurrentProcess(), oldHandle,
771  GetCurrentProcess(), &m_Handle,
772  0, FALSE, DUPLICATE_SAME_ACCESS),
773  eRunError, "CThread::Run() -- error getting thread handle");
774  NCBI_THREAD_VALIDATE(CloseHandle(oldHandle),
775  eRunError, "CThread::Run() -- error closing thread handle");
776  }
777 #elif defined(NCBI_POSIX_THREADS)
778  pthread_attr_t attr;
779  NCBI_THREAD_VALIDATE(pthread_attr_init(&attr) == 0, eRunError,
780  "CThread::Run() - error initializing thread attributes");
781  if ( ! (flags & fRunUnbound) ) {
782 #if defined(NCBI_OS_BSD) || defined(NCBI_OS_CYGWIN) || defined(NCBI_OS_IRIX)
783  NCBI_THREAD_VALIDATE(pthread_attr_setscope(&attr,
784  PTHREAD_SCOPE_PROCESS) == 0, eRunError,
785  "CThread::Run() - error setting thread scope");
786 #else
787  NCBI_THREAD_VALIDATE(pthread_attr_setscope(&attr,
788  PTHREAD_SCOPE_SYSTEM) == 0, eRunError,
789  "CThread::Run() - error setting thread scope");
790 #endif
791  }
792  if ( m_IsDetached ) {
793  NCBI_THREAD_VALIDATE(pthread_attr_setdetachstate(&attr,
794  PTHREAD_CREATE_DETACHED) == 0, eRunError,
795  "CThread::Run() - error setting thread detach state");
796  }
797  NCBI_THREAD_VALIDATE(pthread_attr_setstacksize(&attr,
798  TParamThreadStackSize::GetDefault()) == 0, eRunError,
799  "Thread::Run() -- error setting stack size");
800  NCBI_THREAD_VALIDATE(pthread_create(&m_Handle, &attr,
801  ThreadWrapperCallerImpl, this) == 0, eRunError,
802  "CThread::Run() -- error creating thread");
803 
804  NCBI_THREAD_VALIDATE(pthread_attr_destroy(&attr) == 0, eRunError,
805  "CThread::Run() - error destroying thread attributes");
806 
807 #else
808  if (flags & fRunAllowST) {
809  Wrapper(this);
810  }
811  else {
812  NCBI_THREAD_VALIDATE(0, eRunError,
813  "CThread::Run() -- system does not support threads");
814  }
815 #endif
816 
817  // prevent deletion of CThread until thread is finished
818  m_SelfRef.Reset(this);
819 
820  }
821  catch (...) {
822  // In case of any error we need to decrement threads count
823  --sm_ThreadsCount;
824  throw;
825  }
826 
827  // Indicate that the thread is run
828  m_IsRun = true;
829  return true;
830 }
831 
832 
833 void CThread::Detach(void)
834 {
835  CFastMutexGuard state_guard(s_ThreadMutex);
836 
837  // Check the thread state: it must be run, but not detached yet
838  NCBI_THREAD_VALIDATE(m_IsRun, eControlError,
839  "CThread::Detach() -- called for not yet started thread");
840  NCBI_THREAD_VALIDATE(!m_IsDetached, eControlError,
841  "CThread::Detach() -- called for already detached thread");
842 
843  // Detach the thread
844 #if defined(NCBI_WIN32_THREADS)
845  NCBI_THREAD_VALIDATE(CloseHandle(m_Handle), eControlError,
846  "CThread::Detach() -- error closing thread handle");
847  m_Handle = NULL;
848 #elif defined(NCBI_POSIX_THREADS)
849  NCBI_THREAD_VALIDATE(pthread_detach(m_Handle) == 0, eControlError,
850  "CThread::Detach() -- error detaching thread");
851 #endif
852 
853  // Indicate the thread is detached
854  m_IsDetached = true;
855 
856  // Schedule the thread object for destruction, if already terminated
857  if ( m_IsTerminated ) {
858  m_SelfRef.Reset();
859  }
860 }
861 
862 
863 void CThread::Join(void** exit_data)
864 {
865  // Check the thread state: it must be run, but not detached yet
866  {{
867  CFastMutexGuard state_guard(s_ThreadMutex);
868  NCBI_THREAD_VALIDATE(m_IsRun, eControlError,
869  "CThread::Join() -- called for not yet started thread");
870  NCBI_THREAD_VALIDATE(!m_IsDetached, eControlError,
871  "CThread::Join() -- called for detached thread");
872  NCBI_THREAD_VALIDATE(!m_IsJoined, eControlError,
873  "CThread::Join() -- called for already joined thread");
874  m_IsJoined = true;
875  }}
876 
877  // Join (wait for) and destroy
878 #if defined(NCBI_WIN32_THREADS)
879  NCBI_THREAD_VALIDATE(WaitForSingleObject(m_Handle, INFINITE) == WAIT_OBJECT_0,
880  eControlError, "CThread::Join() -- can not join thread");
881  DWORD status;
882  NCBI_THREAD_VALIDATE(GetExitCodeThread(m_Handle, &status) &&
883  status != DWORD(STILL_ACTIVE), eControlError,
884  "CThread::Join() -- thread is still running after join");
885  NCBI_THREAD_VALIDATE(CloseHandle(m_Handle), eControlError,
886  "CThread::Join() -- can not close thread handle");
887  m_Handle = NULL;
888 #elif defined(NCBI_POSIX_THREADS)
889  NCBI_THREAD_VALIDATE(pthread_join(m_Handle, 0) == 0, eControlError,
890  "CThread::Join() -- can not join thread");
891 #endif
892 
893  // Set exit_data value
894  if ( exit_data ) {
895  *exit_data = m_ExitData;
896  }
897 
898  // Schedule the thread object for destruction
899  {{
900  CFastMutexGuard state_guard(s_ThreadMutex);
901  m_SelfRef.Reset();
902  }}
903 }
904 
905 
906 void CThread::Exit(void* exit_data)
907 {
908  // Don't exit from the main thread
909  CThread* x_this = GetCurrentThread();
910  NCBI_THREAD_VALIDATE(x_this != 0, eControlError,
911  "CThread::Exit() -- attempt to call for the main thread");
912 
913  {{
914  CFastMutexGuard state_guard(s_ThreadMutex);
915  x_this->m_ExitData = exit_data;
916  }}
917 
918  // Throw the exception to be caught by Wrapper()
919  throw CExitThreadException();
920 }
921 
922 
924 {
925  CFastMutexGuard state_guard(s_ThreadMutex);
926 
927  // Do not discard after Run()
928  if ( m_IsRun ) {
929  return false;
930  }
931 
932  // Schedule for destruction (or, destroy it right now if there is no
933  // other CRef<>-based references to this object left).
934  m_SelfRef.Reset(this);
935  m_SelfRef.Reset();
936  return true;
937 }
938 
939 
940 void CThread::OnExit(void)
941 {
942  return;
943 }
944 
945 
947 {
948  *id = GetCurrentThreadSystemID();
949 }
950 
951 
952 #if defined(NCBI_OS_LINUX) && defined(PR_SET_NAME)
954 {
955  prctl(PR_SET_NAME, (unsigned long)name.data(), 0, 0, 0);
956 }
957 #else
959 {
960 }
961 #endif
962 
963 
964 bool CThread::sm_IsExiting = false;
966 
967 
969 {
970  sm_WaitForThreadsTimeout = timeout;
971 }
972 
973 
975 {
976  if (sm_ThreadsCount == 0) return true;
977  if ( !IsMain() ) return false;
978 
980  bool infinite = sm_WaitForThreadsTimeout.IsInfinite();
981  unsigned long to = 0;
982  unsigned long q = 10;
983  if ( !infinite ) {
985  if (to < q) q = to;
986  }
987  while (sm_ThreadsCount > 0 && (infinite || sw.Elapsed()*1000 < to)) {
988  SleepMilliSec(q);
989  }
990  return sm_ThreadsCount == 0;
991 }
992 
993 
994 const char* CThreadException::GetErrCodeString(void) const
995 {
996  switch (GetErrCode()) {
997  case eRunError: return "eRunError";
998  case eControlError: return "eControlError";
999  case eOther: return "eOther";
1000  default: return CException::GetErrCodeString();
1001  }
1002 }
1003 
1004 
~CExitThreadException(void)
Definition: ncbithr.cpp:403
void EnterWrapper(void)
Definition: ncbithr.cpp:376
CExitThreadException(void)
Definition: ncbithr.cpp:386
CSafeStatic<>::
T & Get(void)
Create the variable if not created yet, return the reference.
CStopWatch –.
Definition: ncbitime.hpp:1937
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTimeout – Timeout interval.
Definition: ncbitime.hpp:1693
CTlBase –.
Definition: ncbithr.hpp:66
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
void clear()
Definition: set.hpp:153
void erase(iterator pos)
Definition: set.hpp:151
static uch flags
static void cleanup(void)
Definition: ct_dynamic.c:30
#define false
Definition: bool.h:36
#define bool
Definition: bool.h:34
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
char data[12]
Definition: iconv.c:80
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
#define NULL
Definition: ncbistd.hpp:225
static void SetRequestContext(CRequestContext *ctx)
Shortcut to CDiagContextThreadData::GetThreadData().SetRequestContext()
Definition: ncbidiag.cpp:1907
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
Definition: ncbidiag.cpp:1901
CRef< CRequestContext > Clone(void) const
Copy current request context to a new one.
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
#define NCBI_CATCH_ALL_X(err_subcode, message)
Definition: ncbiexpt.hpp:619
#define NCBI_CATCH_X(err_subcode, message)
Catch CExceptions as well with default error code and given error subcode placed in diagnostics.
Definition: ncbiexpt.hpp:615
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
virtual void DoDeleteThisObject(void)
Mark this object as allocated in heap – object can be deleted.
Definition: ncbiobj.cpp:926
void AddReference(void) const
Add reference to object.
Definition: ncbiobj.hpp:489
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:773
void RemoveReference(void) const
Remove reference to object.
Definition: ncbiobj.hpp:500
bool Referenced(void) const THROWS_NONE
Check if object is referenced.
Definition: ncbiobj.hpp:468
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
pid_t TPid
Process identifier (PID) and process handle.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
const char * data(void) const
Return a pointer to the array represented.
Definition: tempstr.hpp:313
void * m_ExitData
as returned by Main() or passed to Exit()
Definition: ncbithr.hpp:657
TValue * GetValue(void)
Definition: ncbithr.hpp:335
void * TWrapperArg
Define platform-dependent argument wrapper.
static bool WaitForAllThreads(void)
Definition: ncbithr.cpp:974
bool Run(TRunMode flags=fRunDefault)
Run the thread.
Definition: ncbithr.cpp:724
TThreadHandle m_Handle
platform-dependent thread handle
Definition: ncbithr.hpp:651
static void Exit(void *exit_data)
Cancel current thread.
Definition: ncbithr.cpp:906
void Register(CTlsBase *tls)
Definition: ncbithr.cpp:111
bool m_IsTerminated
if Exit() was called for the thread
Definition: ncbithr.hpp:655
static TID GetSelf(void)
Definition: ncbithr.cpp:515
virtual const char * GetErrCodeString(void) const override
Translate from the error code value to its string representation.
Definition: ncbithr.cpp:994
bool x_DeleteTlsData(ECleanupMode mode=eCleanup_Toolkit)
Deletes STlsData* structure and managed pointer Returns true if CTlsBase must be deregistered from cu...
Definition: ncbithr.cpp:322
bool m_Initialized
Indicates if thread data initialized.
Definition: ncbithr.hpp:123
static void GetSystemID(TThreadSystemID *id)
Get system ID of the current thread - for internal use only.
Definition: ncbithr.cpp:946
static CUsedTlsBases & GetUsedTlsBases(void)
Get the list of used TLS-es for the current thread.
Definition: ncbithr.cpp:151
ENativeThreadCleanup
Flag indicating if cleanup function should be called when using native threads rather than CThread.
Definition: ncbithr.hpp:78
ECleanupMode
Flag telling which code has called TLS cleanup.
Definition: ncbithr.hpp:84
bool Discard(void)
If the thread has not been Run() yet, then schedule the thread object for destruction,...
Definition: ncbithr.cpp:923
static CTimeout sm_WaitForThreadsTimeout
Definition: ncbithr.hpp:661
void Detach(void)
Inform the thread that user does not need to wait for its termination.
Definition: ncbithr.cpp:833
static CStaticTls< CUsedTlsBases > sm_UsedTlsBases
Definition: ncbithr.hpp:509
FCleanupBase m_CleanupFunc
Definition: ncbithr.hpp:130
void ClearAll(CTlsBase::ECleanupMode mode=CTlsBase::eCleanup_Toolkit)
The function is called before thread termination to cleanup data stored in the TLS.
Definition: ncbithr.cpp:82
static void Init(void)
Init TLS, call before creating thread.
Definition: ncbithr.cpp:168
virtual void OnExit(void)
Override this to execute finalization code.
Definition: ncbithr.cpp:940
virtual ~CThread(void)
To be called only internally! NOTE: destructor of the derived (user-provided) class should be declare...
Definition: ncbithr.cpp:659
static void SetCurrentThreadName(const CTempString &)
Set name for the current thread.
Definition: ncbithr.cpp:958
bool m_IsDetached
if the thread is detached
Definition: ncbithr.hpp:653
pthread_key_t TTlsKey
Define internal TLS key type.
void x_Destroy(void)
Destroy thread data.
Definition: ncbithr.cpp:234
void x_Init(void)
Initialize thread data.
Definition: ncbithr.cpp:216
CThread(void)
Constructor.
Definition: ncbithr.cpp:645
~CUsedTlsBases(void)
Definition: ncbithr.cpp:77
unsigned int TID
Get ID of current thread.
Definition: ncbithr.hpp:598
CRef< CRequestContext > m_ParentRequestContext
Definition: ncbithr.hpp:658
static void InitializeMainThreadId(void)
Initialize main thread's TID.
Definition: ncbithr.cpp:482
bool m_IsRun
if Run() was called for the thread
Definition: ncbithr.hpp:652
bool m_AutoDestroy
Indicates if object should be destroyed in destructor.
Definition: ncbithr.hpp:124
TTlsKey m_Key
Definition: ncbithr.hpp:122
static void x_CleanupThreadCallback(void *ptr)
Definition: ncbithr.cpp:210
TTlsSet m_UsedTls
Definition: ncbithr.hpp:507
static TWrapperRes Wrapper(TWrapperArg arg)
Function to use (internally) as the thread's startup function.
Definition: ncbithr.cpp:552
static void CleanupAndDeleteTlsData(void *data, ECleanupMode mode=eCleanup_Toolkit)
Definition: ncbithr.cpp:201
static void ClearAllCurrentThread(CTlsBase::ECleanupMode mode=CTlsBase::eCleanup_Toolkit)
Clear used TLS-es for the current thread.
Definition: ncbithr.cpp:174
void x_Reset(void)
Helper method to reset thread data.
Definition: ncbithr.cpp:345
virtual void * Main(void)=0
Derived (user-created) class must provide a real thread function.
static bool sm_IsExiting
Definition: ncbithr.hpp:660
void x_SetValue(void *value, FCleanupBase cleanup, void *cleanup_data, ENativeThreadCleanup native)
Helper method to set thread data.
Definition: ncbithr.cpp:274
void x_InitializeThreadId(void)
initalize new thread id, must be called from Wrapper().
Definition: ncbithr.cpp:471
static bool IsMain(void)
Definition: ncbithr.cpp:537
void SetValue(TValue *value, FCleanup cleanup=0, void *cleanup_data=0, CTlsBase::ENativeThreadCleanup native=CTlsBase::eSkipCleanup)
Definition: ncbithr.hpp:338
void * TWrapperRes
Define platform-dependent result wrapper.
int TRunMode
Bitwise OR'd flags for thread creation passed to Run().
Definition: ncbithr.hpp:558
pthread_t TThreadSystemID
Define platform-dependent thread ID type.
static void SetWaitForAllThreadsTimeout(const CTimeout &timeout)
Set timeout for stopping all threads on application exit.
Definition: ncbithr.cpp:968
static atomic< unsigned int > sm_ThreadsCount
Total amount of threads.
Definition: ncbithr.hpp:671
CUsedTlsBases(void)
Definition: ncbithr.cpp:72
bool m_IsJoined
if Join() was called for the thread
Definition: ncbithr.hpp:654
static void CleanupTlsData(void *data, ECleanupMode mode=eCleanup_Toolkit)
Definition: ncbithr.cpp:191
void Deregister(CTlsBase *tls)
Definition: ncbithr.cpp:122
static CThread * GetCurrentThread(void)
Get current CThread object (or NULL, if main thread)
Definition: ncbithr.cpp:508
CRef< CThread > m_SelfRef
"this" – to avoid premature destruction
Definition: ncbithr.hpp:656
void Join(void **exit_data=0)
Wait for the thread termination.
Definition: ncbithr.cpp:863
ENativeThreadCleanup m_Native
Definition: ncbithr.hpp:132
STlsData * x_GetTlsData(void) const
Helper method to get the STlsData*.
Definition: ncbithr.hpp:725
static TThreadSystemID GetCurrentThreadSystemID(void)
Get the current thread ID.
Definition: ncbimtx.hpp:152
void * m_CleanupData
Definition: ncbithr.hpp:131
@ eControlError
Failed to control thread's state.
Definition: ncbithr.hpp:697
@ eOther
Other thread errors.
Definition: ncbithr.hpp:698
@ eRunError
Failed to run thread.
Definition: ncbithr.hpp:696
@ fRunCloneRequestContext
Clone parent's request context and pass it to the new thread.
Definition: ncbithr.hpp:552
@ fRunAllowST
Allow threads to run in single thread builds.
Definition: ncbithr.hpp:549
@ fRunUnbound
Run thread in a N:1 thread:LPW mode.
Definition: ncbithr.hpp:545
@ fRunNice
Run thread with low priority (MS-Win only)
Definition: ncbithr.hpp:548
@ fRunDetached
Run the thread detached (non-joinable)
Definition: ncbithr.hpp:541
@ eSkipCleanup
Definition: ncbithr.hpp:80
@ eDoCleanup
Definition: ncbithr.hpp:79
@ eCleanup_Native
Cleanup is performed by thread_local destructor.
Definition: ncbithr.hpp:86
double Elapsed(void) const
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2775
bool IsInfinite() const
Definition: ncbitime.hpp:2729
unsigned long GetAsMilliSeconds(void) const
Get as number of milliseconds.
Definition: ncbitime.cpp:3490
@ eStart
Start timer immediately after creating.
Definition: ncbitime.hpp:1941
#define HANDLE
An abstraction for a file handle.
Definition: mdb.c:383
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
static CStopWatch sw
Definition of all error codes used in corelib (xncbi.lib).
if(yy_accept[yy_current_state])
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
#define FALSE
bool replacment for C indicating false.
Definition: ncbi_std.h:101
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
#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
static bool sm_MainThreadIdInitialized
Definition: ncbithr.cpp:442
CThread::TID sx_GetMainThreadId()
Definition: ncbithr.cpp:449
static DECLARE_TLS_VAR(CThread *, sx_ThreadPtr)
DEFINE_STATIC_MUTEX(s_TlsCleanupMutex)
TWrapperRes(* FSystemWrapper)(TWrapperArg)
Definition: ncbithr.cpp:679
static void s_CleanupUsedTlsBases(CUsedTlsBases *tls, void *)
Definition: ncbithr.cpp:132
DEFINE_STATIC_FAST_MUTEX(s_ThreadMutex)
void s_TlsSetValue(TTlsKey &key, void *data, const char *err_message)
Definition: ncbithr.cpp:261
static int sx_GetNextThreadId(void)
Definition: ncbithr.cpp:463
#define NCBI_THREAD_VALIDATE(cond, error_code, message)
Definition: ncbithr.cpp:714
void sx_SetMainThreadId(CThread::TID id)
Definition: ncbithr.cpp:456
NCBI_PARAM_DEF_EX(bool, Thread, Catch_Unhandled_Exceptions, true, 0, THREAD_CATCH_UNHANDLED_EXCEPTIONS)
NCBI_PARAM_DECL(bool, Thread, Catch_Unhandled_Exceptions)
TWrapperRes ThreadWrapperCaller(TWrapperArg arg)
Definition: ncbithr.cpp:673
static TWrapperRes ThreadWrapperCallerImpl(TWrapperArg arg)
Definition: ncbithr.cpp:681
static const CThread::TID kMainThreadId
Definition: ncbithr.cpp:443
static CSafeStatic< CUsedTlsBases > s_MainUsedTlsBases(0, s_CleanupMainUsedTlsBases, CSafeStaticLifeSpan::eLifeSpan_Long)
static CThread::TID sx_MainThreadId
Definition: ncbithr.cpp:444
static void s_CleanupMainUsedTlsBases(CUsedTlsBases &tls)
Definition: ncbithr.cpp:137
typedef NCBI_PARAM_TYPE(Thread, Catch_Unhandled_Exceptions) TParamThreadCatchExceptions
Defines CRequestContext class for NCBI C++ diagnostic API.
unsigned int DWORD
Definition: sqltypes.h:98
#define assert(x)
Definition: srv_diag.hpp:58
Internal structure to store all three pointers in the same TLS.
Definition: ncbithr.hpp:128
#define _ASSERT
Modified on Fri Sep 20 14:57:59 2024 by modify_doxy.py rev. 669887