DSL
Threading.cpp
1 //@AUTOHEADER@BEGIN@
2 /***********************************************************************\
3 | Drift Standard Libraries v1.01 |
4 | Copyright 2010-2023 Drift Solutions / Indy Sams |
5 | Docs and more information available at https://www.driftsolutions.dev |
6 | This file released under the 3-clause BSD license, |
7 | see included DSL.LICENSE.TXT file for details. |
8 \***********************************************************************/
9 //@AUTOHEADER@END@
10 
11 #include <drift/dslcore.h>
12 #include <drift/Mutex.h>
13 #include <drift/Threading.h>
14 #include <drift/GenLib.h>
15 #if defined(DSL_THREADING_USE_C11)
16 #define DSL_LIST_TYPE unordered_set
17 #include <unordered_set>
18 #include <thread> // std::this_thread::sleep_for
19 #include <chrono> // std::chrono::seconds
20 #else
21 #define DSL_LIST_TYPE set
22 #include <set>
23 #endif
24 #if defined(WIN32)
25 #include <process.h>
26 #endif
27 
28 DSL_Mutex * DSL_Thread_Mutex()
29 {
30  static DSL_Mutex actualMutex;
31  return &actualMutex;
32 }
33 typedef DSL_LIST_TYPE<DSL_THREAD_INFO *> DSL_List_Type;
34 DSL_List_Type DSL_List;
35 uint32 DSL_NoThreads=0;
36 
37 void DSL_UnregisterThread(DSL_THREAD_INFO * tt) {
38  AutoMutexPtr(DSL_Thread_Mutex());
39  DSL_List_Type::iterator x = DSL_List.find(tt);
40  if (x != DSL_List.end()) {
41  DSL_List.erase(x);
42  }
43 #if defined(WIN32)
44  if (tt->hThread) {
45  CloseHandle(tt->hThread);
46  }
47 #endif
48  dsl_free(tt);
49  DSL_NoThreads--;
50 }
51 
52 #ifdef WIN32
53 typedef struct tagTHREADNAME_INFO
54 {
55  DWORD dwType; // must be 0x1000
56  LPCSTR szName; // pointer to name (in user addr space)
57  DWORD dwThreadID; // thread ID (-1=caller thread)
58  DWORD dwFlags; // reserved for future use, must be zero
59 } THREADNAME_INFO;
60 
61 DSL_API void DSL_CC DSL_SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) {
62  if (szThreadName == NULL) { return; }
63  THREADNAME_INFO info;
64  info.dwType = 0x1000;
65  info.szName = szThreadName;
66  info.dwThreadID = dwThreadID;
67  info.dwFlags = 0;
68 
69  __try {
70 #ifdef _WIN64
71  RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
72 #else
73  RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info );
74 #endif
75  }
76  __except (EXCEPTION_CONTINUE_EXECUTION) {
77  }
78 }
79 #else
80 DSL_API void DSL_CC DSL_SetThreadName(pthread_t thread_id, const char * szThreadName) {
81  if (szThreadName == NULL) { return; }
82  pthread_setname_np(thread_id, szThreadName);
83  /*
84  #if defined(PR_SET_NAME)
85  if (pthread_self() == thread_id) {
86  prctl(PR_SET_NAME, szThreadName, 0, 0, 0);
87  }
88 #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
89  pthread_set_name_np(pthread_self(), name);
90 #elif defined(MAC_OSX)
91  pthread_setname_np(name);
92 #else
93  */
94 }
95 #endif
96 
97 DSL_THREAD_INFO * DSL_CC DSL_StartThread(ThreadProto Thread,void * Parm, const char * desc, int32 id) {
98  DSL_THREAD_INFO * ret = (DSL_THREAD_INFO *)dsl_malloc(sizeof(DSL_THREAD_INFO));
99  memset(ret, 0, sizeof(DSL_THREAD_INFO));
100 
101  DSL_Thread_Mutex()->Lock();
102  DSL_List.insert(ret);
103  DSL_NoThreads++;
104  DSL_Thread_Mutex()->Release();
105 
106  if (desc) { sstrcpy(ret->desc, desc); }
107  ret->id = id;
108  ret->parm = Parm;
109  ret->RemoveMe = DSL_UnregisterThread;
110 
111 #if defined(WIN32)
112  unsigned int ThreadID=0;
113  ret->hThread = (HANDLE)_beginthreadex(NULL, 0, Thread, ret, 0, &ThreadID);
114  if (ret->hThread != 0) {
115  DSL_SetThreadName(ThreadID, desc);
116  } else {
117  DSL_UnregisterThread(ret);
118  return NULL;
119  }
120 #else
121  if (pthread_create(&ret->hThread, NULL, Thread, (void *)ret) == 0) {
122  DSL_SetThreadName(ret->hThread, desc);
123  pthread_detach(ret->hThread); // tells OS that it can reclaim used memory after thread exits
124  } else {
125  DSL_UnregisterThread(ret);
126  return NULL;
127  }
128 #endif
129 
130  return ret;
131 }
132 
133 bool DSL_CC DSL_StartThreadNoRecord(ThreadProto Thread,void * Parm, const char * Desc) {
134 #if defined(WIN32)
135  unsigned int ThreadID=0;
136  HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, Thread, Parm, 0, &ThreadID);
137  if (hThread != 0) {
138  DSL_SetThreadName(ThreadID, Desc);
139  CloseHandle(hThread);
140  return true;
141  }
142 #else
143  pthread_t a_thread;
144  if (pthread_create(&a_thread, NULL, Thread, Parm) == 0) {
145  DSL_SetThreadName(a_thread, Desc);
146  pthread_detach(a_thread); // tells OS that it can reclaim used memory after thread exits
147  return true;
148  }
149 #endif
150  return false;
151 }
152 
153 bool DSL_CC DSL_KillThread(DSL_THREAD_INFO * tt) {
154 #if defined(WIN32)
155  TerminateThread(tt->hThread, 0);
156  DSL_UnregisterThread(tt);
157  return true;
158 #else
159  if (pthread_cancel(tt->hThread) == 0) {
160  DSL_UnregisterThread(tt);
161  return true;
162  }
163  return false;
164 #endif
165 }
166 
167 void DSL_CC DSL_PrintRunningThreads() {
168  AutoMutexPtr(DSL_Thread_Mutex());
169 
170  printf("Running threads:");
171  for (DSL_List_Type::iterator x = DSL_List.begin(); x != DSL_List.end(); x++) {
172  DSL_THREAD_INFO * tScan = *x;
173  printf(" [%s]", tScan->desc);
174  }
175  printf("\n");
176 }
177 
178 void DSL_CC DSL_PrintRunningThreadsWithID(int id) {
179  AutoMutexPtr(DSL_Thread_Mutex());
180 
181  printf("Running threads:");
182  for (DSL_List_Type::iterator x = DSL_List.begin(); x != DSL_List.end(); x++) {
183  DSL_THREAD_INFO * tScan = *x;
184  if (tScan->id == id) {
185  printf(" [%s]",tScan->desc);
186  }
187  }
188  printf("\n");
189 }
190 
191 uint32 DSL_CC DSL_NumThreads() {
192  AutoMutexPtr(DSL_Thread_Mutex());
193  return DSL_NoThreads;
194 }
195 
196 uint32 DSL_CC DSL_NumThreadsWithID(int id) {
197  uint32 ret = 0;
198  AutoMutexPtr(DSL_Thread_Mutex());
199  for (DSL_List_Type::iterator x = DSL_List.begin(); x != DSL_List.end(); x++) {
200  DSL_THREAD_INFO * tScan = *x;
201  if (tScan->id == id) { ret++; }
202  }
203  return ret;
204 }
205 
206 void DSL_CC safe_sleep(int sleepfor, bool inmilli) {
207 #if defined(DSL_THREADING_USE_C11)
208  this_thread::sleep_for(inmilli ? chrono::milliseconds(sleepfor) : chrono::seconds(sleepfor));
209 #elif defined(WIN32)
210  if (!inmilli) {
211  Sleep(1000 * sleepfor);
212  } else {
213  Sleep(sleepfor);
214  }
215 #else // Unix-style
216  struct timespec delta, rem;
217  if (!inmilli) {
218  delta.tv_sec = sleepfor;
219  delta.tv_nsec= 0;
220  } else {
221  delta.tv_sec = sleepfor / 1000;
222  sleepfor -= (delta.tv_sec * 1000);
223  delta.tv_nsec= sleepfor * 1000000;
224  }
225 
226  while (nanosleep(&delta,&rem) == -1 && errno == EINTR) {
227  memcpy(&delta, &rem, sizeof(rem));
228  }
229 #endif
230 }
DSL_API void DSL_CC dsl_free(void *ptr)
Definition: dsl.cpp:345
#define sstrcpy(x, y)
Definition: GenLib.h:102
uint32 DSL_CC DSL_NumThreads()
Number of active threads (does not count threads started with DSL_StartThreadNoRecord)
Definition: Threading.cpp:191
bool DSL_CC DSL_StartThreadNoRecord(ThreadProto Thread, void *Parm, const char *Desc)
Definition: Threading.cpp:133
DSL_THREAD_INFO *DSL_CC DSL_StartThread(ThreadProto Thread, void *Parm, const char *desc, int32 id)
Definition: Threading.cpp:97
uint32 DSL_CC DSL_NumThreadsWithID(int id)
Number of active threads with matching id #.
Definition: Threading.cpp:196
void * parm
User-specified parameter.
Definition: Threading.h:40
int32 id
User-specified ID, if DSL_StartThread() is used with no ID, it defaults to -1.
Definition: Threading.h:39