1 /******************************************************************************/
2 /* SlunkCrypt, by LoRd_MuldeR <MuldeR2@GMX.de> */
3 /* This work has been released under the CC0 1.0 Universal license! */
4 /******************************************************************************/
15 #if defined(_MSC_VER) && !defined(_DLL)
16 # define PTW32_STATIC_LIB 1
22 # include <sys/sysinfo.h>
26 #define TSTATE_IDLE 0U
27 #define TSTATE_WORK 1U
28 #define TSTATE_EXIT 2U
30 // ==========================================================================
32 // ==========================================================================
36 thrdpl_worker_t worker;
45 size_t thread_count, pending;
46 pthread_mutex_t mutex;
47 pthread_cond_t cond_pending;
53 thrdpl_shared_t *shared;
55 pthread_cond_t cond_state;
63 thrdpl_shared_t shared;
64 thrdpl_thread_t thread_data[MAX_THREADS];
67 // ==========================================================================
69 // ==========================================================================
71 static INLINE size_t bound(const size_t min, const size_t value, const size_t max)
73 return (value < min) ? min : ((value > max) ? max : value);
76 #define PTHRD_MUTEX_LOCK(X) do \
78 if (pthread_mutex_lock((X)) != 0) \
85 #define PTHRD_MUTEX_UNLOCK(X) do \
87 if (pthread_mutex_unlock((X)) != 0) \
94 #define PTHRD_COND_SIGNAL(X) do \
96 if (pthread_cond_signal((X)) != 0) \
103 #define PTHRD_COND_BROADCAST(X) do \
105 if (pthread_cond_broadcast((X)) != 0) \
112 #define PTHRD_COND_WAIT(X,Y) do \
114 if (pthread_cond_wait((X), (Y)) != 0) \
121 #define CHECK_IF_CANCELLED() do \
123 if (data->state == TSTATE_EXIT) \
125 PTHRD_MUTEX_UNLOCK(&shared->mutex); \
131 // ==========================================================================
133 // ==========================================================================
135 static void *worker_thread_main(void *const arg)
137 thrdpl_thread_t *const data = (thrdpl_thread_t*) arg;
138 thrdpl_shared_t *const shared = (thrdpl_shared_t*) data->shared;
144 PTHRD_MUTEX_LOCK(&shared->mutex);
145 CHECK_IF_CANCELLED();
147 while (data->state != TSTATE_WORK)
149 PTHRD_COND_WAIT(&data->cond_state, &shared->mutex);
150 CHECK_IF_CANCELLED();
154 PTHRD_MUTEX_UNLOCK(&shared->mutex);
156 task->worker(shared->thread_count, task->context, task->buffer, task->length);
158 PTHRD_MUTEX_LOCK(&shared->mutex);
159 CHECK_IF_CANCELLED();
161 data->state = TSTATE_IDLE;
162 if (!(--shared->pending))
164 PTHRD_COND_BROADCAST(&shared->cond_pending);
167 PTHRD_MUTEX_UNLOCK(&shared->mutex);
168 PTHRD_COND_SIGNAL(&data->cond_state);
172 // ==========================================================================
174 // ==========================================================================
176 #if defined(__unix__)
177 # define NUM_PROCESSORS_FUNC get_nprocs
178 #elif defined(PTW32_VERSION)
179 # define NUM_PROCESSORS_FUNC pthread_num_processors_np
182 static size_t detect_cpu_count(void)
184 #ifdef NUM_PROCESSORS_FUNC
185 const int cpu_count = NUM_PROCESSORS_FUNC();
188 return (size_t) cpu_count;
194 // ==========================================================================
196 // ==========================================================================
198 static int create_worker(thrdpl_shared_t *const shared, thrdpl_thread_t *const thread_data)
200 thread_data->state = TSTATE_IDLE;
201 thread_data->shared = shared;
203 if (pthread_cond_init(&thread_data->cond_state, NULL) != 0)
208 if (pthread_create(&thread_data->thread, NULL, worker_thread_main, thread_data) != 0)
210 pthread_cond_destroy(&thread_data->cond_state);
217 static int destroy_worker(thrdpl_thread_t *const thread_data)
219 PTHRD_MUTEX_LOCK(&thread_data->shared->mutex);
220 thread_data->state = TSTATE_EXIT;
221 PTHRD_MUTEX_UNLOCK(&thread_data->shared->mutex);
223 PTHRD_COND_BROADCAST(&thread_data->cond_state);
224 pthread_join(thread_data->thread, NULL);
225 pthread_cond_destroy(&thread_data->cond_state);
230 // ==========================================================================
232 // ==========================================================================
234 thrdpl_t *slunkcrypt_thrdpl_create(const size_t count)
237 thrdpl_t *thrdpl = NULL;
239 const size_t cpu_count = bound(1U, (count > 0U) ? count : detect_cpu_count(), MAX_THREADS);
245 if (!(thrdpl = (thrdpl_t*)malloc(sizeof(thrdpl_t))))
250 memset(thrdpl, 0, sizeof(thrdpl_t));
251 thrdpl->shared.thread_count = cpu_count;
253 if (pthread_mutex_init(&thrdpl->shared.mutex, NULL) != 0)
258 if (pthread_cond_init(&thrdpl->shared.cond_pending, NULL) != 0)
260 pthread_mutex_destroy(&thrdpl->shared.mutex);
264 for (i = 0U; i < cpu_count; ++i)
266 if (create_worker(&thrdpl->shared, &thrdpl->thread_data[i]) != 0)
268 for (j = 0U; j < i; ++j)
270 destroy_worker(&thrdpl->thread_data[j]);
272 pthread_cond_destroy(&thrdpl->shared.cond_pending);
273 pthread_mutex_destroy(&thrdpl->shared.mutex);
285 size_t slunkcrypt_thrdpl_count(const thrdpl_t *const thrdpl)
287 return thrdpl->shared.thread_count;
290 void slunkcrypt_thrdpl_exec(thrdpl_t *const thrdpl, const size_t index, const thrdpl_worker_t worker, void *const context, uint8_t *const buffer, const size_t length)
292 thrdpl_thread_t *const thread = &thrdpl->thread_data[index];
294 PTHRD_MUTEX_LOCK(&thrdpl->shared.mutex);
296 while ((thread->state != TSTATE_IDLE) && (thread->state != TSTATE_EXIT))
298 PTHRD_COND_WAIT(&thread->cond_state, &thrdpl->shared.mutex);
301 if (thread->state == TSTATE_EXIT)
303 abort(); /*this is not supposed to happen!*/
306 thread->state = TSTATE_WORK;
307 thread->task.worker = worker;
308 thread->task.context = context;
309 thread->task.buffer = buffer;
310 thread->task.length = length;
312 ++thrdpl->shared.pending;
314 PTHRD_MUTEX_UNLOCK(&thrdpl->shared.mutex);
315 PTHRD_COND_SIGNAL(&thread->cond_state);
318 void slunkcrypt_thrdpl_await(thrdpl_t *const thrdpl)
320 PTHRD_MUTEX_LOCK(&thrdpl->shared.mutex);
322 while (thrdpl->shared.pending)
324 PTHRD_COND_WAIT(&thrdpl->shared.cond_pending, &thrdpl->shared.mutex);
327 PTHRD_MUTEX_UNLOCK(&thrdpl->shared.mutex);
330 void slunkcrypt_thrdpl_destroy(thrdpl_t *const thrdpl)
336 for (i = 0U; i < thrdpl->shared.thread_count; ++i)
338 destroy_worker(&thrdpl->thread_data[i]);
340 pthread_cond_destroy(&thrdpl->shared.cond_pending);
341 pthread_mutex_destroy(&thrdpl->shared.mutex);