|
5 | 5 | #include <hx/thread/ConditionVariable.hpp> |
6 | 6 | #include <hx/thread/RecursiveMutex.hpp> |
7 | 7 | #include <hx/thread/CountingSemaphore.hpp> |
| 8 | +#include "thread/ThreadImpl.hpp" |
8 | 9 | #include <atomic> |
9 | 10 |
|
10 | | -DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread); |
11 | | - |
12 | | -// Thread number 0 is reserved for the main thread |
13 | | -static std::atomic_int g_nextThreadNumber(1); |
14 | | - |
15 | | - |
16 | | -// How to manage hxThreadInfo references for non haxe threads (main, extenal)? |
17 | | -// HXCPP_THREAD_INFO_PTHREAD - use pthread api |
18 | | -// HXCPP_THREAD_INFO_LOCAL - use thread_local storage |
19 | | -// HXCPP_THREAD_INFO_SINGLETON - use one structure for all threads. Not ideal. |
20 | | - |
21 | | -#if __cplusplus > 199711L && !defined(__BORLANDC__) |
22 | | - #define HXCPP_THREAD_INFO_LOCAL |
23 | | -#elif defined (HXCPP_PTHREADS) |
24 | | - #define HXCPP_THREAD_INFO_PTHREAD |
25 | | -#else |
26 | | - #define HXCPP_THREAD_INFO_SINGLETON |
27 | | -#endif |
28 | | - |
29 | | - |
30 | 11 | // --- Deque ---------------------------------------------------------- |
31 | 12 |
|
32 | 13 | struct Deque : public Array_obj<Dynamic> |
@@ -171,265 +152,49 @@ Dynamic __hxcpp_deque_pop(Dynamic q,bool block) |
171 | 152 | return d->PopFront(block); |
172 | 153 | } |
173 | 154 |
|
174 | | - |
175 | | - |
176 | 155 | // --- Thread ---------------------------------------------------------- |
177 | 156 |
|
178 | | -class hxThreadInfo : public hx::Object |
179 | | -{ |
180 | | -public: |
181 | | - typedef |
182 | | -#if (HXCPP_API_LEVEL>=500) |
183 | | - hx::Callable<void()> |
184 | | -#else |
185 | | - Dynamic |
186 | | -#endif |
187 | | - ThreadFuncType; |
188 | | - |
189 | | - HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdThreadInfo }; |
190 | | - |
191 | | - hxThreadInfo(ThreadFuncType inFunction, int inThreadNumber) |
192 | | - : mFunction(inFunction), mThreadNumber(inThreadNumber), mTLS(0,0) |
193 | | - { |
194 | | - mSemaphore = new HxSemaphore; |
195 | | - mDeque = Deque::Create(); |
196 | | - HX_OBJ_WB_NEW_MARKED_OBJECT(this); |
197 | | - } |
198 | | - hxThreadInfo() |
199 | | - { |
200 | | - mSemaphore = 0; |
201 | | - mDeque = Deque::Create(); |
202 | | - HX_OBJ_WB_NEW_MARKED_OBJECT(this); |
203 | | - } |
204 | | - int GetThreadNumber() const |
205 | | - { |
206 | | - return mThreadNumber; |
207 | | - } |
208 | | - void CleanSemaphore() |
209 | | - { |
210 | | - delete mSemaphore; |
211 | | - mSemaphore = 0; |
212 | | - } |
213 | | - void Send(Dynamic inMessage) |
214 | | - { |
215 | | - mDeque->PushBack(inMessage); |
216 | | - } |
217 | | - Dynamic ReadMessage(bool inBlocked) |
218 | | - { |
219 | | - return mDeque->PopFront(inBlocked); |
220 | | - } |
221 | | - String toString() |
222 | | - { |
223 | | - return String(GetThreadNumber()); |
224 | | - } |
225 | | - void SetTLS(int inID,Dynamic inVal) { |
226 | | - mTLS->__SetItem(inID,inVal); |
227 | | - } |
228 | | - Dynamic GetTLS(int inID) { return mTLS[inID]; } |
229 | | - |
230 | | - void __Mark(hx::MarkContext *__inCtx) |
231 | | - { |
232 | | - HX_MARK_MEMBER(mFunction); |
233 | | - HX_MARK_MEMBER(mTLS); |
234 | | - if (mDeque) |
235 | | - HX_MARK_OBJECT(mDeque); |
236 | | - } |
237 | | - #ifdef HXCPP_VISIT_ALLOCS |
238 | | - void __Visit(hx::VisitContext *__inCtx) |
239 | | - { |
240 | | - HX_VISIT_MEMBER(mFunction); |
241 | | - HX_VISIT_MEMBER(mTLS); |
242 | | - if (mDeque) |
243 | | - HX_VISIT_OBJECT(mDeque); |
244 | | - } |
245 | | - #endif |
246 | | - |
247 | | - |
248 | | - Array<Dynamic> mTLS; |
249 | | - HxSemaphore *mSemaphore; |
250 | | - ThreadFuncType mFunction; |
251 | | - int mThreadNumber; |
252 | | - Deque *mDeque; |
253 | | -}; |
254 | | - |
255 | | - |
256 | | -THREAD_FUNC_TYPE hxThreadFunc( void *inInfo ) |
257 | | -{ |
258 | | - // info[1] will the the "top of stack" - values under this |
259 | | - // (ie info[0] and other stack values) will be in the GC conservative range |
260 | | - hxThreadInfo *info[2]; |
261 | | - info[0] = (hxThreadInfo *)inInfo; |
262 | | - info[1] = 0; |
263 | | - |
264 | | - tlsCurrentThread = info[0]; |
265 | | - |
266 | | - hx::SetTopOfStack((int *)&info[1], true); |
267 | | - |
268 | | - // Release the creation function |
269 | | - info[0]->mSemaphore->Set(); |
270 | | - |
271 | | - // Call the debugger function to annouce that a thread has been created |
272 | | - //__hxcpp_dbg_threadCreatedOrTerminated(info[0]->GetThreadNumber(), true); |
273 | | - |
274 | | - if ( info[0]->mFunction.GetPtr() ) |
275 | | - { |
276 | | - // Try ... catch |
277 | | - info[0]->mFunction(); |
278 | | - } |
279 | | - |
280 | | - // Call the debugger function to annouce that a thread has terminated |
281 | | - //__hxcpp_dbg_threadCreatedOrTerminated(info[0]->GetThreadNumber(), false); |
282 | | - |
283 | | - hx::UnregisterCurrentThread(); |
284 | | - |
285 | | - tlsCurrentThread = 0; |
286 | | - |
287 | | - THREAD_FUNC_RET |
288 | | -} |
289 | | - |
290 | | - |
291 | 157 | #if (HXCPP_API_LEVEL>=500) |
292 | 158 | Dynamic __hxcpp_thread_create(hx::Callable<void()> inStart) |
293 | 159 | #else |
294 | 160 | Dynamic __hxcpp_thread_create(Dynamic inStart) |
295 | 161 | #endif |
296 | 162 | { |
297 | | - #ifdef EMSCRIPTEN |
298 | | - return hx::Throw( HX_CSTRING("Threads are not supported on Emscripten") ); |
299 | | - #else |
300 | | - int threadNumber = g_nextThreadNumber++; |
301 | | - |
302 | | - hxThreadInfo *info = new hxThreadInfo(inStart, threadNumber); |
303 | | - |
304 | | - hx::GCPrepareMultiThreaded(); |
305 | | - hx::EnterGCFreeZone(); |
306 | | - |
307 | | - bool ok = HxCreateDetachedThread(hxThreadFunc, info); |
308 | | - if (ok) |
309 | | - { |
310 | | - info->mSemaphore->Wait(); |
311 | | - } |
312 | | - |
313 | | - hx::ExitGCFreeZone(); |
314 | | - info->CleanSemaphore(); |
315 | | - |
316 | | - if (!ok) |
317 | | - throw Dynamic( HX_CSTRING("Could not create thread") ); |
318 | | - return info; |
319 | | - #endif |
320 | | -} |
321 | | - |
322 | | -#ifdef HXCPP_THREAD_INFO_PTHREAD |
323 | | -static pthread_key_t externThreadInfoKey;; |
324 | | -static pthread_once_t key_once = PTHREAD_ONCE_INIT; |
325 | | -static void destroyThreadInfo(void *i) |
326 | | -{ |
327 | | - hx::Object **threadRoot = (hx::Object **)i; |
328 | | - hx::GCRemoveRoot(threadRoot); |
329 | | - delete threadRoot; |
330 | | -} |
331 | | -static void make_key() |
332 | | -{ |
333 | | - pthread_key_create(&externThreadInfoKey, destroyThreadInfo); |
334 | | -} |
335 | | -#elif defined(HXCPP_THREAD_INFO_LOCAL) |
336 | | -struct ThreadInfoHolder |
337 | | -{ |
338 | | - hx::Object **threadRoot; |
339 | | - ThreadInfoHolder() : threadRoot(0) { } |
340 | | - ~ThreadInfoHolder() |
341 | | - { |
342 | | - if (threadRoot) |
343 | | - { |
344 | | - hx::GCRemoveRoot(threadRoot); |
345 | | - delete threadRoot; |
346 | | - } |
347 | | - } |
348 | | - void set(hx::Object **info) { threadRoot = info; } |
349 | | - hxThreadInfo *get() { return threadRoot ? (hxThreadInfo *)*threadRoot : nullptr; } |
350 | | - |
351 | | -}; |
352 | | -static thread_local ThreadInfoHolder threadHolder; |
353 | | -#else |
354 | | -static hx::Object **sMainThreadInfoRoot = 0; |
355 | | -#endif |
356 | | - |
357 | | -static hxThreadInfo *GetCurrentInfo(bool createNew = true) |
358 | | -{ |
359 | | - hxThreadInfo *info = tlsCurrentThread; |
360 | | - if (!info) |
361 | | - { |
362 | | - #ifdef HXCPP_THREAD_INFO_PTHREAD |
363 | | - pthread_once(&key_once, make_key); |
364 | | - hxThreadInfo **pp = (hxThreadInfo **)pthread_getspecific(externThreadInfoKey); |
365 | | - if (pp) |
366 | | - info = *pp; |
367 | | - #elif defined(HXCPP_THREAD_INFO_LOCAL) |
368 | | - info = threadHolder.get(); |
369 | | - #else |
370 | | - if (sMainThreadInfoRoot) |
371 | | - info = (hxThreadInfo *)*sMainThreadInfoRoot; |
372 | | - #endif |
373 | | - } |
374 | | - |
375 | | - if (!info && createNew) |
376 | | - { |
377 | | - // New, non-haxe thread - might be the first thread, or might be a new |
378 | | - // foreign thread. |
379 | | - info = new hxThreadInfo(null(), 0); |
380 | | - hx::Object **threadRoot = new hx::Object *; |
381 | | - *threadRoot = info; |
382 | | - hx::GCAddRoot(threadRoot); |
383 | | - #ifdef HXCPP_THREAD_INFO_PTHREAD |
384 | | - pthread_setspecific(externThreadInfoKey, threadRoot); |
385 | | - #elif defined(HXCPP_THREAD_INFO_LOCAL) |
386 | | - threadHolder.set(threadRoot); |
387 | | - #else |
388 | | - sMainThreadInfoRoot = threadRoot; |
389 | | - #endif |
390 | | - } |
391 | | - return info; |
| 163 | + return hx::thread::Thread_obj::create(inStart); |
392 | 164 | } |
393 | 165 |
|
394 | 166 | Dynamic __hxcpp_thread_current() |
395 | 167 | { |
396 | | - return GetCurrentInfo(); |
| 168 | + return hx::thread::Thread_obj::current(); |
397 | 169 | } |
398 | 170 |
|
399 | 171 | void __hxcpp_thread_send(Dynamic inThread, Dynamic inMessage) |
400 | 172 | { |
401 | | - hxThreadInfo *info = dynamic_cast<hxThreadInfo *>(inThread.mPtr); |
402 | | - if (!info) |
403 | | - throw HX_INVALID_OBJECT; |
404 | | - info->Send(inMessage); |
| 173 | + hx::Throw(HX_CSTRING("Not Implemented")); |
405 | 174 | } |
406 | 175 |
|
407 | 176 | Dynamic __hxcpp_thread_read_message(bool inBlocked) |
408 | 177 | { |
409 | | - hxThreadInfo *info = GetCurrentInfo(); |
410 | | - return info->ReadMessage(inBlocked); |
| 178 | + return hx::Throw(HX_CSTRING("Not Implemented")); |
411 | 179 | } |
412 | 180 |
|
413 | 181 | bool __hxcpp_is_current_thread(hx::Object *inThread) |
414 | 182 | { |
415 | | - hxThreadInfo *info = tlsCurrentThread; |
416 | | - return info==inThread; |
| 183 | + return inThread == hx::thread::Thread_obj::current(); |
417 | 184 | } |
418 | 185 |
|
419 | 186 | // --- TLS ------------------------------------------------------------ |
420 | 187 |
|
421 | 188 | Dynamic __hxcpp_tls_get(int inID) |
422 | 189 | { |
423 | | - return GetCurrentInfo()->GetTLS(inID); |
| 190 | + return reinterpret_cast<hx::thread::ThreadImpl_obj*>(hx::thread::Thread_obj::current().GetPtr())->getSlot(inID); |
424 | 191 | } |
425 | 192 |
|
426 | 193 | void __hxcpp_tls_set(int inID,Dynamic inVal) |
427 | 194 | { |
428 | | - GetCurrentInfo()->SetTLS(inID,inVal); |
| 195 | + reinterpret_cast<hx::thread::ThreadImpl_obj*>(hx::thread::Thread_obj::current().GetPtr())->setSlot(inID, inVal); |
429 | 196 | } |
430 | 197 |
|
431 | | - |
432 | | - |
433 | 198 | // --- Mutex ------------------------------------------------------------ |
434 | 199 |
|
435 | 200 | Dynamic __hxcpp_mutex_create() |
@@ -636,13 +401,7 @@ void __hxcpp_lock_release(Dynamic inlock) |
636 | 401 |
|
637 | 402 | int __hxcpp_GetCurrentThreadNumber() |
638 | 403 | { |
639 | | - // Can't allow GetCurrentInfo() to create the main thread's info |
640 | | - // because that can cause a call loop. |
641 | | - hxThreadInfo *threadInfo = GetCurrentInfo(false); |
642 | | - if (!threadInfo) { |
643 | | - return 0; |
644 | | - } |
645 | | - return threadInfo->GetThreadNumber(); |
| 404 | + return hx::thread::Thread_obj::id(); |
646 | 405 | } |
647 | 406 |
|
648 | 407 | // --- Atomic --- |
|
0 commit comments