mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-19 06:30:36 -07:00
865 lines
30 KiB
C
865 lines
30 KiB
C
/****************************************************************************
|
|
|
|
Author : Gabriele 'matrix' Gristina <gabriele.gristina@gmail.com>
|
|
Date : Sun Jan 10 13:59:37 CET 2021
|
|
Version: 0.1beta
|
|
License: GNU General Public License v3 or any later version (see LICENSE.txt)
|
|
|
|
*****************************************************************************
|
|
Copyright (C) 2020-2021 <Gabriele Gristina>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
****************************************************************************/
|
|
|
|
#include "threads.h"
|
|
|
|
const char *thread_strerror(int error) {
|
|
switch (error) {
|
|
case THREAD_NOERROR:
|
|
return (const char *) "No error";
|
|
case THREAD_ERROR_CTX_IS_NULL:
|
|
return (const char *) "CTX IS NULL";
|
|
case THREAD_ERROR_CTX_IS_INIT:
|
|
return (const char *) "CTX IS INIT";
|
|
case THREAD_ERROR_TYPE_INVALID:
|
|
return (const char *) "INVALID TYPE";
|
|
case THREAD_ERROR_COUNT_INVALID:
|
|
return (const char *) "INVALID THREAD COUNT";
|
|
case THREAD_ERROR_ATTR_SETDETACH:
|
|
return (const char *) "SETDETACHSTATE FAILED";
|
|
case THREAD_ERROR_ATTR:
|
|
return (const char *) "INIT ATTR FAILED";
|
|
case THREAD_ERROR_MUTEXATTR:
|
|
return (const char *) "INIT MUTEXATTR FAILED";
|
|
case THREAD_ERROR_CREATE:
|
|
return (const char *) "PTHREAD CREATE FAILED";
|
|
case THREAD_ERROR_MUTEX:
|
|
return (const char *) "INIT MUTEXFAILED";
|
|
case THREAD_ERROR_COND:
|
|
return (const char *) "INIT COND FAILED";
|
|
case THREAD_ERROR_MUTEX_USLEEP:
|
|
return (const char *) "INIT MUTEX USLEEP FAILED";
|
|
case THREAD_ERROR_COND_USLEEP:
|
|
return (const char *) "INIT COND USLEEP FAILED";
|
|
case THREAD_ERROR_GENERIC:
|
|
return (const char *) "GENERIC ERROR";
|
|
case THREAD_ERROR_ALLOC:
|
|
return (const char *) "ALLOC FAILED";
|
|
case THREAD_ERROR_INTERNAL:
|
|
return (const char *) "INTERNAL ERROR";
|
|
}
|
|
|
|
return (const char *) "GENERIC";
|
|
}
|
|
|
|
int thread_init(thread_ctx_t *ctx, short type, size_t thread_count) {
|
|
if (!ctx) return THREAD_ERROR_CTX_IS_NULL;
|
|
if (ctx->init) return THREAD_ERROR_CTX_IS_INIT;
|
|
if (type != THREAD_TYPE_ASYNC && type != THREAD_TYPE_SEQ) return THREAD_ERROR_TYPE_INVALID;
|
|
if (thread_count == 0) return THREAD_ERROR_COUNT_INVALID;
|
|
|
|
memset(ctx, 0, sizeof(thread_ctx_t));
|
|
|
|
ctx->thread_count = thread_count;
|
|
ctx->type = type;
|
|
ctx->enable_condusleep = (type == THREAD_TYPE_ASYNC && thread_count == 1);
|
|
|
|
ctx->thread_handles = (pthread_t *) calloc(thread_count, sizeof(pthread_t));
|
|
if (!ctx->thread_handles) {
|
|
return THREAD_ERROR_ALLOC;
|
|
}
|
|
|
|
ctx->thread_mutexs = (pthread_mutex_t *) calloc(thread_count, sizeof(pthread_mutex_t));
|
|
if (!ctx->thread_mutexs) {
|
|
free(ctx->thread_handles);
|
|
return THREAD_ERROR_ALLOC;
|
|
}
|
|
|
|
ctx->thread_conds = (pthread_cond_t *) calloc(thread_count, sizeof(pthread_cond_t));
|
|
if (!ctx->thread_conds) {
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
return THREAD_ERROR_ALLOC;
|
|
}
|
|
|
|
if (pthread_attr_init(&ctx->attr) != 0) {
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_conds);
|
|
return THREAD_ERROR_ATTR;
|
|
}
|
|
|
|
pthread_attr_setdetachstate(&ctx->attr, PTHREAD_CREATE_JOINABLE);
|
|
|
|
if (pthread_mutexattr_init(&ctx->mutex_attr) != 0) {
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_conds);
|
|
pthread_attr_destroy(&ctx->attr);
|
|
return THREAD_ERROR_MUTEXATTR;
|
|
}
|
|
|
|
pthread_mutexattr_settype(&ctx->mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
|
|
|
|
if (ctx->enable_condusleep) {
|
|
if (pthread_mutex_init(&ctx->thread_mutex_usleep, NULL) != 0) {
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_conds);
|
|
pthread_attr_destroy(&ctx->attr);
|
|
pthread_mutexattr_destroy(&ctx->mutex_attr);
|
|
return THREAD_ERROR_MUTEX_USLEEP;
|
|
}
|
|
|
|
if (pthread_cond_init(&ctx->thread_cond_usleep, NULL) != 0) {
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_conds);
|
|
pthread_mutex_destroy(&ctx->thread_mutex_usleep);
|
|
pthread_attr_destroy(&ctx->attr);
|
|
pthread_mutexattr_destroy(&ctx->mutex_attr);
|
|
return THREAD_ERROR_COND_USLEEP;
|
|
}
|
|
}
|
|
|
|
int err = 0;
|
|
int z = 0;
|
|
|
|
for (z = 0; z < (int) ctx->thread_count; z++) {
|
|
if (ctx->type == THREAD_TYPE_ASYNC) {
|
|
if (pthread_mutex_init(&ctx->thread_mutexs[z], NULL) != 0) {
|
|
err = THREAD_ERROR_MUTEX;
|
|
break;
|
|
}
|
|
|
|
if (pthread_cond_init(&ctx->thread_conds[z], NULL) != 0) {
|
|
pthread_mutex_destroy(&ctx->thread_mutexs[z]);
|
|
err = THREAD_ERROR_COND;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (err != 0) {
|
|
z--; // step back
|
|
|
|
for (; z >= 0; z--) {
|
|
pthread_cond_destroy(&ctx->thread_conds[z]);
|
|
pthread_mutex_destroy(&ctx->thread_mutexs[z]);
|
|
}
|
|
|
|
if (ctx->enable_condusleep) {
|
|
pthread_mutex_destroy(&ctx->thread_mutex_usleep);
|
|
pthread_cond_destroy(&ctx->thread_cond_usleep);
|
|
}
|
|
|
|
free(ctx->thread_handles);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_conds);
|
|
pthread_attr_destroy(&ctx->attr);
|
|
pthread_mutexattr_destroy(&ctx->mutex_attr);
|
|
return err;
|
|
}
|
|
|
|
ctx->init = 1;
|
|
return 0;
|
|
}
|
|
|
|
int thread_start_scheduler(thread_ctx_t *ctx, thread_args_t *t_arg, wu_queue_ctx_t *queue_ctx) {
|
|
size_t z;
|
|
bool found = false;
|
|
bool done = false;
|
|
unsigned int th_cnt;
|
|
|
|
if (ctx->type == THREAD_TYPE_SEQ) {
|
|
bool error = false;
|
|
uint32_t slice = 0;
|
|
for (slice = 0; slice < t_arg[0].max_slices; slice += ctx->thread_count) {
|
|
int err = 0;
|
|
|
|
if ((err = thread_start(ctx, t_arg)) != 0) {
|
|
printf("Error: thread_start() failed (%d): %s\n", err, thread_strerror(err));
|
|
}
|
|
|
|
// waiting threads return
|
|
if (err == 0) thread_stop(ctx);
|
|
|
|
for (z = 0; z < ctx->thread_count; z++) {
|
|
if (t_arg[z].r) {
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (t_arg[z].err) {
|
|
error = true;
|
|
}
|
|
}
|
|
|
|
// internal err
|
|
if (error && err == 0) {
|
|
thread_destroy(ctx);
|
|
err = THREAD_ERROR_INTERNAL;
|
|
}
|
|
|
|
if (err != 0) return err;
|
|
|
|
if (found) break;
|
|
}
|
|
} else if (ctx->type == THREAD_TYPE_ASYNC) {
|
|
|
|
// crack hitag key or die tryin'
|
|
do { // master
|
|
th_cnt = 0;
|
|
|
|
for (z = 0; z < ctx->thread_count; z++) {
|
|
#if TDEBUG >= 1 && DEBUGME == 1
|
|
if (ctx->thread_count == 1) { printf("[%zu] get status from thread ...\n", z); fflush(stdout); }
|
|
#endif
|
|
|
|
pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
thread_status_t cur_status = t_arg[z].status;
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
|
|
#if TDEBUG >= 1 && DEBUGME == 1
|
|
if (ctx->thread_count == 1) { printf("[%zu] thread status: %s\n", z, thread_status_strdesc(cur_status)); fflush(stdout); }
|
|
#endif
|
|
if (found) {
|
|
#if TDEBUG >= 3
|
|
printf("[%zu] Processing exit logic\n", z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (cur_status < TH_FOUND_KEY) {
|
|
#if TDEBUG >= 1
|
|
printf("[%zu] key found from another thread, set quit\n", z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
t_arg[z].status = TH_END;
|
|
t_arg[z].quit = true;
|
|
if (cur_status == TH_WAIT) {
|
|
pthread_cond_signal(&ctx->thread_conds[z]);
|
|
}
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
} else {
|
|
if (ctx->thread_count == 1) {
|
|
th_cnt++;
|
|
#if TDEBUG >= 1
|
|
printf("[%zu] Increment th_cnt: %u/%zu\n", z, th_cnt, ctx->thread_count);
|
|
fflush(stdout);
|
|
#endif
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (cur_status == TH_WAIT) {
|
|
pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
|
|
if (wu_queue_done(queue_ctx) != QUEUE_EMPTY) {
|
|
t_arg[z].status = TH_PROCESSING;
|
|
|
|
#if TDEBUG >= 1
|
|
printf("[master] thread [%zu], I give you another try (%s)\n", z, thread_status_strdesc(t_arg[z].status));
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
pthread_cond_signal(&ctx->thread_conds[z]);
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
continue;
|
|
} else {
|
|
#if TDEBUG >= 1
|
|
printf("[master] thread [%zu], max step reached. Quit.\n", z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
cur_status = t_arg[z].status = TH_END;
|
|
t_arg[z].quit = true;
|
|
|
|
pthread_cond_signal(&ctx->thread_conds[z]);
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
}
|
|
}
|
|
|
|
if (cur_status == TH_PROCESSING) {
|
|
if (ctx->enable_condusleep) {
|
|
#if TDEBUG >= 1
|
|
printf("[master] before pthread_cond_wait, TH_PROCESSING\n");
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_lock(&ctx->thread_mutex_usleep);
|
|
#if TDEBUG >= 1
|
|
printf("[master] thread [%zu], I'm waiting you end of task, I'm in %s give me a signal.\n", z, thread_status_strdesc(t_arg[z].status));
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_cond_wait(&ctx->thread_cond_usleep, &ctx->thread_mutex_usleep);
|
|
#if TDEBUG >= 1
|
|
printf("[master] thread [%zu], got the signal with new state: %s.\n", z, thread_status_strdesc(t_arg[z].status));
|
|
fflush(stdout);
|
|
#endif
|
|
if (t_arg[z].status == TH_FOUND_KEY) {
|
|
found = true;
|
|
}
|
|
|
|
pthread_mutex_unlock(&ctx->thread_mutex_usleep);
|
|
#if TDEBUG >= 1
|
|
printf("[master] after pthread_cond_wait, TH_PROCESSING\n");
|
|
fflush(stdout);
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
// since found is handled before this part (line 237), removing the if-statement
|
|
// doesn't change anything according to cppcheck.
|
|
#if TDEBUG >= 1
|
|
printf("[master] thread [%zu], the key is found. set TH_END from TH_PROCESSING\n", z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
t_arg[z].status = TH_END;
|
|
t_arg[z].quit = true;
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
continue;
|
|
|
|
}
|
|
if (cur_status == TH_ERROR) {
|
|
// something went wrong
|
|
pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
t_arg[z].status = TH_END;
|
|
t_arg[z].quit = true;
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
continue;
|
|
}
|
|
|
|
if (cur_status >= TH_FOUND_KEY) {
|
|
th_cnt++;
|
|
|
|
if (cur_status == TH_FOUND_KEY) {
|
|
thread_setEnd(ctx, t_arg);
|
|
found = true;
|
|
done = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (th_cnt == ctx->thread_count) done = true;
|
|
|
|
} while (!done);
|
|
}
|
|
|
|
return (found) ? 0 : 1;
|
|
}
|
|
|
|
int thread_destroy(thread_ctx_t *ctx) {
|
|
if (!ctx) return -1;
|
|
if (!ctx->init) return -2;
|
|
|
|
if (ctx->enable_condusleep) {
|
|
pthread_cond_destroy(&ctx->thread_cond_usleep);
|
|
pthread_mutex_destroy(&ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
for (size_t z = 0; z < ctx->thread_count; z++) {
|
|
pthread_cond_destroy(&ctx->thread_conds[z]);
|
|
pthread_mutex_destroy(&ctx->thread_mutexs[z]);
|
|
}
|
|
|
|
pthread_mutexattr_destroy(&ctx->mutex_attr);
|
|
pthread_attr_init(&ctx->attr);
|
|
|
|
free(ctx->thread_conds);
|
|
free(ctx->thread_mutexs);
|
|
free(ctx->thread_handles);
|
|
|
|
memset(ctx, 0, sizeof(thread_ctx_t));
|
|
ctx->init = 0;
|
|
return 0;
|
|
}
|
|
|
|
int thread_start(thread_ctx_t *ctx, thread_args_t *t_arg) {
|
|
int err = 0;
|
|
int z = 0;
|
|
|
|
for (z = 0; z < (int) ctx->thread_count; z++) {
|
|
if (pthread_create(&ctx->thread_handles[z], &ctx->attr, (ctx->type == THREAD_TYPE_ASYNC) ? computing_process_async : computing_process, (void *) &t_arg[z]) != 0) {
|
|
err = THREAD_ERROR_CREATE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err != 0) {
|
|
z--; // step back
|
|
|
|
for (; z >= 0; z++) {
|
|
pthread_cancel(ctx->thread_handles[z]);
|
|
pthread_join(ctx->thread_handles[z], NULL);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int thread_stop(thread_ctx_t *ctx) {
|
|
for (size_t z = 0; z < ctx->thread_count; z++) {
|
|
if (ctx->type == THREAD_TYPE_ASYNC) pthread_cancel(ctx->thread_handles[z]);
|
|
pthread_join(ctx->thread_handles[z], NULL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const char *thread_status_strdesc(thread_status_t s) {
|
|
switch (s) {
|
|
case TH_START:
|
|
return (const char *) "START";
|
|
case TH_WAIT:
|
|
return (const char *) "WAIT";
|
|
case TH_PROCESSING:
|
|
return (const char *) "PROCESSING";
|
|
case TH_ERROR:
|
|
return (const char *) "ERROR";
|
|
case TH_FOUND_KEY:
|
|
return (const char *) "FOUND_KEY";
|
|
case TH_END:
|
|
return (const char *) "END";
|
|
}
|
|
|
|
return (const char *) "... or die tryin'";
|
|
}
|
|
|
|
bool thread_setEnd(thread_ctx_t *ctx, thread_args_t *t_arg) {
|
|
bool found = false;
|
|
|
|
size_t z;
|
|
|
|
int c_ret = 0;
|
|
|
|
for (z = 0; z < ctx->thread_count; z++) {
|
|
int m_ret = pthread_mutex_lock(&ctx->thread_mutexs[z]);
|
|
if (m_ret != 0) {
|
|
printf("[%zu] [%s] Error: pthread_mutex_lock() failed (%d): %s\n", z, __func__, m_ret, strerror(m_ret));
|
|
}
|
|
|
|
thread_status_t tmp = t_arg[z].status;
|
|
|
|
#if DEBUGME > 0
|
|
printf("[%zu] [%s] Thread status: %s\n", z, __func__, thread_status_strdesc(t_arg[z].status));
|
|
#endif
|
|
|
|
if (tmp == TH_FOUND_KEY || tmp == TH_END || tmp == TH_ERROR) {
|
|
if (tmp == TH_FOUND_KEY) found = true;
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
continue;
|
|
}
|
|
|
|
#if DEBUGME > 0
|
|
printf("[%zu] [%s] Set thread status to TH_END\n", z, __func__);
|
|
#endif
|
|
|
|
t_arg[z].status = TH_END;
|
|
|
|
if (tmp == TH_WAIT) {
|
|
#if DEBUGME > 0
|
|
printf("[%zu] [%s] Send cond_signal to thread\n", z, __func__);
|
|
#endif
|
|
|
|
c_ret = pthread_cond_signal(&ctx->thread_conds[z]);
|
|
if (c_ret != 0) {
|
|
printf("[%zu] [%s] Error: pthread_cond_signal() failed (%d): %s\n", z, __func__, c_ret, strerror(c_ret));
|
|
}
|
|
}
|
|
|
|
pthread_mutex_unlock(&ctx->thread_mutexs[z]);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void *computing_process(void *arg) {
|
|
thread_args_t *a = (thread_args_t *) arg;
|
|
|
|
uint64_t off = 0;
|
|
|
|
size_t z = a->device_id;
|
|
uint64_t *matches = a->matches;
|
|
uint32_t *matches_found = a->matches_found;
|
|
|
|
uint32_t uid = a->uid;
|
|
uint32_t aR2 = a->aR2;
|
|
uint32_t nR1 = a->nR1;
|
|
uint32_t nR2 = a->nR2;
|
|
|
|
opencl_ctx_t *ctx = a->ocl_ctx;
|
|
|
|
wu_queue_data_t wu;
|
|
wu_queue_pop(&ctx->queue_ctx, &wu, false);
|
|
off = wu.off;
|
|
a->slice = wu.id + 1;
|
|
|
|
if (ctx->queue_ctx.queue_type == QUEUE_TYPE_RANDOM) {
|
|
#if DEBUGME > 0
|
|
printf("[%zu] Slice %5zu (off %6zu), max %5zu, remain %5zu slice(s)\n", z, wu.id + 1, wu.off, wu.max, wu.rem);
|
|
#else
|
|
float progress = 100.0 - (((wu.rem + 1) * 100.0) / wu.max);
|
|
printf("\r[%zu] Slice %5zu/%5zu (%5zu remain) ( %2.1f%% )", z, wu.id + 1, wu.max, wu.rem, progress);
|
|
#endif // DEBUGME
|
|
} else {
|
|
#if DEBUGME > 0
|
|
printf("[%zu] Slice %zu/%zu, off %zu\n", z, wu.id + 1, wu.max, wu.off);
|
|
#else
|
|
float progress = (((wu.id + 1) * 100.0) / wu.max);
|
|
printf("\r[%zu] Slice %zu/%zu ( %2.1f%% )", z, wu.id + 1, wu.max, progress);
|
|
#endif // DEBUGME
|
|
}
|
|
fflush(stdout);
|
|
|
|
int ret = runKernel(ctx, (uint32_t) off, matches, matches_found, z);
|
|
|
|
a->r = false;
|
|
a->err = false;
|
|
|
|
if (ret < 1) { // error or nada
|
|
if (ret == -1) a->err = true;
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
if (!ctx->force_hitag2_opencl) {
|
|
#if DEBUGME >= 2
|
|
printf("[%s][%zu] master, I found %5u candidates @ slice %zu\n", __func__, z, matches_found[0], a->slice + 1);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
for (uint32_t match = 0; match < matches_found[0]; match++) {
|
|
a->r = try_state(matches[match], uid, aR2, nR1, nR2, &a->key);
|
|
if (a->r) break;
|
|
}
|
|
} else {
|
|
// the OpenCL kernel return only one key if found, else nothing
|
|
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, I found the key @ slice %zu\n", __func__, z, a->slice + 1);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
a->r = true;
|
|
a->key = matches[0];
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
void *computing_process_async(void *arg) {
|
|
thread_args_t *a = (thread_args_t *) arg;
|
|
|
|
size_t z = a->device_id;
|
|
|
|
// TH_START, not really needed lock with mutex here
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
// fetching data from thread struct, I hope they are good
|
|
thread_status_t status = a->status;
|
|
|
|
uint64_t *matches = a->matches;
|
|
uint32_t *matches_found = a->matches_found;
|
|
uint32_t uid = a->uid;
|
|
uint32_t aR2 = a->aR2;
|
|
uint32_t nR1 = a->nR1;
|
|
uint32_t nR2 = a->nR2;
|
|
|
|
size_t max_slices = a->max_slices;
|
|
|
|
opencl_ctx_t *ctx = a->ocl_ctx;
|
|
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
if (status == TH_START) {
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] uid %u, aR2 %u, nR1 %u, nR2 %u, Initial status: %s\n", __func__, z, uid, aR2, nR1, nR2, thread_status_strdesc(status));
|
|
#endif
|
|
status = TH_WAIT;
|
|
// proceed to next
|
|
}
|
|
|
|
do {
|
|
if (status == TH_WAIT) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
// update thread status to WAIT, todo: check with multiple devices
|
|
|
|
if (a->status == TH_END) { // other threads found the key
|
|
fflush(stdout);
|
|
//status = TH_END;
|
|
a->quit = true;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
pthread_exit(NULL);
|
|
} else {
|
|
a->status = TH_WAIT;
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_WAIT\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
}
|
|
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, i'm here to serve you. I'm in %s give me a signal.\n", __func__, z, thread_status_strdesc(status));
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
pthread_cond_wait(&a->thread_ctx->thread_conds[z], &a->thread_ctx->thread_mutexs[z]);
|
|
|
|
status = a->status; // read new status from master
|
|
|
|
#if TDEBUG >= 2
|
|
printf("[%s][%zu] master, got the signal with new state: %s.\n", __func__, z, thread_status_strdesc(status));
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
if (status == TH_WAIT) {
|
|
#if TDEBUG >=1
|
|
printf("[%s] ! Error: need to be TH_PROCESSING or TH_END, not TH_WAIT ... exit\n", __func__);
|
|
fflush(stdout);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (status == TH_ERROR) {
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, got error signal, proceed with exit\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
if (status == TH_PROCESSING) {
|
|
#if TDEBUG >= 2
|
|
printf("[%s][%zu] master, got a work-unit, processing ...\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
wu_queue_data_t wu;
|
|
wu_queue_pop(&ctx->queue_ctx, &wu, false);
|
|
uint32_t off = wu.off;
|
|
a->slice = wu.id + 1;
|
|
|
|
if (ctx->queue_ctx.queue_type == QUEUE_TYPE_RANDOM) {
|
|
#if DEBUGME > 0
|
|
printf("[%zu] Slice %5zu (off %6zu), max %5zu, remain %5zu slice(s)\n", z, wu.id + 1, wu.off, wu.max, wu.rem);
|
|
#else
|
|
float progress = 100.0 - (((wu.rem + 1) * 100.0) / wu.max);
|
|
printf("\r[%zu] Slice %5zu/%5zu (%5zu remain) ( %2.1f%% )", z, wu.id + 1, wu.max, wu.rem, progress);
|
|
#endif // DEBUGME
|
|
} else {
|
|
#if DEBUGME > 0
|
|
printf("[%zu] Slice %zu/%zu, off %zu\n", z, wu.id + 1, wu.max, wu.off);
|
|
#else
|
|
float progress = (((wu.id + 1) * 100.0) / wu.max);
|
|
printf("\r[%zu] Slice %zu/%zu ( %2.1f%% )", z, wu.id + 1, wu.max, progress);
|
|
#endif // DEBUGME
|
|
}
|
|
|
|
fflush(stdout);
|
|
|
|
int ret = runKernel(ctx, off, matches, matches_found, z);
|
|
|
|
if (ret < 1) { // error or nada
|
|
if (ret == -1) {
|
|
// untested code
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
a->err = true;
|
|
a->status = TH_ERROR;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, something is broken, exit\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_ERROR\n", __func__, z);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
// end of unstested code
|
|
}
|
|
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, process is done but no candidates found\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
if (a->slice >= max_slices) a->status = TH_END;
|
|
else a->status = TH_WAIT;
|
|
|
|
status = a->status;
|
|
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_WAIT\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!ctx->force_hitag2_opencl) {
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, we got %5u candidates. Proceed to validation\n", __func__, z, matches_found[0]);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
for (uint32_t match = 0; match < matches_found[0]; match++) {
|
|
if (a->quit) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
a->status = TH_END;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, Another thread found the key, quit 2 \n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_END\n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
a->r = try_state(matches[match], uid, aR2, nR1, nR2, &a->key);
|
|
if (a->r) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
a->s = matches[match];
|
|
a->status = TH_FOUND_KEY;
|
|
a->quit = true;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
#if TDEBUG >= 1
|
|
#ifdef _ISOC99_SOURCE
|
|
printf("[%s][%zu] master, I found the key ! state %U64x, slice %zu\n", __func__, z, a->s, a->slice + 1);
|
|
#else
|
|
printf("[%s][%zu] master, I found the key ! state %" STR(OFF_FORMAT_U) ", slice %zu\n", __func__, z, a->s, a->slice + 1);
|
|
#endif
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_FOUND_KEY\n", __func__, z);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
}
|
|
|
|
if (a->quit) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
a->status = TH_END;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, Another thread found the key, quit 1 \n", __func__, z);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_END\n", __func__, z);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
// setting internal status to wait
|
|
status = TH_WAIT;
|
|
continue;
|
|
} else {
|
|
// the OpenCL kernel return only one key if found, else nothing
|
|
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutexs[z]);
|
|
a->r = true;
|
|
a->key = matches[0];
|
|
status = a->status = TH_FOUND_KEY;
|
|
a->quit = true;
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutexs[z]);
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] master, I found the key at slice %zu\n", __func__, z, a->slice + 1);
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
if (a->thread_ctx->enable_condusleep) {
|
|
pthread_mutex_lock(&a->thread_ctx->thread_mutex_usleep);
|
|
pthread_cond_signal(&a->thread_ctx->thread_cond_usleep); // unlock master/TH_PROCESSING cond
|
|
#if TDEBUG >= 1
|
|
printf("[%s][%zu] after pthread_cond_signal TH_FOUND_KEY\n", __func__, z);
|
|
#endif
|
|
pthread_mutex_unlock(&a->thread_ctx->thread_mutex_usleep);
|
|
}
|
|
|
|
pthread_exit(NULL);
|
|
}
|
|
}
|
|
|
|
if (status >= TH_FOUND_KEY) {
|
|
#if TDEBUG >= 1
|
|
if (status == TH_FOUND_KEY) {
|
|
printf("[%s][%zu] master, TH_FOUND_KEY, if you see this message, something is wrong\n", __func__, z);
|
|
fflush(stdout);
|
|
} else if (status == TH_END) {
|
|
printf("[%s][%zu] master, TH_END reached\n", __func__, z);
|
|
fflush(stdout);
|
|
}
|
|
#endif
|
|
pthread_exit(NULL);
|
|
}
|
|
|
|
} while (status < TH_FOUND_KEY);
|
|
|
|
pthread_exit(NULL);
|
|
return NULL;
|
|
}
|