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

Go to the SVN repository for this file.

1 /* $Id: ncbithr.cpp 67385 2015-05-13 16:41:39Z sadyrovr $
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/ncbi_system.hpp>
47 #include <corelib/error_codes.hpp>
48 #ifdef NCBI_POSIX_THREADS
49 # include <sys/time.h> // for gettimeofday()
50 #endif
51 #ifdef NCBI_OS_LINUX
52 # include <sys/prctl.h>
53 #endif
54 
55 #include "ncbidbg_p.hpp"
56 
57 
58 #define NCBI_USE_ERRCODE_X Corelib_Threads
59 
61 
62 
63 /////////////////////////////////////////////////////////////////////////////
64 // CTlsBase::
65 //
66 
67 
68 DEFINE_STATIC_MUTEX(s_TlsCleanupMutex);
69 
70 
72 {
73 }
74 
75 
77 {
78 }
79 
80 
82 {
83  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
84  // Prevent double-destruction
85  CTlsBase* used_tls = NULL;
87  CTlsBase* tls = *it;
88  // Do not cleanup it now - this will cause infinite recursion
89  if (tls == &sm_UsedTlsBases.Get()) {
90  used_tls = tls;
91  continue;
92  }
93  // Prevent double-destruction
94  tls->x_DeleteTlsData();
95  if (tls->m_AutoDestroy && tls->Referenced()) {
96  tls->RemoveReference();
97  }
98  }
99  m_UsedTls.clear();
100 
101  if (used_tls) {
102  used_tls->x_DeleteTlsData();
103  if (used_tls->m_AutoDestroy && used_tls->Referenced()) {
104  used_tls->RemoveReference();
105  }
106  }
107 }
108 
109 
111 {
112  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
113  if ( m_UsedTls.insert(tls).second ) {
114  if (tls->m_AutoDestroy) {
115  tls->AddReference();
116  }
117  }
118 }
119 
120 
122 {
123  CMutexGuard tls_cleanup_guard(s_TlsCleanupMutex);
125  if (tls->m_AutoDestroy) {
126  tls->RemoveReference();
127  }
128 }
129 
130 
131 static void s_CleanupUsedTlsBases(CUsedTlsBases* tls, void*)
132 {
133  delete tls;
134 }
135 
137 {
138  tls.ClearAll();
139 }
140 
141 // Storage for used TLS sets
144 // Main thread needs a usual safe-static-ref for proper cleanup --
145 // there's no thread which can do it on destruction.
149 
151 {
152  if ( !CThread::GetSelf() )
153  {
154  return *s_MainUsedTlsBases;
155  }
156 
158  if ( !tls )
159  {
160  tls = new CUsedTlsBases();
162  }
163  return *tls;
164 }
165 
166 
168 {
170 }
171 
172 
174 {
175  if ( CUsedTlsBases* tls = sm_UsedTlsBases.GetValue() ) {
176  tls->ClearAll();
177  }
178 }
179 
180 
181 void CTlsBase::CleanupTlsData(void* data)
182 {
183  if (!data) return;
184  STlsData* tls_data = static_cast<STlsData*>(data);
185  if (tls_data->m_Value && tls_data->m_CleanupFunc) {
186  tls_data->m_CleanupFunc(tls_data->m_Value, tls_data->m_CleanupData);
187  }
188 }
189 
190 
191 #if defined(NCBI_POSIX_THREADS)
192 // pthread can handle automatic cleanup
193 extern "C" void s_PosixTlsCleanup(void* ptr)
194 {
196 }
197 #endif
198 
200 {
201  // Create platform-dependent TLS key (index)
202 #if defined(NCBI_WIN32_THREADS)
203  xncbi_Verify((m_Key = TlsAlloc()) != DWORD(-1));
204 #elif defined(NCBI_POSIX_THREADS)
205  xncbi_Verify(pthread_key_create(&m_Key, s_PosixTlsCleanup) == 0);
206  // pthread_key_create does not reset the value to 0 if the key has been
207  // used and deleted.
208  xncbi_Verify(pthread_setspecific(m_Key, 0) == 0);
209 #else
210  m_Key = 0;
211 #endif
212 
213  m_Initialized = true;
214 }
215 
216 
218 {
219  x_Reset();
220  m_Initialized = false;
221 
222  // Destroy system TLS key
223 #if defined(NCBI_WIN32_THREADS)
224  if ( TlsFree(m_Key) ) {
225  m_Key = 0;
226  return;
227  }
228  assert(0);
229 #elif defined(NCBI_POSIX_THREADS)
230  if (pthread_key_delete(m_Key) == 0) {
231  m_Key = 0;
232  return;
233  }
234  assert(0);
235 #else
236  m_Key = 0;
237  return;
238 #endif
239 }
240 
241 
242 // Platform-specific TLS data storing
243 inline
244 void s_TlsSetValue(TTlsKey& key, void* data, const char* err_message)
245 {
246 #if defined(NCBI_WIN32_THREADS)
247  xncbi_Validate(TlsSetValue(key, data), err_message);
248 #elif defined(NCBI_POSIX_THREADS)
249  xncbi_Validate(pthread_setspecific(key, data) == 0, err_message);
250 #else
251  key = data;
252  assert(err_message); // to get rid of the "unused variable" warning
253 #endif
254 }
255 
256 
258  FCleanupBase cleanup,
259  void* cleanup_data)
260 {
261  if ( !m_Initialized ) {
262  return;
263  }
264 
265  // Get previously stored data
266  STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData());
267 
268  // Create and initialize TLS structure, if it was not present
269  if ( !tls_data ) {
270  tls_data = new STlsData;
271  xncbi_Validate(tls_data != 0,
272  "CTlsBase::x_SetValue() -- cannot allocate "
273  "memory for TLS data");
274  tls_data->m_Value = 0;
275  tls_data->m_CleanupFunc = 0;
276  tls_data->m_CleanupData = 0;
277  }
278 
279  // Cleanup
280  if (tls_data->m_Value != value) {
281  CleanupTlsData(tls_data);
282  }
283 
284  // Store the values
285  tls_data->m_Value = value;
286  tls_data->m_CleanupFunc = cleanup;
287  tls_data->m_CleanupData = cleanup_data;
288 
289  // Store the structure in the TLS
290  s_TlsSetValue(m_Key, tls_data,
291  "CTlsBase::x_SetValue() -- error setting value");
292 
293  // Add to the used TLS list to cleanup data in the thread Exit()
295 }
296 
297 
299 {
300  if ( !m_Initialized ) {
301  return false;
302  }
303 
304  // Get previously stored data
305  STlsData* tls_data = static_cast<STlsData*> (x_GetTlsData());
306  if ( !tls_data ) {
307  return false;
308  }
309 
310  // Cleanup & destroy
311  CleanupTlsData(tls_data);
312  delete tls_data;
313 
314  // Store NULL in the TLS
315  s_TlsSetValue(m_Key, 0,
316  "CTlsBase::x_Reset() -- error cleaning-up TLS");
317 
318  return true;
319 }
320 
321 
323 {
324  if ( x_DeleteTlsData() ) {
325  // Deregister this TLS from the current thread
327  }
328 }
329 
330 
331 /////////////////////////////////////////////////////////////////////////////
332 // CExitThreadException::
333 //
334 // Exception used to terminate threads safely, cleaning up
335 // all the resources allocated.
336 //
337 
338 
340 {
341 public:
342  // Create new exception object, initialize counter.
343  CExitThreadException(void);
344 
345  // Create a copy of exception object, increase counter.
347 
348  // Destroy the object, decrease counter. If the counter is
349  // zero outside of CThread::Wrapper(), rethrow exception.
350  ~CExitThreadException(void);
351 
352  // Inform the object it has reached CThread::Wrapper().
353  void EnterWrapper(void)
354  {
355  *m_InWrapper = true;
356  }
357 private:
359  bool* m_InWrapper;
360 };
361 
362 
364  : m_RefCount(new int),
365  m_InWrapper(new bool)
366 {
367  *m_RefCount = 1;
368  *m_InWrapper = false;
369 }
370 
371 
373  : m_RefCount(prev.m_RefCount),
374  m_InWrapper(prev.m_InWrapper)
375 {
376  (*m_RefCount)++;
377 }
378 
379 
381 {
382  if (--(*m_RefCount) > 0) {
383  // Not the last object - continue to handle exceptions
384  return;
385  }
386 
387  bool tmp_in_wrapper = *m_InWrapper; // save the flag
388  delete m_RefCount;
389  delete m_InWrapper;
390 
391  if ( !tmp_in_wrapper ) {
392  // Something is wrong - terminate the thread
393  assert(((void)("CThread::Exit() -- cannot exit thread"), 0));
394 #if defined(NCBI_WIN32_THREADS)
395  ExitThread(0);
396 #elif defined(NCBI_POSIX_THREADS)
397  pthread_exit(0);
398 #endif
399  }
400 
401 }
402 
403 
404 
405 /////////////////////////////////////////////////////////////////////////////
406 // CThread::
407 //
408 
409 // Mutex to protect CThread members and to make sure that Wrapper() function
410 // will not proceed until after the appropriate Run() is finished.
411 DEFINE_STATIC_FAST_MUTEX(s_ThreadMutex);
412 
413 volatile unsigned int CThread::sm_ThreadsCount = 0;
414 
415 
416 // Internal storage for thread objects and related variables/functions
417 static DECLARE_TLS_VAR(CThread*, sx_ThreadPtr);
418 static DECLARE_TLS_VAR(CThread::TID, sx_ThreadId);
419 static bool sm_MainThreadIdInitialized = false;
420 static const CThread::TID kMainThreadId = ~CThread::TID(0);
421 
422 
423 static int sx_GetNextThreadId(void)
424 {
425  CFastMutexGuard guard(s_ThreadMutex);
426  static int s_ThreadCount = 0;
427  return ++s_ThreadCount;
428 }
429 
430 
432 {
433 #if defined(NCBI_THREADS)
434  _ASSERT(!sx_ThreadPtr);
435  _ASSERT(!sx_ThreadId);
436 #endif
437  sx_ThreadPtr = this;
438  sx_ThreadId = sx_GetNextThreadId();
439 }
440 
441 
443 {
444  // mark main thread
445 #if defined(NCBI_THREADS)
446  _ASSERT(!sx_ThreadPtr);
447  _ASSERT(!sx_ThreadId);
448 #endif
449  sx_ThreadPtr = 0;
450  sx_ThreadId = kMainThreadId;
451  sm_MainThreadIdInitialized = true;
452 }
453 
454 
456 {
457  // Get pointer to the current thread object
458  return sx_ThreadPtr;
459 }
460 
461 
463 {
464  TID id = sx_ThreadId;
465  if ( !id && sm_MainThreadIdInitialized ) {
466  // Info has not been set - this is a native thread,
467  // main thread is already assigned so we can assign new thread an ID.
468  sx_ThreadId = id = sx_GetNextThreadId();
469  }
470  // kMainThreadId is marker for main thread
471  return id == kMainThreadId? 0: id;
472 }
473 
474 
475 NCBI_PARAM_DECL(bool, Thread, Catch_Unhandled_Exceptions);
476 NCBI_PARAM_DEF_EX(bool, Thread, Catch_Unhandled_Exceptions, true, 0,
477  THREAD_CATCH_UNHANDLED_EXCEPTIONS);
478 typedef NCBI_PARAM_TYPE(Thread, Catch_Unhandled_Exceptions) TParamThreadCatchExceptions;
479 
480 
482 {
483  // Get thread object and self ID
484  CThread* thread_obj = static_cast<CThread*>(arg);
485 
486  // Set Toolkit thread ID.
487  thread_obj->x_InitializeThreadId();
488  xncbi_Validate(GetSelf() != 0,
489  "CThread::Wrapper() -- error assigning thread ID");
490 
491 #if defined NCBI_THREAD_PID_WORKAROUND
492  // Store this thread's PID. Changed PID means forking of the thread.
493  thread_obj->m_ThreadPID =
494  CProcess::sx_GetPid(CProcess::ePID_GetThread);
495 #endif
496 
497  bool catch_all = TParamThreadCatchExceptions::GetDefault();
498 
499  // Run user-provided thread main function here
500  if ( catch_all ) {
501  try {
502  thread_obj->m_ExitData = thread_obj->Main();
503  }
504  catch (CExitThreadException& e) {
505  e.EnterWrapper();
506  }
507 #if defined(NCBI_COMPILER_MSVC) && defined(_DEBUG)
508  // Microsoft promotes many common application errors to exceptions.
509  // This includes occurrences such as dereference of a NULL pointer and
510  // walking off of a dangling pointer. The catch-all is lifted only in
511  // debug mode to permit easy inspection of such error conditions, while
512  // maintaining safety of production, release-mode applications.
513  NCBI_CATCH_X(1, "CThread::Wrapper: CThread::Main() failed");
514 #else
515  NCBI_CATCH_ALL_X(2, "CThread::Wrapper: CThread::Main() failed");
516 #endif
517  }
518  else {
519  try {
520  thread_obj->m_ExitData = thread_obj->Main();
521  }
522  catch (CExitThreadException& e) {
523  e.EnterWrapper();
524  }
525  }
526 
527  // Call user-provided OnExit()
528  if ( catch_all ) {
529  try {
530  thread_obj->OnExit();
531  }
532 #if defined(NCBI_COMPILER_MSVC) && defined(_DEBUG)
533  // Microsoft promotes many common application errors to exceptions.
534  // This includes occurrences such as dereference of a NULL pointer and
535  // walking off of a dangling pointer. The catch-all is lifted only in
536  // debug mode to permit easy inspection of such error conditions, while
537  // maintaining safety of production, release-mode applications.
538  NCBI_CATCH_X(3, "CThread::Wrapper: CThread::OnExit() failed");
539 #else
540  NCBI_CATCH_ALL_X(4, "CThread::Wrapper: CThread::OnExit() failed");
541 #endif
542  }
543  else {
544  thread_obj->OnExit();
545  }
546 
547  // Cleanup local storages used by this thread
549 
550  {{
551  CFastMutexGuard state_guard(s_ThreadMutex);
552 
553  // Thread is terminated - decrement counter under mutex
554  --sm_ThreadsCount;
555 
556  // Indicate the thread is terminated
557  thread_obj->m_IsTerminated = true;
558 
559  // Schedule the thread object for destruction, if detached
560  if ( thread_obj->m_IsDetached ) {
561  thread_obj->m_SelfRef.Reset();
562  }
563  }}
564 
565  return 0;
566 }
567 
568 
570  : m_IsRun(false),
571  m_IsDetached(false),
572  m_IsJoined(false),
573  m_IsTerminated(false),
574  m_ExitData(0)
575 #if defined NCBI_THREAD_PID_WORKAROUND
576  , m_ThreadPID(0)
577 #endif
578 {
580 #if defined(HAVE_PTHREAD_SETCONCURRENCY) && defined(NCBI_POSIX_THREADS)
581  // Adjust concurrency for Solaris etc.
582  if (pthread_getconcurrency() == 0) {
583  xncbi_Validate(pthread_setconcurrency(GetCpuCount()) == 0,
584  "CThread::CThread() -- pthread_setconcurrency(2) "
585  "failed");
586  }
587 #endif
588 }
589 
590 
592 {
593 #if defined(NCBI_WIN32_THREADS)
594  // close handle if it's not yet closed
595  CFastMutexGuard state_guard(s_ThreadMutex);
596  if ( m_IsRun && m_Handle != NULL ) {
597  CloseHandle(m_Handle);
598  m_Handle = NULL;
599  }
600 #endif
601 }
602 
603 
604 
606  return CThread::Wrapper(arg);
607 }
608 
609 #if defined(NCBI_POSIX_THREADS)
610 extern "C" {
612 
614  return ThreadWrapperCaller(arg);
615  }
616 }
617 #elif defined(NCBI_WIN32_THREADS)
618 extern "C" {
619  typedef TWrapperRes (WINAPI *FSystemWrapper)(TWrapperArg);
620 
621  static TWrapperRes WINAPI ThreadWrapperCallerImpl(TWrapperArg arg) {
622  return ThreadWrapperCaller(arg);
623  }
624 }
625 #endif
626 
627 
628 #if defined NCBI_THREAD_PID_WORKAROUND
629 TPid CThread::sx_GetThreadPid(void)
630 {
631  CThread* thread_ptr = GetCurrentThread();
632  return thread_ptr ? thread_ptr->m_ThreadPID : 0;
633 }
634 
635 
636 void CThread::sx_SetThreadPid(TPid pid)
637 {
638  CThread* thread_ptr = GetCurrentThread();
639  if ( thread_ptr ) {
640  thread_ptr->m_ThreadPID = pid;
641  }
642 }
643 #endif
644 
645 
646 #define NCBI_THREAD_VALIDATE(cond, error_code, message) \
647  if ( !(cond) ) NCBI_THROW(CThreadException, error_code, message)
648 
650 {
652 
653  // Do not allow the new thread to run until m_Handle is set
654  CFastMutexGuard state_guard(s_ThreadMutex);
655 
656  // Check
657  NCBI_THREAD_VALIDATE(!m_IsRun, eRunError,
658  "CThread::Run() -- called for already started thread");
659 
660  m_IsDetached = (flags & fRunDetached) != 0;
661 
662 #if defined NCBI_THREAD_PID_WORKAROUND
663  CProcess::sx_GetPid(CProcess::ePID_GetCurrent);
664 #endif
665 
666  // Thread will run - increment counter under mutex
667  ++sm_ThreadsCount;
668  try {
669 
670 #if defined(NCBI_WIN32_THREADS)
671  // We need this parameter in WinNT - can not use NULL instead!
672  DWORD thread_id;
673  // Suspend thread to adjust its priority
674  DWORD creation_flags = (flags & fRunNice) == 0 ? 0 : CREATE_SUSPENDED;
675  m_Handle = CreateThread(NULL, 0, ThreadWrapperCallerImpl,
676  this, creation_flags, &thread_id);
677  NCBI_THREAD_VALIDATE(m_Handle != NULL, eRunError,
678  "CThread::Run() -- error creating thread");
679  if (flags & fRunNice) {
680  // Adjust priority and resume the thread
681  SetThreadPriority(m_Handle, THREAD_PRIORITY_BELOW_NORMAL);
682  ResumeThread(m_Handle);
683  }
684  if ( m_IsDetached ) {
685  CloseHandle(m_Handle);
686  m_Handle = NULL;
687  }
688  else {
689  // duplicate handle to adjust security attributes
690  HANDLE oldHandle = m_Handle;
691  NCBI_THREAD_VALIDATE(DuplicateHandle(GetCurrentProcess(), oldHandle,
692  GetCurrentProcess(), &m_Handle,
693  0, FALSE, DUPLICATE_SAME_ACCESS),
694  eRunError, "CThread::Run() -- error getting thread handle");
695  NCBI_THREAD_VALIDATE(CloseHandle(oldHandle),
696  eRunError, "CThread::Run() -- error closing thread handle");
697  }
698 #elif defined(NCBI_POSIX_THREADS)
699  pthread_attr_t attr;
700  NCBI_THREAD_VALIDATE(pthread_attr_init(&attr) == 0, eRunError,
701  "CThread::Run() - error initializing thread attributes");
702  if ( ! (flags & fRunUnbound) ) {
703 #if defined(NCBI_OS_BSD) || defined(NCBI_OS_CYGWIN) || defined(NCBI_OS_IRIX)
704  NCBI_THREAD_VALIDATE(pthread_attr_setscope(&attr,
705  PTHREAD_SCOPE_PROCESS) == 0, eRunError,
706  "CThread::Run() - error setting thread scope");
707 #else
708  NCBI_THREAD_VALIDATE(pthread_attr_setscope(&attr,
709  PTHREAD_SCOPE_SYSTEM) == 0, eRunError,
710  "CThread::Run() - error setting thread scope");
711 #endif
712  }
713  if ( m_IsDetached ) {
714  NCBI_THREAD_VALIDATE(pthread_attr_setdetachstate(&attr,
715  PTHREAD_CREATE_DETACHED) == 0, eRunError,
716  "CThread::Run() - error setting thread detach state");
717  }
718  NCBI_THREAD_VALIDATE(pthread_create(&m_Handle, &attr,
719  ThreadWrapperCallerImpl, this) == 0, eRunError,
720  "CThread::Run() -- error creating thread");
721 
722  NCBI_THREAD_VALIDATE(pthread_attr_destroy(&attr) == 0, eRunError,
723  "CThread::Run() - error destroying thread attributes");
724 
725 #else
726  if (flags & fRunAllowST) {
727  Wrapper(this);
728  }
729  else {
730  NCBI_THREAD_VALIDATE(0, eRunError,
731  "CThread::Run() -- system does not support threads");
732  }
733 #endif
734 
735  // prevent deletion of CThread until thread is finished
736  m_SelfRef.Reset(this);
737 
738  }
739  catch (...) {
740  // In case of any error we need to decrement threads count
741  --sm_ThreadsCount;
742  throw;
743  }
744 
745  // Indicate that the thread is run
746  m_IsRun = true;
747  return true;
748 }
749 
750 
751 void CThread::Detach(void)
752 {
753  CFastMutexGuard state_guard(s_ThreadMutex);
754 
755  // Check the thread state: it must be run, but not detached yet
756  NCBI_THREAD_VALIDATE(m_IsRun, eControlError,
757  "CThread::Detach() -- called for not yet started thread");
758  NCBI_THREAD_VALIDATE(!m_IsDetached, eControlError,
759  "CThread::Detach() -- called for already detached thread");
760 
761  // Detach the thread
762 #if defined(NCBI_WIN32_THREADS)
763  NCBI_THREAD_VALIDATE(CloseHandle(m_Handle), eControlError,
764  "CThread::Detach() -- error closing thread handle");
765  m_Handle = NULL;
766 #elif defined(NCBI_POSIX_THREADS)
767  NCBI_THREAD_VALIDATE(pthread_detach(m_Handle) == 0, eControlError,
768  "CThread::Detach() -- error detaching thread");
769 #endif
770 
771  // Indicate the thread is detached
772  m_IsDetached = true;
773 
774  // Schedule the thread object for destruction, if already terminated
775  if ( m_IsTerminated ) {
776  m_SelfRef.Reset();
777  }
778 }
779 
780 
781 void CThread::Join(void** exit_data)
782 {
783  // Check the thread state: it must be run, but not detached yet
784  {{
785  CFastMutexGuard state_guard(s_ThreadMutex);
786  NCBI_THREAD_VALIDATE(m_IsRun, eControlError,
787  "CThread::Join() -- called for not yet started thread");
788  NCBI_THREAD_VALIDATE(!m_IsDetached, eControlError,
789  "CThread::Join() -- called for detached thread");
790  NCBI_THREAD_VALIDATE(!m_IsJoined, eControlError,
791  "CThread::Join() -- called for already joined thread");
792  m_IsJoined = true;
793  }}
794 
795  // Join (wait for) and destroy
796 #if defined(NCBI_WIN32_THREADS)
797  NCBI_THREAD_VALIDATE(WaitForSingleObject(m_Handle, INFINITE) == WAIT_OBJECT_0,
798  eControlError, "CThread::Join() -- can not join thread");
799  DWORD status;
800  NCBI_THREAD_VALIDATE(GetExitCodeThread(m_Handle, &status) &&
801  status != DWORD(STILL_ACTIVE), eControlError,
802  "CThread::Join() -- thread is still running after join");
803  NCBI_THREAD_VALIDATE(CloseHandle(m_Handle), eControlError,
804  "CThread::Join() -- can not close thread handle");
805  m_Handle = NULL;
806 #elif defined(NCBI_POSIX_THREADS)
807  NCBI_THREAD_VALIDATE(pthread_join(m_Handle, 0) == 0, eControlError,
808  "CThread::Join() -- can not join thread");
809 #endif
810 
811  // Set exit_data value
812  if ( exit_data ) {
813  *exit_data = m_ExitData;
814  }
815 
816  // Schedule the thread object for destruction
817  {{
818  CFastMutexGuard state_guard(s_ThreadMutex);
819  m_SelfRef.Reset();
820  }}
821 }
822 
823 
824 void CThread::Exit(void* exit_data)
825 {
826  // Don't exit from the main thread
827  CThread* x_this = GetCurrentThread();
828  NCBI_THREAD_VALIDATE(x_this != 0, eControlError,
829  "CThread::Exit() -- attempt to call for the main thread");
830 
831  {{
832  CFastMutexGuard state_guard(s_ThreadMutex);
833  x_this->m_ExitData = exit_data;
834  }}
835 
836  // Throw the exception to be caught by Wrapper()
837  throw CExitThreadException();
838 }
839 
840 
842 {
843  CFastMutexGuard state_guard(s_ThreadMutex);
844 
845  // Do not discard after Run()
846  if ( m_IsRun ) {
847  return false;
848  }
849 
850  // Schedule for destruction (or, destroy it right now if there is no
851  // other CRef<>-based references to this object left).
852  m_SelfRef.Reset(this);
853  m_SelfRef.Reset();
854  return true;
855 }
856 
857 
858 void CThread::OnExit(void)
859 {
860  return;
861 }
862 
863 
865 {
866  *id = GetCurrentThreadSystemID();
867 }
868 
869 
870 #if defined(NCBI_OS_LINUX) && defined(PR_SET_NAME)
872 {
873  prctl(PR_SET_NAME, (unsigned long)name.data(), 0, 0, 0);
874 }
875 #else
877 {
878 }
879 #endif
880 
881 
882 const char* CThreadException::GetErrCodeString(void) const
883 {
884  switch (GetErrCode()) {
885  case eRunError: return "eRunError";
886  case eControlError: return "eControlError";
887  case eOther: return "eOther";
888  default: return CException::GetErrCodeString();
889  }
890 }
891 
892 
pthread_t TThreadSystemID
Define platform-dependent thread ID type.
#define NCBI_THREAD_VALIDATE(cond, error_code, message)
Definition: ncbithr.cpp:646
Allow threads to run in single thread builds.
Definition: ncbithr.hpp:524
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:900
TWrapperRes ThreadWrapperCaller(TWrapperArg arg)
Definition: ncbithr.cpp:605
Definition: dbpivot.c:60
CSafeStatic<>::
Run the thread detached (non-joinable)
Definition: ncbithr.hpp:516
bool m_Initialized
Indicates if thread data initialized.
Definition: ncbithr.hpp:109
void x_SetValue(void *value, FCleanupBase cleanup=0, void *cleanup_data=0)
Helper method to set thread data.
Definition: ncbithr.cpp:257
Run thread with low priority (MS-Win only)
Definition: ncbithr.hpp:523
DEFINE_STATIC_FAST_MUTEX(s_ThreadMutex)
#define assert(x)
Definition: srv_diag.hpp:58
bool Run(TRunMode flags=fRunDefault)
Run the thread.
Definition: ncbithr.cpp:649
bool
Definition: cgiapp.hpp:496
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:62
bool Referenced(void) const THROWS_NONE
Check if object is referenced.
Definition: ncbiobj.hpp:469
static unsigned int GetSelf()
Definition: nc_lib.cpp:41
TValue * GetValue(void)
Definition: ncbithr.hpp:309
const struct ncbi::grid::netcache::search::fields::KEY key
#define xncbi_Verify(expression)
Definition: ncbidbg_p.hpp:47
CExitThreadException(void)
Definition: ncbithr.cpp:363
Other thread errors.
Definition: ncbithr.hpp:643
CRef< CThread > m_SelfRef
"this" – to avoid premature destruction
Definition: ncbithr.hpp:611
Failed to run thread.
Definition: ncbithr.hpp:641
TWrapperRes(* FSystemWrapper)(TWrapperArg)
Definition: ncbithr.cpp:611
~CUsedTlsBases(void)
Definition: ncbithr.cpp:76
void RemoveReference(void) const
Remove reference to object.
Definition: ncbiobj.hpp:501
Run thread in a N:1 thread:LPW mode.
Definition: ncbithr.hpp:520
static void ClearAllCurrentThread(void)
Clear used TLS-es for the current thread.
Definition: ncbithr.cpp:173
iterator_bool insert(const value_type &val)
Definition: set.hpp:149
bool m_IsRun
if Run() was called for the thread
Definition: ncbithr.hpp:607
static void s_CleanupUsedTlsBases(CUsedTlsBases *tls, void *)
Definition: ncbithr.cpp:131
Internal structure to store all three pointers in the same TLS.
Definition: ncbithr.hpp:114
TThreadHandle m_Handle
platform-dependent thread handle
Definition: ncbithr.hpp:606
static void InitializeMainThreadId(void)
Initialize main thread's TID.
Definition: ncbithr.cpp:442
static CThread * GetCurrentThread(void)
Get current CThread object (or NULL, if main thread)
Definition: ncbithr.cpp:455
#define NULL
Definition: ncbistd.hpp:225
static void SetCurrentThreadName(const CTempString &)
Set name for the current thread.
Definition: ncbithr.cpp:876
bool m_IsJoined
if Join() was called for the thread
Definition: ncbithr.hpp:609
pthread_key_t TTlsKey
Define internal TLS key type.
void ClearAll(void)
The function must be called before thread termination when using native threads instead of CThread...
Definition: ncbithr.cpp:81
static bool sm_MainThreadIdInitialized
Definition: ncbithr.cpp:419
pid_t TPid
Turn on/off workaround for linux PID and PPID.
#define xncbi_Validate(expression, message)
Definition: ncbidbg_p.hpp:52
void EnterWrapper(void)
Definition: ncbithr.cpp:353
typedef NCBI_PARAM_TYPE(Thread, Catch_Unhandled_Exceptions) TParamThreadCatchExceptions
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:101
static CUsedTlsBases & GetUsedTlsBases(void)
Get the list of used TLS-es for the current thread.
Definition: ncbithr.cpp:150
static TThreadSystemID GetCurrentThreadSystemID(void)
Get the current thread ID.
Definition: ncbimtx.hpp:137
unsigned int DWORD
Definition: sqltypes.h:98
static void GetSystemID(TThreadSystemID *id)
Get system ID of the current thread - for internal use only.
Definition: ncbithr.cpp:864
static TWrapperRes Wrapper(TWrapperArg arg)
Function to use (internally) as the thread's startup function.
Definition: ncbithr.cpp:481
TTlsKey m_Key
Definition: ncbithr.hpp:108
static void s_CleanupMainUsedTlsBases(CUsedTlsBases &tls)
Definition: ncbithr.cpp:136
static TID GetSelf(void)
Definition: ncbithr.cpp:462
void x_InitializeThreadId(void)
initalize new thread id, must be called from Wrapper().
Definition: ncbithr.cpp:431
TTlsSet m_UsedTls
Definition: ncbithr.hpp:482
int TRunMode
Bitwise OR'd flags for thread creation passed to Run().
Definition: ncbithr.hpp:529
void s_TlsSetValue(TTlsKey &key, void *data, const char *err_message)
Definition: ncbithr.cpp:244
static const CThread::TID kMainThreadId
Definition: ncbithr.cpp:420
static DECLARE_TLS_VAR(CThread *, sx_ThreadPtr)
STlsData * x_GetTlsData(void) const
Helper method to get the STlsData*.
Definition: ncbithr.hpp:670
bool m_IsDetached
if the thread is detached
Definition: ncbithr.hpp:608
static int sx_GetNextThreadId(void)
Definition: ncbithr.cpp:423
static TWrapperRes ThreadWrapperCallerImpl(TWrapperArg arg)
Definition: ncbithr.cpp:613
NCBI_PARAM_DECL(bool, Thread, Catch_Unhandled_Exceptions)
void * m_ExitData
as returned by Main() or passed to Exit()
Definition: ncbithr.hpp:612
virtual void OnExit(void)
Override this to execute finalization code.
Definition: ncbithr.cpp:858
typedef HANDLE(WINAPI *FCreateToolHelp32Snapshot)(DWORD dwFlags
void * TWrapperRes
Define platform-dependent result wrapper.
Definition: testodbc.c:30
void SetValue(TValue *value, FCleanup cleanup=0, void *cleanup_data=0)
Definition: ncbithr.hpp:312
unsigned int TID
Get ID of current thread (for main thread it is always zero).
Definition: ncbithr.hpp:564
static void CleanupTlsData(void *data)
Definition: ncbithr.cpp:181
static CSafeStatic< CUsedTlsBases > s_MainUsedTlsBases(0, s_CleanupMainUsedTlsBases, CSafeStaticLifeSpan::eLifeSpan_Long)
virtual void * Main(void)=0
Derived (user-created) class must provide a real thread function.
if(yy_accept[yy_current_state])
char value[7]
Definition: config.c:428
void erase(iterator pos)
Definition: set.hpp:151
static void Exit(void *exit_data)
Cancel current thread.
Definition: ncbithr.cpp:824
void s_PosixTlsCleanup(void *ptr)
Definition: ncbithr.cpp:193
#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:454
void * m_CleanupData
Definition: ncbithr.hpp:117
bool Discard(void)
If the thread has not been Run() yet, then schedule the thread object for destruction, and return TRUE.
Definition: ncbithr.cpp:841
CTlBase –.
Definition: ncbithr.hpp:66
bool m_AutoDestroy
Indicates if object should be destroyed in destructor.
Definition: ncbithr.hpp:110
void * TWrapperArg
Define platform-dependent argument wrapper.
Failed to control thread's state.
Definition: ncbithr.hpp:642
void x_Destroy(void)
Destroy thread data.
Definition: ncbithr.cpp:217
void x_Reset(void)
Helper method to reset thread data.
Definition: ncbithr.cpp:322
CUsedTlsBases(void)
Definition: ncbithr.cpp:71
void clear()
Definition: set.hpp:153
static volatile unsigned int sm_ThreadsCount
Total amount of threads.
Definition: ncbithr.hpp:622
static CStaticTls< CUsedTlsBases > sm_UsedTlsBases
Definition: ncbithr.hpp:484
#define _ASSERT
bool m_IsTerminated
if Exit() was called for the thread
Definition: ncbithr.hpp:610
static void Init(void)
Init TLS, call before creating thread.
Definition: ncbithr.cpp:167
void x_Init(void)
Initialize thread data.
Definition: ncbithr.cpp:199
~CExitThreadException(void)
Definition: ncbithr.cpp:380
DEFINE_STATIC_MUTEX(s_TlsCleanupMutex)
void Register(CTlsBase *tls)
Definition: ncbithr.cpp:110
bool x_DeleteTlsData(void)
Deletes STlsData* structure and managed pointer Returns true if CTlsBase must be deregistered from cu...
Definition: ncbithr.cpp:298
virtual ~CThread(void)
To be called only internally! NOTE: destructor of the derived (user-provided) class should be declare...
Definition: ncbithr.cpp:591
void Detach(void)
Inform the thread that user does not need to wait for its termination.
Definition: ncbithr.cpp:751
virtual const char * GetErrCodeString(void) const
Translate from the error code value to its string representation.
Definition: ncbithr.cpp:882
const char * data(void) const
Return a pointer to the array represented.
Definition: tempstr.hpp:353
CThread(void)
Constructor.
Definition: ncbithr.cpp:569
void Deregister(CTlsBase *tls)
Definition: ncbithr.cpp:121
virtual void DoDeleteThisObject(void)
Mark this object as allocated in heap – object can be deleted.
Definition: ncbiobj.cpp:892
void AddReference(void) const
Add reference to object.
Definition: ncbiobj.hpp:490
#define NCBI_CATCH_ALL_X(err_subcode, message)
Definition: ncbiexpt.hpp:458
void Join(void **exit_data=0)
Wait for the thread termination.
Definition: ncbithr.cpp:781
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:98
unsigned int
Definition: types.hpp:1153
void Reset(void)
Reset reference object.
Definition: ncbiobj.hpp:756
T & Get(void)
Create the variable if not created yet, return the reference.
NCBI_PARAM_DEF_EX(bool, Thread, Catch_Unhandled_Exceptions, true, 0, THREAD_CATCH_UNHANDLED_EXCEPTIONS)
unsigned int GetCpuCount(void)
System/memory information.
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:426
FCleanupBase m_CleanupFunc
Definition: ncbithr.hpp:116
Modified on Sat Apr 22 17:06:27 2017 by modify_doxy.py rev. 533848