HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SYS_SequentialThreadIndex.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: SYS_UniqueThreadIndex.h ( SYS Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __SYS_UniqueThreadIndex__
12 #define __SYS_UniqueThreadIndex__
13 
14 #include "SYS_API.h"
15 #include "SYS_AtomicInt.h"
16 #include "SYS_MemoryOrder.h"
17 
18 #include <cstddef>
19 #if defined(LINUX) || defined(MBSD)
20 #include <pthread.h>
21 #endif
22 
23 
24 /// Helper class to ensure each thread gets allocated a sequential index that
25 /// can be used to uniquely associate a thread.
27 {
28 public:
29  enum { FIRST_INDEX = 1 };
30 
31  /// Returns the sequential thread index for the current thread.
32  /// The first index is always the value of FIRST_INDEX, usually the
33  /// main thread.
34  static inline int get();
35 
36  /// Returns the index that will be assigned to the next thread that calls
37  /// get() for the first time.
38  static inline int next();
39 private:
40  static SYS_AtomicInt32 myNextIndex;
41 
42 #if defined(WIN32)
43  static int myTlsIndex;
44 #elif defined(LINUX) || defined(MBSD)
45  static pthread_key_t myTlsKey;
46 
47  // Define a DSO constructor function. This is called prior to any
48  // initialization of static objects in the same DSO.
49  static __attribute__((constructor)) void initDSO();
50 #endif
51 
52 };
53 
54 SYS_API inline int SYSgetSTID()
55 {
57 }
58 
59 
60 // === Implementation ===
61 int
63 {
64  return myNextIndex.load(SYS_MEMORY_ORDER_SEQ_CST) + FIRST_INDEX;
65 }
66 
67 
68 #if defined(WIN32)
69 // We don't want to drag the Win32 headers in for just two functions, so
70 // we just forward declare them here.
71 extern "C" {
72  __declspec(dllimport) void *__stdcall TlsGetValue(unsigned long);
73  __declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void *);
74 };
75 
76 int
78 {
79  ptrdiff_t tid;
80 
81  tid = reinterpret_cast<ptrdiff_t>(::TlsGetValue(myTlsIndex));
82  if (tid < FIRST_INDEX)
83  {
84  tid = myNextIndex.exchangeAdd(1) + FIRST_INDEX;
85  ::TlsSetValue(myTlsIndex, reinterpret_cast<void *>(tid));
86  }
87 
88  return static_cast<int>(tid);
89 }
90 
91 
92 
93 #elif defined(LINUX) || defined(MBSD)
94 
95 int
97 {
98  // *** Note for performance freaks, who're likely here because there ***
99  // *** are calls to pthread_getspecific in the profiler output: ***
100  // *** On Linux, it turns out that pthread_getspecific and __thread ***
101  // *** have about the same performance, since the implementation is ***
102  // *** roughly the same. (__thread is implemented on top of calls to ***
103  // *** __tls_get_addr, which has about the same implementation ***
104  // *** complexity as pthread_getspecific, or about 2-3 MOV instructions ***
105  // *** in the most-often used case; e.g. normal TLS key creation usage, ***
106  // *** threads not popping in-and-out of existence uncontrollably). ***
107  // *** On OSX, however the __thread directive is not supported at all ***
108  // *** since the Mach-O format has no native support, like ELF does. ***
109  // *** However, unlike the glibc versions, pthread_getspecific on OSX ***
110  // *** is implemented with a single MOV instruction, albeit through a ***
111  // *** naked function call. ***
112  ptrdiff_t tid;
113  tid = reinterpret_cast<ptrdiff_t>(::pthread_getspecific(myTlsKey));
114  if (tid < FIRST_INDEX)
115  {
116  tid = myNextIndex.exchangeAdd(1) + FIRST_INDEX;
117  ::pthread_setspecific(myTlsKey, reinterpret_cast<void *>(tid));
118  }
119 
120  return static_cast<int>(tid);
121 }
122 
123 #endif
124 
125 
126 #endif // __SYS_UniqueThreadIndex__
void
Definition: png.h:1083
T exchangeAdd(T val)
__attribute__((visibility("default")))
auto get(const UT_JSONValue::map_traverser &m) -> decltype(m.key())
Definition: UT_JSONValue.h:972
T load(SYS_MemoryOrder order=SYS_MEMORY_ORDER_SEQ_CST) const
SYS_API int SYSgetSTID()
#define SYS_API
Definition: SYS_API.h:11