+11
-14
include/SDL3/SDL_thread.h
+11
-14
include/SDL3/SDL_thread.h
···
105
105
/**
106
106
* The SDL thread state.
107
107
*
108
-
* SDL stores the current state of a thread in an atomic int. The current
109
-
* state of a thread can be checked by calling SDL_GetThreadState.
108
+
* The current state of a thread can be checked by calling SDL_GetThreadState.
110
109
*
111
110
* \since This enum is available since SDL 3.1.3.
112
111
*
···
114
113
*/
115
114
typedef enum SDL_ThreadState
116
115
{
117
-
SDL_THREAD_STATE_ALIVE,
118
-
SDL_THREAD_STATE_DETACHED,
119
-
SDL_THREAD_STATE_ZOMBIE,
120
-
SDL_THREAD_STATE_CLEANED,
116
+
SDL_THREAD_UNKNOWN, /**< The thread is not valid */
117
+
SDL_THREAD_ALIVE, /**< The thread is currently running */
118
+
SDL_THREAD_DETACHED, /**< The thread is detached and can't be waited on */
119
+
SDL_THREAD_COMPLETE, /**< The thread has finished and should be cleaned up with SDL_WaitThread() */
121
120
} SDL_ThreadState;
122
121
123
122
/**
···
408
407
/**
409
408
* Wait for a thread to finish.
410
409
*
411
-
* Threads that haven't been detached will remain (as a "zombie") until this
410
+
* Threads that haven't been detached will remain until this
412
411
* function cleans them up. Not doing so is a resource leak.
413
412
*
414
413
* Once a thread has been cleaned up through this function, the SDL_Thread
415
414
* that references it becomes invalid and should not be referenced again. As
416
415
* such, only one thread may call SDL_WaitThread() on another.
417
416
*
418
-
* The return code for the thread function is placed in the area pointed to by
417
+
* The return code from the thread function is placed in the area pointed to by
419
418
* `status`, if `status` is not NULL.
420
419
*
421
420
* You may not wait on a thread that has been used in a call to
···
429
428
*
430
429
* \param thread the SDL_Thread pointer that was returned from the
431
430
* SDL_CreateThread() call that started this thread.
432
-
* \param status pointer to an integer that will receive the value returned
433
-
* from the thread function by its 'return', or NULL to not
434
-
* receive such value back.
431
+
* \param status a pointer filled in with the value returned
432
+
* from the thread function by its 'return', or -1 if the thread has been detached or isn't valid, may be NULL.
435
433
*
436
434
* \since This function is available since SDL 3.1.3.
437
435
*
···
443
441
/**
444
442
* Get the current state of a thread.
445
443
*
446
-
* \param thread the thread whose status you want to check.
447
-
* \returns the current state of a thread as defined in the SDL_ThreadState
448
-
* enum.
444
+
* \param thread the thread to query.
445
+
* \returns the current state of a thread, or SDL_THREAD_UNKNOWN if the thread isn't valid.
449
446
*
450
447
* \since This function is available since SDL 3.2.0.
451
448
*
+3
src/SDL_utils.c
+3
src/SDL_utils.c
+1
src/SDL_utils_c.h
+1
src/SDL_utils_c.h
+37
-18
src/thread/SDL_thread.c
+37
-18
src/thread/SDL_thread.c
···
306
306
#endif // SDL_THREADS_DISABLED
307
307
}
308
308
309
+
static bool ThreadValid(SDL_Thread *thread)
310
+
{
311
+
return SDL_ObjectValid(thread, SDL_OBJECT_TYPE_THREAD);
312
+
}
313
+
309
314
void SDL_RunThread(SDL_Thread *thread)
310
315
{
311
316
void *userdata = thread->userdata;
···
326
331
SDL_CleanupTLS();
327
332
328
333
// Mark us as ready to be joined (or detached)
329
-
if (!SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_ZOMBIE)) {
334
+
if (!SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_COMPLETE)) {
330
335
// Clean up if something already detached us.
331
-
if (SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_STATE_DETACHED, SDL_THREAD_STATE_CLEANED)) {
336
+
if (SDL_GetThreadState(thread) == SDL_THREAD_DETACHED) {
337
+
SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false);
332
338
SDL_free(thread->name); // Can't free later, we've already cleaned up TLS
333
339
SDL_free(thread);
334
340
}
···
364
370
return NULL;
365
371
}
366
372
thread->status = -1;
367
-
SDL_SetAtomicInt(&thread->state, SDL_THREAD_STATE_ALIVE);
373
+
SDL_SetAtomicInt(&thread->state, SDL_THREAD_ALIVE);
368
374
369
375
// Set up the arguments for the thread
370
376
if (name) {
···
378
384
thread->userfunc = fn;
379
385
thread->userdata = userdata;
380
386
thread->stacksize = stacksize;
387
+
388
+
SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, true);
381
389
382
390
// Create the thread and go!
383
391
if (!SDL_SYS_CreateThread(thread, pfnBeginThread, pfnEndThread)) {
384
392
// Oops, failed. Gotta free everything
393
+
SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false);
385
394
SDL_free(thread->name);
386
395
SDL_free(thread);
387
396
thread = NULL;
···
420
429
421
430
SDL_ThreadID SDL_GetThreadID(SDL_Thread *thread)
422
431
{
423
-
SDL_ThreadID id;
432
+
SDL_ThreadID id = 0;
424
433
425
434
if (thread) {
426
-
id = thread->threadid;
435
+
if (ThreadValid(thread)) {
436
+
id = thread->threadid;
437
+
}
427
438
} else {
428
439
id = SDL_GetCurrentThreadID();
429
440
}
···
432
443
433
444
const char *SDL_GetThreadName(SDL_Thread *thread)
434
445
{
435
-
if (thread) {
446
+
if (ThreadValid(thread)) {
436
447
return SDL_GetPersistentString(thread->name);
437
448
} else {
438
449
return NULL;
···
446
457
447
458
void SDL_WaitThread(SDL_Thread *thread, int *status)
448
459
{
449
-
if (thread) {
450
-
SDL_SYS_WaitThread(thread);
460
+
if (!ThreadValid(thread) || SDL_GetThreadState(thread) == SDL_THREAD_DETACHED) {
451
461
if (status) {
452
-
*status = thread->status;
462
+
*status = -1;
453
463
}
454
-
SDL_free(thread->name);
455
-
SDL_free(thread);
464
+
return;
456
465
}
466
+
467
+
SDL_SYS_WaitThread(thread);
468
+
if (status) {
469
+
*status = thread->status;
470
+
}
471
+
SDL_SetObjectValid(thread, SDL_OBJECT_TYPE_THREAD, false);
472
+
SDL_free(thread->name);
473
+
SDL_free(thread);
457
474
}
458
475
459
476
SDL_ThreadState SDL_GetThreadState(SDL_Thread *thread)
460
477
{
478
+
if (!ThreadValid(thread)) {
479
+
return SDL_THREAD_UNKNOWN;
480
+
}
481
+
461
482
return (SDL_ThreadState)SDL_GetAtomicInt(&thread->state);
462
483
}
463
484
464
485
void SDL_DetachThread(SDL_Thread *thread)
465
486
{
466
-
if (!thread) {
487
+
if (!ThreadValid(thread)) {
467
488
return;
468
489
}
469
490
470
491
// Grab dibs if the state is alive+joinable.
471
-
if (SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_STATE_ALIVE, SDL_THREAD_STATE_DETACHED)) {
492
+
if (SDL_CompareAndSwapAtomicInt(&thread->state, SDL_THREAD_ALIVE, SDL_THREAD_DETACHED)) {
472
493
SDL_SYS_DetachThread(thread);
473
494
} else {
474
495
// all other states are pretty final, see where we landed.
475
-
const int thread_state = SDL_GetAtomicInt(&thread->state);
476
-
if ((thread_state == SDL_THREAD_STATE_DETACHED) || (thread_state == SDL_THREAD_STATE_CLEANED)) {
496
+
SDL_ThreadState thread_state = SDL_GetThreadState(thread);
497
+
if (thread_state == SDL_THREAD_DETACHED) {
477
498
return; // already detached (you shouldn't call this twice!)
478
-
} else if (thread_state == SDL_THREAD_STATE_ZOMBIE) {
499
+
} else if (thread_state == SDL_THREAD_COMPLETE) {
479
500
SDL_WaitThread(thread, NULL); // already done, clean it up.
480
-
} else {
481
-
SDL_assert(0 && "Unexpected thread state");
482
501
}
483
502
}
484
503
}
+1
-1
src/thread/SDL_thread_c.h
+1
-1
src/thread/SDL_thread_c.h
+1
-1
src/thread/n3ds/SDL_systhread.c
+1
-1
src/thread/n3ds/SDL_systhread.c
···
126
126
Detached threads can be waited on, but should NOT be cleaned manually
127
127
as it would result in a fatal error.
128
128
*/
129
-
if (R_SUCCEEDED(res) && SDL_GetAtomicInt(&thread->state) != SDL_THREAD_STATE_DETACHED) {
129
+
if (R_SUCCEEDED(res) && SDL_GetThreadState(thread) != SDL_THREAD_DETACHED) {
130
130
threadFree(thread->handle);
131
131
}
132
132
}