ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
thread_pool.c
Go to the documentation of this file.
1
6#include "thread_pool.h"
7#include "common.h"
8#include "log/logging.h"
9#include "platform/thread.h"
10#include <string.h>
11
12thread_pool_t *thread_pool_create(const char *pool_name) {
14 if (!pool) {
15 SET_ERRNO(ERROR_MEMORY, "Failed to allocate thread pool");
16 return NULL;
17 }
18
19 memset(pool, 0, sizeof(*pool));
20
21 // Copy pool name (truncate if necessary)
22 if (pool_name) {
23 SAFE_STRNCPY(pool->name, pool_name, sizeof(pool->name));
24 } else {
25 SAFE_STRNCPY(pool->name, "unnamed", sizeof(pool->name));
26 }
27
28 // Initialize linked list
29 pool->threads = NULL;
30 pool->thread_count = 0;
31
32 // Initialize mutex
33 if (mutex_init(&pool->threads_mutex) != 0) {
34 SAFE_FREE(pool);
35 SET_ERRNO(ERROR_THREAD, "Failed to initialize thread pool mutex");
36 return NULL;
37 }
38
39 log_debug("Thread pool '%s' created", pool->name);
40 return pool;
41}
42
44 if (!pool) {
45 return;
46 }
47
48 log_debug("Destroying thread pool '%s' (thread_count=%zu)", pool->name, pool->thread_count);
49
50 // Stop all threads first (if not already stopped)
51 if (pool->thread_count > 0) {
52 log_debug("Thread pool '%s' has %zu threads, stopping them first", pool->name, pool->thread_count);
54 }
55
56 // Destroy mutex
58
59 // Free pool
60 SAFE_FREE(pool);
61
62 log_debug("Thread pool destroyed");
63}
64
65asciichat_error_t thread_pool_spawn(thread_pool_t *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id,
66 const char *thread_name) {
67 if (!pool) {
68 return SET_ERRNO(ERROR_INVALID_PARAM, "pool is NULL");
69 }
70
71 if (!thread_func) {
72 return SET_ERRNO(ERROR_INVALID_PARAM, "thread_func is NULL");
73 }
74
75 // Allocate thread entry
77 if (!entry) {
78 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate thread pool entry");
79 }
80
81 memset(entry, 0, sizeof(*entry));
82 entry->stop_id = stop_id;
83 entry->thread_func = thread_func;
84 entry->thread_arg = thread_arg;
85 entry->next = NULL;
86
87 // Copy thread name (truncate if necessary)
88 if (thread_name) {
89 SAFE_STRNCPY(entry->name, thread_name, sizeof(entry->name));
90 } else {
91 // Auto-generate name
92 SAFE_SNPRINTF(entry->name, sizeof(entry->name), "%s_worker_%d", pool->name, stop_id);
93 }
94
95 // Create thread
96 if (asciichat_thread_create(&entry->thread, thread_func, thread_arg) != 0) {
97 SAFE_FREE(entry);
98 return SET_ERRNO(ERROR_THREAD, "Failed to create thread '%s' in pool '%s'", entry->name, pool->name);
99 }
100
101 // Add to thread list (sorted by stop_id)
103
104 if (!pool->threads || pool->threads->stop_id > stop_id) {
105 // Insert at head
106 entry->next = pool->threads;
107 pool->threads = entry;
108 } else {
109 // Find insertion point (maintain sorted order by stop_id)
110 thread_pool_entry_t *prev = pool->threads;
111 while (prev->next && prev->next->stop_id <= stop_id) {
112 prev = prev->next;
113 }
114 entry->next = prev->next;
115 prev->next = entry;
116 }
117
118 pool->thread_count++;
120
121 log_debug("Spawned thread '%s' (stop_id=%d) in pool '%s' (total_threads=%zu)", entry->name, stop_id, pool->name,
122 pool->thread_count);
123
124 return ASCIICHAT_OK;
125}
126
128 if (!pool) {
129 return SET_ERRNO(ERROR_INVALID_PARAM, "pool is NULL");
130 }
131
133
134 if (pool->thread_count == 0) {
136 log_debug("Thread pool '%s' has no threads to stop", pool->name);
137 return ASCIICHAT_OK;
138 }
139
140 log_debug("Stopping %zu threads in pool '%s' in stop_id order", pool->thread_count, pool->name);
141
142 // Threads are already sorted by stop_id (ascending), so just iterate and join
143 thread_pool_entry_t *entry = pool->threads;
144 while (entry) {
145 log_debug("Joining thread '%s' (stop_id=%d) in pool '%s'", entry->name, entry->stop_id, pool->name);
146
147 // Join thread (wait for it to exit)
148 if (asciichat_thread_join(&entry->thread, NULL) != 0) {
149 log_warn("Failed to join thread '%s' in pool '%s'", entry->name, pool->name);
150 }
151
152 thread_pool_entry_t *next = entry->next;
153 SAFE_FREE(entry);
154 entry = next;
155 }
156
157 // Clear list
158 pool->threads = NULL;
159 pool->thread_count = 0;
160
162
163 log_debug("All threads stopped in pool '%s'", pool->name);
164 return ASCIICHAT_OK;
165}
166
168 if (!pool) {
169 return 0;
170 }
171
172 // Note: We're not locking here for performance
173 // thread_count is a simple size_t which should be atomic on most platforms
174 // If strict thread safety is required, use mutex_lock/unlock
175 return pool->thread_count;
176}
177
179 return thread_pool_get_count(pool) > 0;
180}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:412
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ERROR_MEMORY
Definition error_codes.h:53
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_INVALID_PARAM
@ ERROR_THREAD
Definition error_codes.h:95
#define log_warn(...)
Log a WARN message.
#define log_debug(...)
Log a DEBUG message.
int mutex_init(mutex_t *mutex)
Initialize a mutex.
#define mutex_lock(mutex)
Lock a mutex (with debug tracking in debug builds)
Definition mutex.h:140
int asciichat_thread_join(asciichat_thread_t *thread, void **retval)
Wait for a thread to complete (blocking)
#define mutex_unlock(mutex)
Unlock a mutex (with debug tracking in debug builds)
Definition mutex.h:175
int asciichat_thread_create(asciichat_thread_t *thread, void *(*func)(void *), void *arg)
Create a new thread.
int mutex_destroy(mutex_t *mutex)
Destroy a mutex.
๐Ÿ“ Logging API with multiple log levels and terminal output control
๐Ÿงต Cross-platform thread interface for ascii-chat
Thread pool entry (internal linked list node)
Definition thread_pool.h:88
void *(* thread_func)(void *)
Thread function.
Definition thread_pool.h:91
void * thread_arg
Thread argument.
Definition thread_pool.h:92
asciichat_thread_t thread
Thread handle.
Definition thread_pool.h:89
struct thread_pool_entry * next
Linked list next pointer.
Definition thread_pool.h:94
int stop_id
Cleanup order (lower = stop first, -1 = unordered)
Definition thread_pool.h:90
char name[64]
Thread name for debugging.
Definition thread_pool.h:93
Thread pool structure.
mutex_t threads_mutex
Mutex protecting thread list.
thread_pool_entry_t * threads
Linked list of threads (sorted by stop_id)
size_t thread_count
Number of threads in pool.
char name[64]
Pool name for debugging.
void thread_pool_destroy(thread_pool_t *pool)
Destroy a thread pool.
Definition thread_pool.c:43
thread_pool_t * thread_pool_create(const char *pool_name)
Create a new thread pool.
Definition thread_pool.c:12
size_t thread_pool_get_count(const thread_pool_t *pool)
Get thread count in the pool.
bool thread_pool_has_threads(const thread_pool_t *pool)
Check if pool has any threads.
asciichat_error_t thread_pool_spawn(thread_pool_t *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *thread_name)
Spawn a worker thread in the pool.
Definition thread_pool.c:65
asciichat_error_t thread_pool_stop_all(thread_pool_t *pool)
Stop all threads in the pool in stop_id order.
๐Ÿงต Generic thread pool abstraction for managing worker threads
Common SIMD utilities and structures.