Slightly improved thread management code.
This commit is contained in:
parent
f70ccb6a14
commit
342562cf2e
@ -262,10 +262,8 @@ static void thread_worker(const size_t thread_count, void *const context, uint8_
|
|||||||
buffer[i] = process_next_symbol(state, buffer[i]);
|
buffer[i] = process_next_symbol(state, buffer[i]);
|
||||||
state->counter += (uint32_t)thread_count;
|
state->counter += (uint32_t)thread_count;
|
||||||
random_skip(&state->random, 63U * (thread_count - 1U));
|
random_skip(&state->random, 63U * (thread_count - 1U));
|
||||||
CHECK_ABORTED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aborted:
|
|
||||||
update_index(state, thread_count, length);
|
update_index(state, thread_count, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +309,14 @@ slunkcrypt_t slunkcrypt_alloc_ext(const uint64_t nonce, const uint8_t *const pas
|
|||||||
return SLUNKCRYPT_NULL;
|
return SLUNKCRYPT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->thread_pool = slunkcrypt_thrdpl_create(param->thread_count);
|
if ((state->thread_pool = slunkcrypt_thrdpl_create(param->thread_count, thread_worker)))
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0U; i < slunkcrypt_thrdpl_count(state->thread_pool); ++i)
|
||||||
|
{
|
||||||
|
slunkcrypt_thrdpl_init(state->thread_pool, i, &state->data.thread_data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (initialize_state(&state->data, THREAD_COUNT(state), nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
|
if (initialize_state(&state->data, THREAD_COUNT(state), nonce, passwd, passwd_len, mode) == SLUNKCRYPT_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -368,12 +373,7 @@ int slunkcrypt_inplace(const slunkcrypt_t context, uint8_t *const buffer, size_t
|
|||||||
const size_t thread_count = THREAD_COUNT(state);
|
const size_t thread_count = THREAD_COUNT(state);
|
||||||
if (thread_count > 1U)
|
if (thread_count > 1U)
|
||||||
{
|
{
|
||||||
size_t i;
|
slunkcrypt_thrdpl_exec(state->thread_pool, buffer, length);
|
||||||
for (i = 0U; i < thread_count; ++i)
|
|
||||||
{
|
|
||||||
slunkcrypt_thrdpl_exec(state->thread_pool, i, thread_worker, &state->data.thread_data[i], buffer, length);
|
|
||||||
}
|
|
||||||
slunkcrypt_thrdpl_await(state->thread_pool);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -34,27 +34,19 @@
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
thrdpl_worker_t worker;
|
thrdpl_worker_t worker;
|
||||||
void *context;
|
|
||||||
size_t length;
|
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
}
|
size_t thread_count, generation, remain, length;
|
||||||
thrdpl_task_t;
|
int stop_flag;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
size_t thread_count, pending;
|
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_cond_t cond_pending;
|
pthread_cond_t cond_0, cond_1;
|
||||||
}
|
}
|
||||||
thrdpl_shared_t;
|
thrdpl_shared_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
thrdpl_shared_t *shared;
|
thrdpl_shared_t *shared;
|
||||||
size_t state;
|
void *context;
|
||||||
pthread_cond_t cond_state;
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
thrdpl_task_t task;
|
|
||||||
}
|
}
|
||||||
thrdpl_thread_t;
|
thrdpl_thread_t;
|
||||||
|
|
||||||
@ -68,12 +60,12 @@ struct thrdpl_data_t
|
|||||||
// Utilities
|
// Utilities
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
static INLINE size_t bound(const size_t min, const size_t value, const size_t max)
|
static INLINE size_t BOUND(const size_t min, const size_t value, const size_t max)
|
||||||
{
|
{
|
||||||
return (value < min) ? min : ((value > max) ? max : value);
|
return (value < min) ? min : ((value > max) ? max : value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PTHRD_MUTEX_LOCK(X) do \
|
#define PTHRD_MUTEX_ENTER(X) do \
|
||||||
{ \
|
{ \
|
||||||
if (pthread_mutex_lock((X)) != 0) \
|
if (pthread_mutex_lock((X)) != 0) \
|
||||||
{ \
|
{ \
|
||||||
@ -82,7 +74,7 @@ static INLINE size_t bound(const size_t min, const size_t value, const size_t ma
|
|||||||
} \
|
} \
|
||||||
while(0)
|
while(0)
|
||||||
|
|
||||||
#define PTHRD_MUTEX_UNLOCK(X) do \
|
#define PTHRD_MUTEX_LEAVE(X) do \
|
||||||
{ \
|
{ \
|
||||||
if (pthread_mutex_unlock((X)) != 0) \
|
if (pthread_mutex_unlock((X)) != 0) \
|
||||||
{ \
|
{ \
|
||||||
@ -100,7 +92,7 @@ while(0)
|
|||||||
} \
|
} \
|
||||||
while(0)
|
while(0)
|
||||||
|
|
||||||
#define PTHRD_COND_BROADCAST(X) do \
|
#define PTHRD_COND_BRDCST(X) do \
|
||||||
{ \
|
{ \
|
||||||
if (pthread_cond_broadcast((X)) != 0) \
|
if (pthread_cond_broadcast((X)) != 0) \
|
||||||
{ \
|
{ \
|
||||||
@ -118,11 +110,11 @@ while(0)
|
|||||||
} \
|
} \
|
||||||
while(0)
|
while(0)
|
||||||
|
|
||||||
#define CHECK_IF_CANCELLED() do \
|
#define CHECK_IF_STOPPED() do \
|
||||||
{ \
|
{ \
|
||||||
if (data->state == TSTATE_EXIT) \
|
if (shared->stop_flag) \
|
||||||
{ \
|
{ \
|
||||||
PTHRD_MUTEX_UNLOCK(&shared->mutex); \
|
PTHRD_MUTEX_LEAVE(&shared->mutex); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
@ -137,35 +129,31 @@ static void *worker_thread_main(void *const arg)
|
|||||||
thrdpl_thread_t *const data = (thrdpl_thread_t*) arg;
|
thrdpl_thread_t *const data = (thrdpl_thread_t*) arg;
|
||||||
thrdpl_shared_t *const shared = (thrdpl_shared_t*) data->shared;
|
thrdpl_shared_t *const shared = (thrdpl_shared_t*) data->shared;
|
||||||
|
|
||||||
thrdpl_task_t *task;
|
size_t previous = 0U;
|
||||||
|
|
||||||
|
PTHRD_MUTEX_ENTER(&shared->mutex);
|
||||||
|
CHECK_IF_STOPPED();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
PTHRD_MUTEX_LOCK(&shared->mutex);
|
while (shared->generation == previous)
|
||||||
CHECK_IF_CANCELLED();
|
|
||||||
|
|
||||||
while (data->state != TSTATE_WORK)
|
|
||||||
{
|
{
|
||||||
PTHRD_COND_WAIT(&data->cond_state, &shared->mutex);
|
PTHRD_COND_WAIT(&shared->cond_0, &shared->mutex);
|
||||||
CHECK_IF_CANCELLED();
|
CHECK_IF_STOPPED();
|
||||||
}
|
}
|
||||||
|
|
||||||
task = &data->task;
|
previous = shared->generation;
|
||||||
PTHRD_MUTEX_UNLOCK(&shared->mutex);
|
PTHRD_MUTEX_LEAVE(&shared->mutex);
|
||||||
|
|
||||||
task->worker(shared->thread_count, task->context, task->buffer, task->length);
|
shared->worker(shared->thread_count, data->context, shared->buffer, shared->length);
|
||||||
|
|
||||||
PTHRD_MUTEX_LOCK(&shared->mutex);
|
PTHRD_MUTEX_ENTER(&shared->mutex);
|
||||||
CHECK_IF_CANCELLED();
|
CHECK_IF_STOPPED();
|
||||||
|
|
||||||
data->state = TSTATE_IDLE;
|
if (!(--shared->remain))
|
||||||
if (!(--shared->pending))
|
|
||||||
{
|
{
|
||||||
PTHRD_COND_BROADCAST(&shared->cond_pending);
|
PTHRD_COND_SIGNAL(&shared->cond_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PTHRD_MUTEX_UNLOCK(&shared->mutex);
|
|
||||||
PTHRD_COND_SIGNAL(&data->cond_state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,52 +179,16 @@ static size_t detect_cpu_count(void)
|
|||||||
return 1U;
|
return 1U;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
// Manage threads
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
static int create_worker(thrdpl_shared_t *const shared, thrdpl_thread_t *const thread_data)
|
|
||||||
{
|
|
||||||
thread_data->state = TSTATE_IDLE;
|
|
||||||
thread_data->shared = shared;
|
|
||||||
|
|
||||||
if (pthread_cond_init(&thread_data->cond_state, NULL) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pthread_create(&thread_data->thread, NULL, worker_thread_main, thread_data) != 0)
|
|
||||||
{
|
|
||||||
pthread_cond_destroy(&thread_data->cond_state);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int destroy_worker(thrdpl_thread_t *const thread_data)
|
|
||||||
{
|
|
||||||
PTHRD_MUTEX_LOCK(&thread_data->shared->mutex);
|
|
||||||
thread_data->state = TSTATE_EXIT;
|
|
||||||
PTHRD_MUTEX_UNLOCK(&thread_data->shared->mutex);
|
|
||||||
|
|
||||||
PTHRD_COND_BROADCAST(&thread_data->cond_state);
|
|
||||||
pthread_join(thread_data->thread, NULL);
|
|
||||||
pthread_cond_destroy(&thread_data->cond_state);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Thread pool API
|
// Thread pool API
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
thrdpl_t *slunkcrypt_thrdpl_create(const size_t count)
|
thrdpl_t *slunkcrypt_thrdpl_create(const size_t count, const thrdpl_worker_t worker)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i;
|
||||||
thrdpl_t *thrdpl = NULL;
|
thrdpl_t *thrdpl = NULL;
|
||||||
|
|
||||||
const size_t cpu_count = bound(1U, (count > 0U) ? count : detect_cpu_count(), MAX_THREADS);
|
const size_t cpu_count = BOUND(1U, (count > 0U) ? count : detect_cpu_count(), MAX_THREADS);
|
||||||
if (cpu_count < 2U)
|
if (cpu_count < 2U)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -248,31 +200,35 @@ thrdpl_t *slunkcrypt_thrdpl_create(const size_t count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(thrdpl, 0, sizeof(thrdpl_t));
|
memset(thrdpl, 0, sizeof(thrdpl_t));
|
||||||
thrdpl->shared.thread_count = cpu_count;
|
thrdpl->shared.worker = worker;
|
||||||
|
|
||||||
if (pthread_mutex_init(&thrdpl->shared.mutex, NULL) != 0)
|
if (pthread_mutex_init(&thrdpl->shared.mutex, NULL) != 0)
|
||||||
{
|
{
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_cond_init(&thrdpl->shared.cond_pending, NULL) != 0)
|
if (pthread_cond_init(&thrdpl->shared.cond_0, NULL) != 0)
|
||||||
{
|
{
|
||||||
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pthread_cond_init(&thrdpl->shared.cond_1, NULL) != 0)
|
||||||
|
{
|
||||||
|
pthread_cond_destroy(&thrdpl->shared.cond_0);
|
||||||
|
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0U; i < cpu_count; ++i)
|
for (i = 0U; i < cpu_count; ++i)
|
||||||
{
|
{
|
||||||
if (create_worker(&thrdpl->shared, &thrdpl->thread_data[i]) != 0)
|
thrdpl->thread_data[i].shared = &thrdpl->shared;
|
||||||
|
if (pthread_create(&thrdpl->thread_data[i].thread, NULL, worker_thread_main, &thrdpl->thread_data[i]) != 0)
|
||||||
{
|
{
|
||||||
for (j = 0U; j < i; ++j)
|
slunkcrypt_thrdpl_destroy(thrdpl);
|
||||||
{
|
return NULL;
|
||||||
destroy_worker(&thrdpl->thread_data[j]);
|
|
||||||
}
|
|
||||||
pthread_cond_destroy(&thrdpl->shared.cond_pending);
|
|
||||||
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
|
||||||
goto failure;
|
|
||||||
}
|
}
|
||||||
|
++thrdpl->shared.thread_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return thrdpl;
|
return thrdpl;
|
||||||
@ -287,58 +243,56 @@ size_t slunkcrypt_thrdpl_count(const thrdpl_t *const thrdpl)
|
|||||||
return thrdpl->shared.thread_count;
|
return thrdpl->shared.thread_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void slunkcrypt_thrdpl_init(thrdpl_t *const thrdpl, const size_t index, void *const context)
|
||||||
{
|
{
|
||||||
thrdpl_thread_t *const thread = &thrdpl->thread_data[index];
|
thrdpl->thread_data[index].context = context;
|
||||||
|
}
|
||||||
|
|
||||||
PTHRD_MUTEX_LOCK(&thrdpl->shared.mutex);
|
void slunkcrypt_thrdpl_exec(thrdpl_t *const thrdpl, uint8_t *const buffer, const size_t length)
|
||||||
|
{
|
||||||
|
PTHRD_MUTEX_ENTER(&thrdpl->shared.mutex);
|
||||||
|
|
||||||
while ((thread->state != TSTATE_IDLE) && (thread->state != TSTATE_EXIT))
|
if (thrdpl->shared.stop_flag || (thrdpl->shared.remain != 0U))
|
||||||
{
|
|
||||||
PTHRD_COND_WAIT(&thread->cond_state, &thrdpl->shared.mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread->state == TSTATE_EXIT)
|
|
||||||
{
|
{
|
||||||
abort(); /*this is not supposed to happen!*/
|
abort(); /*this is not supposed to happen!*/
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->state = TSTATE_WORK;
|
thrdpl->shared.buffer = buffer;
|
||||||
thread->task.worker = worker;
|
thrdpl->shared.length = length;
|
||||||
thread->task.context = context;
|
thrdpl->shared.remain = thrdpl->shared.thread_count;
|
||||||
thread->task.buffer = buffer;
|
|
||||||
thread->task.length = length;
|
|
||||||
|
|
||||||
++thrdpl->shared.pending;
|
++thrdpl->shared.generation;
|
||||||
|
PTHRD_COND_BRDCST(&thrdpl->shared.cond_0);
|
||||||
|
|
||||||
PTHRD_MUTEX_UNLOCK(&thrdpl->shared.mutex);
|
while (thrdpl->shared.remain)
|
||||||
PTHRD_COND_SIGNAL(&thread->cond_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void slunkcrypt_thrdpl_await(thrdpl_t *const thrdpl)
|
|
||||||
{
|
|
||||||
PTHRD_MUTEX_LOCK(&thrdpl->shared.mutex);
|
|
||||||
|
|
||||||
while (thrdpl->shared.pending)
|
|
||||||
{
|
{
|
||||||
PTHRD_COND_WAIT(&thrdpl->shared.cond_pending, &thrdpl->shared.mutex);
|
PTHRD_COND_WAIT(&thrdpl->shared.cond_1, &thrdpl->shared.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
PTHRD_MUTEX_UNLOCK(&thrdpl->shared.mutex);
|
PTHRD_MUTEX_LEAVE(&thrdpl->shared.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void slunkcrypt_thrdpl_destroy(thrdpl_t *const thrdpl)
|
void slunkcrypt_thrdpl_destroy(thrdpl_t *const thrdpl)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
PTHRD_MUTEX_ENTER(&thrdpl->shared.mutex);
|
||||||
|
|
||||||
if (thrdpl)
|
if (!thrdpl->shared.stop_flag)
|
||||||
{
|
{
|
||||||
for (i = 0U; i < thrdpl->shared.thread_count; ++i)
|
thrdpl->shared.stop_flag = 1;
|
||||||
{
|
PTHRD_COND_BRDCST(&thrdpl->shared.cond_0);
|
||||||
destroy_worker(&thrdpl->thread_data[i]);
|
|
||||||
}
|
|
||||||
pthread_cond_destroy(&thrdpl->shared.cond_pending);
|
|
||||||
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
|
||||||
free(thrdpl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PTHRD_MUTEX_LEAVE(&thrdpl->shared.mutex);
|
||||||
|
|
||||||
|
for (i = 0U; i < thrdpl->shared.thread_count; ++i)
|
||||||
|
{
|
||||||
|
pthread_join(thrdpl->thread_data[i].thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cond_destroy(&thrdpl->shared.cond_0);
|
||||||
|
pthread_cond_destroy(&thrdpl->shared.cond_1);
|
||||||
|
pthread_mutex_destroy(&thrdpl->shared.mutex);
|
||||||
|
|
||||||
|
free(thrdpl);
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
typedef void (*thrdpl_worker_t)(const size_t thread_count, void *const context, uint8_t *const buffer, const size_t length);
|
typedef void (*thrdpl_worker_t)(const size_t thread_count, void *const context, uint8_t *const buffer, const size_t length);
|
||||||
typedef struct thrdpl_data_t thrdpl_t;
|
typedef struct thrdpl_data_t thrdpl_t;
|
||||||
|
|
||||||
thrdpl_t *slunkcrypt_thrdpl_create(const size_t count);
|
thrdpl_t *slunkcrypt_thrdpl_create(const size_t count, const thrdpl_worker_t worker);
|
||||||
size_t slunkcrypt_thrdpl_count(const thrdpl_t *const thrdpl);
|
size_t slunkcrypt_thrdpl_count(const thrdpl_t *const thrdpl);
|
||||||
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);
|
void slunkcrypt_thrdpl_init(thrdpl_t *const thrdpl, const size_t index, void *const context);
|
||||||
void slunkcrypt_thrdpl_await(thrdpl_t *const thrdpl);
|
void slunkcrypt_thrdpl_exec(thrdpl_t *const thrdpl, uint8_t *const buffer, const size_t length);
|
||||||
void slunkcrypt_thrdpl_destroy(thrdpl_t *const thrdpl);
|
void slunkcrypt_thrdpl_destroy(thrdpl_t *const thrdpl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user