archivemuh
This commit is contained in:
19
src/thread/CMakeLists.txt
Normal file
19
src/thread/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
# Copyright (c) 2025 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
thread.c
|
||||
threadmutex.c
|
||||
)
|
||||
|
||||
# Compiler flags.
|
||||
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
|
||||
target_compile_definitions(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
DUSK_THREAD_PTHREAD=1
|
||||
)
|
||||
endif()
|
101
src/thread/thread.c
Normal file
101
src/thread/thread.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "thread.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
void threadInit(thread_t *thread, const threadcallback_t callback) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
assertNotNull(callback, "Thread callback cannot be NULL.");
|
||||
|
||||
memoryZero(thread, sizeof(thread_t));
|
||||
|
||||
thread->state = THREAD_STATE_STOPPED;
|
||||
thread->callback = callback;
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
thread->threadId = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadStartRequest(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
|
||||
printf("Starting thread...\n");
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
thread->state = THREAD_STATE_STARTING;
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
printf("Thread marked starting.\n");
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
assertTrue(thread->threadId == 0, "Thread id not 0.");
|
||||
|
||||
pthread_create(
|
||||
&thread->threadId,
|
||||
NULL,
|
||||
(void * (*)(void *))threadHandler,
|
||||
thread
|
||||
);
|
||||
pthread_detach(thread->threadId);
|
||||
#endif
|
||||
|
||||
printf("Thread created.\n");
|
||||
}
|
||||
|
||||
void threadStopRequest(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
|
||||
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
if(thread->state != THREAD_STATE_STOPPED) {
|
||||
thread->state = THREAD_STATE_STOP_REQUESTED;
|
||||
}
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
}
|
||||
|
||||
void threadStart(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
|
||||
threadStartRequest(thread);
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
threadMutexWaitLock(&thread->stateMutex);
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
printf("Thread is now running.\n");
|
||||
}
|
||||
|
||||
void threadStop(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
|
||||
threadStopRequest(thread);
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
while(thread->state != THREAD_STATE_STOPPED) {
|
||||
threadMutexWaitLock(&thread->stateMutex);
|
||||
}
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
}
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
void * threadHandler(thread_t *thread) {
|
||||
assertNotNull(thread, "Thread cannot be NULL.");
|
||||
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
thread->state = THREAD_STATE_RUNNING;
|
||||
threadMutexSignal(&thread->stateMutex);
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
|
||||
// Send to callback.
|
||||
thread->callback(thread);
|
||||
|
||||
threadMutexLock(&thread->stateMutex);
|
||||
thread->state = THREAD_STATE_STOPPED;
|
||||
threadMutexSignal(&thread->stateMutex);
|
||||
threadMutexUnlock(&thread->stateMutex);
|
||||
thread->threadId = 0;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
93
src/thread/thread.h
Normal file
93
src/thread/thread.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "thread/threadmutex.h"
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "At least one threading implementation must be defined."
|
||||
#endif
|
||||
|
||||
typedef struct thread_s thread_t;
|
||||
|
||||
typedef void (*threadcallback_t)(thread_t *thread);
|
||||
|
||||
typedef enum {
|
||||
// Thread is definitely not running.
|
||||
THREAD_STATE_STOPPED,
|
||||
|
||||
// Start has been requested, it may even be started by the time you
|
||||
// see this value.
|
||||
THREAD_STATE_STARTING,
|
||||
|
||||
// Thread has definitely started and is running.
|
||||
THREAD_STATE_RUNNING,
|
||||
|
||||
// Something has requested the thread to stop, but it may not have
|
||||
// stopped yet.
|
||||
THREAD_STATE_STOP_REQUESTED,
|
||||
} threadstate_t;
|
||||
|
||||
typedef struct thread_s {
|
||||
threadstate_t state;
|
||||
threadmutex_t stateMutex;
|
||||
threadcallback_t callback;
|
||||
void *data;
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_t threadId;
|
||||
#endif
|
||||
} thread_t;
|
||||
|
||||
/**
|
||||
* Initializes a thread structure.
|
||||
*
|
||||
* @param thread Pointer to the thread structure to initialize.
|
||||
* @param callback The callback function to be called when the thread runs.
|
||||
*/
|
||||
void threadInit(thread_t *thread, const threadcallback_t callback);
|
||||
|
||||
/**
|
||||
* Starts the thread, does not wait for it to finish starting.
|
||||
*
|
||||
* @param thread Pointer to the thread structure to start.
|
||||
*/
|
||||
void threadStartRequest(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Requests the thread to stop, does not block the calling thread.
|
||||
*
|
||||
* @param thread Pointer to the thread structure to stop.
|
||||
*/
|
||||
void threadStopRequest(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Starts the thread, blocking until it has started. Does this as efficiently as
|
||||
* possible depending on the threading implementation. Note that it is possible
|
||||
* for the thread to fully COMPLETE before this function returns.
|
||||
*
|
||||
* @param thread Pointer to the thread structure to start.
|
||||
*/
|
||||
void threadStart(thread_t *thread);
|
||||
|
||||
/**
|
||||
* Stops the thread, blocking until it has stopped. Does this as efficiently as
|
||||
* possible depending on the threading implementation.
|
||||
*
|
||||
* @param thread Pointer to the thread structure to stop.
|
||||
*/
|
||||
void threadStop(thread_t *thread);
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
/**
|
||||
* Handles the thread's lifecycle for pthreads.
|
||||
* @param thread Pointer to the thread structure to handle.
|
||||
*/
|
||||
void * threadHandler(thread_t *thread);
|
||||
#endif
|
50
src/thread/threadmutex.c
Normal file
50
src/thread/threadmutex.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "threadmutex.h"
|
||||
|
||||
void threadMutexInit(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_mutex_init(&lock->mutex, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadMutexLock(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_mutex_lock(&lock->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool_t threadMutexTryLock(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
return pthread_mutex_trylock(&lock->mutex) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadMutexUnlock(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_mutex_unlock(&lock->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadMutexWaitLock(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_cond_wait(&lock->cond, &lock->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadMutexSignal(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_cond_signal(&lock->cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void threadMutexDispose(threadmutex_t *lock) {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_mutex_destroy(&lock->mutex);
|
||||
#endif
|
||||
}
|
73
src/thread/threadmutex.h
Normal file
73
src/thread/threadmutex.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "At least one threading implementation must be defined."
|
||||
#endif
|
||||
|
||||
typedef struct threadlock_t {
|
||||
#if DUSK_THREAD_PTHREAD
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
} threadmutex_t;
|
||||
|
||||
/**
|
||||
* Initializes a thread mutex.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to initialize.
|
||||
*/
|
||||
void threadMutexInit(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Locks the thread mutex.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to lock.
|
||||
*/
|
||||
void threadMutexLock(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Attempts to lock the thread mutex without blocking.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to try locking.
|
||||
* @return true if the lock was acquired, false otherwise.
|
||||
*/
|
||||
bool_t threadMutexTryLock(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Unlocks the thread mutex.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to unlock.
|
||||
*/
|
||||
void threadMutexUnlock(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Releases the thread mutex and waits for it to be locked again.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to wait on.
|
||||
*/
|
||||
void threadMutexWaitLock(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Signals the thread mutex, allowing a waiting thread to proceed as soon as
|
||||
* this mutex is unlocked.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to signal.
|
||||
*/
|
||||
void threadMutexSignal(threadmutex_t *lock);
|
||||
|
||||
/**
|
||||
* Disposes of the thread mutex.
|
||||
*
|
||||
* @param lock Pointer to the thread mutex structure to dispose.
|
||||
*/
|
||||
void threadMutexDispose(threadmutex_t *lock);
|
Reference in New Issue
Block a user