diff --git a/oclengine.c b/oclengine.c index 4557e2c..c649003 100644 --- a/oclengine.c +++ b/oclengine.c @@ -1571,7 +1571,6 @@ vg_ocl_prefix_check(vg_ocl_context_t *vocp, int slot) found_delta, orig_delta); res = 1; } - vocp->voc_pattern_rewrite = 1; } else { vxcp->vxc_delta += (vocp->voc_ocl_cols * vocp->voc_ocl_rows); } @@ -1879,6 +1878,7 @@ vg_opencl_loop(void *arg) vg_ocl_context_t *vocp = (vg_ocl_context_t *) arg; int i; int round, nrows, ncols; + int pattern_generation; const BN_ULONG rekey_max = 100000000; BN_ULONG npoints, rekey_at; @@ -1991,6 +1991,10 @@ l_rekey: !vocp->voc_rekey_func(vocp)) goto enomem; + vg_exec_context_upgrade_lock(vxcp); + + pattern_generation = vcp->vc_pattern_generation; + /* Generate a new random private key */ EC_KEY_generate_key(pkey); npoints = 0; @@ -2007,6 +2011,8 @@ l_rekey: EC_POINT_copy(ppbase[0], EC_KEY_get0_public_key(pkey)); + vg_exec_context_downgrade_lock(vxcp); + if (vcp->vc_pubkey_base) { EC_POINT_add(pgroup, ppbase[0], @@ -2076,6 +2082,15 @@ l_rekey: vg_output_timing(vcp, c, &tvstart); c = 0; } + vg_exec_context_yield(vxcp); + + /* If the patterns changed, reload it to the GPU */ + if (vocp->voc_rekey_func && + (pattern_generation != + vcp->vc_pattern_generation)) { + vocp->voc_pattern_rewrite = 1; + rekey_at = 0; + } } if (vcp->vc_halt) @@ -2176,6 +2191,8 @@ l_rekey: printf("done!\n"); } + vg_exec_context_yield(vxcp); + if (ppbase) { for (i = 0; i < (nrows + ncols); i++) if (ppbase[i]) diff --git a/pattern.c b/pattern.c index 012ec21..3bc1a8f 100644 --- a/pattern.c +++ b/pattern.c @@ -45,9 +45,106 @@ vg_exec_context_new_key(void) return EC_KEY_new_by_curve_name(NID_secp256k1); } +/* + * Thread synchronization helpers + */ + +static pthread_mutex_t vg_thread_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t vg_thread_rdcond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t vg_thread_wrcond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t vg_thread_upcond = PTHREAD_COND_INITIALIZER; +static vg_exec_context_t *vg_threads = NULL; +static int vg_thread_excl = 0; + +static void +__vg_exec_context_yield(vg_exec_context_t *vxcp) +{ + vxcp->vxc_lockmode = 0; + while (vg_thread_excl) { + if (vxcp->vxc_stop) { + assert(vg_thread_excl); + vxcp->vxc_stop = 0; + pthread_cond_signal(&vg_thread_upcond); + } + pthread_cond_wait(&vg_thread_rdcond, &vg_thread_lock); + } + assert(!vxcp->vxc_stop); + assert(!vxcp->vxc_lockmode); + vxcp->vxc_lockmode = 1; +} + +int +vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp) +{ + vg_exec_context_t *tp; + + if (vxcp->vxc_lockmode == 2) + return 0; + + pthread_mutex_lock(&vg_thread_lock); + + assert(vxcp->vxc_lockmode == 1); + vxcp->vxc_lockmode = 0; + + if (vg_thread_excl++) { + assert(vxcp->vxc_stop); + vxcp->vxc_stop = 0; + pthread_cond_signal(&vg_thread_upcond); + pthread_cond_wait(&vg_thread_wrcond, &vg_thread_lock); + + for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) { + assert(!tp->vxc_lockmode); + assert(!tp->vxc_stop); + } + + } else { + for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) { + if (tp->vxc_lockmode) { + assert(tp->vxc_lockmode != 2); + tp->vxc_stop = 1; + } + } + + do { + for (tp = vg_threads; tp != NULL; tp = tp->vxc_next) { + if (tp->vxc_lockmode) { + assert(tp->vxc_lockmode != 2); + pthread_cond_wait(&vg_thread_upcond, + &vg_thread_lock); + break; + } + } + } while (tp); + } + + vxcp->vxc_lockmode = 2; + pthread_mutex_unlock(&vg_thread_lock); + return 1; +} + +void +vg_exec_context_downgrade_lock(vg_exec_context_t *vxcp) +{ + pthread_mutex_lock(&vg_thread_lock); + + assert(vxcp->vxc_lockmode == 2); + assert(!vxcp->vxc_stop); + if (!--vg_thread_excl) { + vxcp->vxc_lockmode = 1; + pthread_cond_broadcast(&vg_thread_rdcond); + pthread_mutex_unlock(&vg_thread_lock); + return; + } + pthread_cond_signal(&vg_thread_wrcond); + __vg_exec_context_yield(vxcp); + pthread_mutex_unlock(&vg_thread_lock); +} + int vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp) { + pthread_mutex_lock(&vg_thread_lock); + memset(vxcp, 0, sizeof(*vxcp)); vxcp->vxc_vc = vcp; @@ -64,18 +161,62 @@ vg_exec_context_init(vg_context_t *vcp, vg_exec_context_t *vxcp) vxcp->vxc_key = vg_exec_context_new_key(); assert(vxcp->vxc_key); EC_KEY_precompute_mult(vxcp->vxc_key, vxcp->vxc_bnctx); + + vxcp->vxc_lockmode = 0; + vxcp->vxc_stop = 0; + + vxcp->vxc_next = vg_threads; + vg_threads = vxcp; + __vg_exec_context_yield(vxcp); + pthread_mutex_unlock(&vg_thread_lock); return 1; } void vg_exec_context_del(vg_exec_context_t *vxcp) { + vg_exec_context_t *tp, **pprev; + + if (vxcp->vxc_lockmode == 2) + vg_exec_context_downgrade_lock(vxcp); + + pthread_mutex_lock(&vg_thread_lock); + assert(vxcp->vxc_lockmode == 1); + vxcp->vxc_lockmode = 0; + + for (pprev = &vg_threads, tp = *pprev; + (tp != vxcp) && (tp != NULL); + pprev = &tp->vxc_next, tp = *pprev); + + assert(tp == vxcp); + *pprev = tp->vxc_next; + + if (tp->vxc_stop) + pthread_cond_signal(&vg_thread_upcond); + BN_clear_free(&vxcp->vxc_bntarg); BN_clear_free(&vxcp->vxc_bnbase); BN_clear_free(&vxcp->vxc_bntmp); BN_clear_free(&vxcp->vxc_bntmp2); BN_CTX_free(vxcp->vxc_bnctx); vxcp->vxc_bnctx = NULL; + pthread_mutex_unlock(&vg_thread_lock); +} + +void +vg_exec_context_yield(vg_exec_context_t *vxcp) +{ + if (vxcp->vxc_lockmode == 2) + vg_exec_context_downgrade_lock(vxcp); + + else if (vxcp->vxc_stop) { + assert(vxcp->vxc_lockmode == 1); + pthread_mutex_lock(&vg_thread_lock); + __vg_exec_context_yield(vxcp); + pthread_mutex_unlock(&vg_thread_lock); + } + + assert(vxcp->vxc_lockmode == 1); } void @@ -473,6 +614,7 @@ int vg_context_add_patterns(vg_context_t *vcp, const char ** const patterns, int npatterns) { + vcp->vc_pattern_generation++; return vcp->vc_add_patterns(vcp, patterns, npatterns); } @@ -480,6 +622,7 @@ void vg_context_clear_all_patterns(vg_context_t *vcp) { vcp->vc_clear_all_patterns(vcp); + vcp->vc_pattern_generation++; } int @@ -1690,7 +1833,7 @@ vg_prefix_test(vg_exec_context_t *vxcp) research: vp = vg_prefix_avl_search(&vcpp->vcp_avlroot, &vxcp->vxc_bntarg); if (vp) { - if (vg_exec_upgrade_lock(vxcp)) + if (vg_exec_context_upgrade_lock(vxcp)) goto research; vg_exec_context_consolidate_key(vxcp); @@ -1717,6 +1860,7 @@ research: vcpp, &vxcp->vxc_bntmp, &vxcp->vxc_bntmp2, vxcp->vxc_bnctx); + vcpp->base.vc_pattern_generation++; } res = 1; } @@ -1983,7 +2127,7 @@ restart_loop: re = vcrp->vcr_regex[i]; - if (vg_exec_upgrade_lock(vxcp) && + if (vg_exec_context_upgrade_lock(vxcp) && ((i >= vcrp->base.vc_npatterns) || (vcrp->vcr_regex[i] != re))) goto restart_loop; @@ -2008,6 +2152,7 @@ restart_loop: vcrp->vcr_regex_extra[nres]; vcrp->vcr_regex_pat[i] = vcrp->vcr_regex_pat[nres]; vcrp->base.vc_npatterns = nres; + vcrp->base.vc_pattern_generation++; } res = 1; } diff --git a/pattern.h b/pattern.h index 48682bc..95fbfae 100644 --- a/pattern.h +++ b/pattern.h @@ -33,7 +33,7 @@ #include #endif -#define VANITYGEN_VERSION "0.19" +#define VANITYGEN_VERSION "0.20pre" typedef struct _vg_context_s vg_context_t; @@ -49,6 +49,11 @@ typedef struct _vg_exec_context_s { BIGNUM vxc_bnbase; BIGNUM vxc_bntmp; BIGNUM vxc_bntmp2; + + /* Thread synchronization */ + struct _vg_exec_context_s *vxc_next; + int vxc_lockmode; + int vxc_stop; } vg_exec_context_t; /* Init/cleanup for common execution context */ @@ -58,9 +63,10 @@ extern void vg_exec_context_consolidate_key(vg_exec_context_t *vxcp); extern void vg_exec_context_calc_address(vg_exec_context_t *vxcp); extern EC_KEY *vg_exec_context_new_key(void); -/* Implementation-specific lock/unlock/consolidate */ -extern void vg_exec_downgrade_lock(vg_exec_context_t *vxcp); -extern int vg_exec_upgrade_lock(vg_exec_context_t *vxcp); +/* Execution context lock handling functions */ +extern void vg_exec_context_downgrade_lock(vg_exec_context_t *vxcp); +extern int vg_exec_context_upgrade_lock(vg_exec_context_t *vxcp); +extern void vg_exec_context_yield(vg_exec_context_t *vxcp); typedef void (*vg_free_func_t)(vg_context_t *); @@ -89,6 +95,7 @@ struct _vg_context_s { unsigned long vc_npatterns; unsigned long vc_npatterns_start; unsigned long long vc_found; + int vc_pattern_generation; double vc_chance; const char *vc_result_file; const char *vc_key_protect_pass; diff --git a/vanitygen.c b/vanitygen.c index 48b4b7d..a47e3fc 100644 --- a/vanitygen.c +++ b/vanitygen.c @@ -34,169 +34,6 @@ const char *version = VANITYGEN_VERSION; -typedef struct _vg_thread_context_s { - vg_exec_context_t base; - struct _vg_thread_context_s *vt_next; - int vt_mode; - int vt_stop; -} vg_thread_context_t; - - -/* - * To synchronize pattern lists, we use a special shared-exclusive lock - * geared toward being held in shared mode 99.9% of the time. - */ - -static pthread_mutex_t vg_thread_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t vg_thread_rdcond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t vg_thread_wrcond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t vg_thread_upcond = PTHREAD_COND_INITIALIZER; -static vg_thread_context_t *vg_threads = NULL; -static int vg_thread_excl = 0; - -void -__vg_thread_yield(vg_thread_context_t *vtcp) -{ - vtcp->vt_mode = 0; - while (vg_thread_excl) { - if (vtcp->vt_stop) { - assert(vg_thread_excl); - vtcp->vt_stop = 0; - pthread_cond_signal(&vg_thread_upcond); - } - pthread_cond_wait(&vg_thread_rdcond, &vg_thread_lock); - } - assert(!vtcp->vt_stop); - assert(!vtcp->vt_mode); - vtcp->vt_mode = 1; -} - -void -vg_thread_context_init(vg_context_t *vcp, vg_thread_context_t *vtcp) -{ - vtcp->vt_mode = 0; - vtcp->vt_stop = 0; - - pthread_mutex_lock(&vg_thread_lock); - vg_exec_context_init(vcp, &vtcp->base); - vtcp->vt_next = vg_threads; - vg_threads = vtcp; - __vg_thread_yield(vtcp); - pthread_mutex_unlock(&vg_thread_lock); -} - -void -vg_thread_context_del(vg_thread_context_t *vtcp) -{ - vg_thread_context_t *tp, **pprev; - - if (vtcp->vt_mode == 2) - vg_exec_downgrade_lock(&vtcp->base); - - pthread_mutex_lock(&vg_thread_lock); - assert(vtcp->vt_mode == 1); - vtcp->vt_mode = 0; - - for (pprev = &vg_threads, tp = *pprev; - (tp != vtcp) && (tp != NULL); - pprev = &tp->vt_next, tp = *pprev); - - assert(tp == vtcp); - *pprev = tp->vt_next; - - if (tp->vt_stop) - pthread_cond_signal(&vg_thread_upcond); - - vg_exec_context_del(&vtcp->base); - pthread_mutex_unlock(&vg_thread_lock); -} - -void -vg_thread_yield(vg_thread_context_t *vtcp) -{ - if (vtcp->vt_mode == 2) - vg_exec_downgrade_lock(&vtcp->base); - - else if (vtcp->vt_stop) { - assert(vtcp->vt_mode == 1); - pthread_mutex_lock(&vg_thread_lock); - __vg_thread_yield(vtcp); - pthread_mutex_unlock(&vg_thread_lock); - } - - assert(vtcp->vt_mode == 1); -} - - - -void -vg_exec_downgrade_lock(vg_exec_context_t *vxcp) -{ - vg_thread_context_t *vtcp = (vg_thread_context_t *) vxcp; - pthread_mutex_lock(&vg_thread_lock); - - assert(vtcp->vt_mode == 2); - assert(!vtcp->vt_stop); - if (!--vg_thread_excl) { - vtcp->vt_mode = 1; - pthread_cond_broadcast(&vg_thread_rdcond); - pthread_mutex_unlock(&vg_thread_lock); - return; - } - pthread_cond_signal(&vg_thread_wrcond); - __vg_thread_yield(vtcp); - pthread_mutex_unlock(&vg_thread_lock); -} - -int -vg_exec_upgrade_lock(vg_exec_context_t *vxcp) -{ - vg_thread_context_t *vtcp = (vg_thread_context_t *) vxcp; - vg_thread_context_t *tp; - - if (vtcp->vt_mode == 2) - return 0; - - pthread_mutex_lock(&vg_thread_lock); - - assert(vtcp->vt_mode == 1); - vtcp->vt_mode = 0; - - if (vg_thread_excl++) { - assert(vtcp->vt_stop); - vtcp->vt_stop = 0; - pthread_cond_signal(&vg_thread_upcond); - pthread_cond_wait(&vg_thread_wrcond, &vg_thread_lock); - - for (tp = vg_threads; tp != NULL; tp = tp->vt_next) { - assert(!tp->vt_mode); - assert(!tp->vt_stop); - } - - } else { - for (tp = vg_threads; tp != NULL; tp = tp->vt_next) { - if (tp->vt_mode) { - assert(tp->vt_mode != 2); - tp->vt_stop = 1; - } - } - - do { - for (tp = vg_threads; tp != NULL; tp = tp->vt_next) { - if (tp->vt_mode) { - assert(tp->vt_mode != 2); - pthread_cond_wait(&vg_thread_upcond, - &vg_thread_lock); - break; - } - } - } while (tp); - } - - vtcp->vt_mode = 2; - pthread_mutex_unlock(&vg_thread_lock); - return 1; -} /* * Address search thread main loop @@ -224,16 +61,16 @@ vg_thread_loop(void *arg) EC_POINT *pbatchinc; vg_test_func_t test_func = vcp->vc_test; - vg_thread_context_t ctx; + vg_exec_context_t ctx; vg_exec_context_t *vxcp; struct timeval tvstart; memset(&ctx, 0, sizeof(ctx)); - vxcp = &ctx.base; + vxcp = &ctx; - vg_thread_context_init(vcp, &ctx); + vg_exec_context_init(vcp, &ctx); pkey = vxcp->vxc_key; pgroup = EC_KEY_get0_group(pkey); @@ -282,7 +119,7 @@ vg_thread_loop(void *arg) while (!vcp->vc_halt) { if (++npoints >= rekey_at) { - pthread_mutex_lock(&vg_thread_lock); + vg_exec_context_upgrade_lock(vxcp); /* Generate a new random private key */ EC_KEY_generate_key(pkey); npoints = 0; @@ -299,7 +136,7 @@ vg_thread_loop(void *arg) assert(rekey_at > 0); EC_POINT_copy(ppnt[0], EC_KEY_get0_public_key(pkey)); - pthread_mutex_unlock(&vg_thread_lock); + vg_exec_context_downgrade_lock(vxcp); npoints++; vxcp->vxc_delta = 0; @@ -387,11 +224,11 @@ vg_thread_loop(void *arg) c = 0; } - vg_thread_yield(&ctx); + vg_exec_context_yield(vxcp); } out: - vg_thread_context_del(&ctx); + vg_exec_context_del(&ctx); vg_context_thread_exit(vcp); for (i = 0; i < ptarraysize; i++)