@ -145,6 +145,7 @@ static char *rpc_user, *rpc_pass;
struct thr_info * thr_info ;
struct thr_info * thr_info ;
static int work_thr_id ;
static int work_thr_id ;
int longpoll_thr_id ;
int longpoll_thr_id ;
static int stage_thr_id ;
struct work_restart * work_restart = NULL ;
struct work_restart * work_restart = NULL ;
pthread_mutex_t time_lock ;
pthread_mutex_t time_lock ;
static pthread_mutex_t hash_lock ;
static pthread_mutex_t hash_lock ;
@ -154,6 +155,8 @@ static struct timeval total_tv_start, total_tv_end;
static int accepted , rejected ;
static int accepted , rejected ;
int hw_errors ;
int hw_errors ;
static int total_queued ;
static int total_queued ;
static char current_block [ 36 ] ;
static char blank [ 36 ] ;
static void applog_and_exit ( const char * fmt , . . . )
static void applog_and_exit ( const char * fmt , . . . )
{
{
@ -616,8 +619,6 @@ static void kill_work(void)
}
}
}
}
static char current_block [ 36 ] ;
static void * get_work_thread ( void * userdata )
static void * get_work_thread ( void * userdata )
{
{
struct workio_cmd * wc = ( struct workio_cmd * ) userdata ;
struct workio_cmd * wc = ( struct workio_cmd * ) userdata ;
@ -648,7 +649,7 @@ static void *get_work_thread(void *userdata)
}
}
/* send work to requesting thread */
/* send work to requesting thread */
if ( unlikely ( ! tq_push ( wc - > thr - > q , ret_work ) ) ) {
if ( unlikely ( ! tq_push ( thr_info [ stage_thr_id ] . q , ret_work ) ) ) {
applog ( LOG_ERR , " Failed to tq_push work in workio_get_work " ) ;
applog ( LOG_ERR , " Failed to tq_push work in workio_get_work " ) ;
kill_work ( ) ;
kill_work ( ) ;
free ( ret_work ) ;
free ( ret_work ) ;
@ -674,23 +675,30 @@ static void *submit_work_thread(void *userdata)
{
{
struct workio_cmd * wc = ( struct workio_cmd * ) userdata ;
struct workio_cmd * wc = ( struct workio_cmd * ) userdata ;
int failures = 0 ;
int failures = 0 ;
char * hexstr ;
pthread_detach ( pthread_self ( ) ) ;
pthread_detach ( pthread_self ( ) ) ;
if ( unlikely ( strncmp ( ( const char * ) wc - > u . work - > data , current_block , 36 ) ) ) {
applog ( LOG_INFO , " Stale work detected, discarding " ) ;
hexstr = bin2hex ( wc - > u . work - > data , 36 ) ;
if ( unlikely ( ! hexstr ) ) {
applog ( LOG_ERR , " submit_work_thread OOM " ) ;
goto out ;
goto out ;
}
}
if ( unlikely ( strncmp ( hexstr , current_block , 36 ) ) ) {
applog ( LOG_INFO , " Stale work detected, discarding " ) ;
goto out_free ;
}
/* submit solution to bitcoin via JSON-RPC */
/* submit solution to bitcoin via JSON-RPC */
while ( ! submit_upstream_work ( wc - > u . work ) ) {
while ( ! submit_upstream_work ( wc - > u . work ) ) {
if ( unlikely ( strncmp ( ( const char * ) wc - > u . work - > data , current_block , 36 ) ) ) {
if ( unlikely ( strncmp ( hexstr , current_block , 36 ) ) ) {
applog ( LOG_INFO , " Stale work detected, discarding " ) ;
applog ( LOG_INFO , " Stale work detected, discarding " ) ;
goto out ;
goto out_free ;
}
}
if ( unlikely ( ( opt_retries > = 0 ) & & ( + + failures > opt_retries ) ) ) {
if ( unlikely ( ( opt_retries > = 0 ) & & ( + + failures > opt_retries ) ) ) {
applog ( LOG_ERR , " Failed %d retries ...terminating workio thread " , opt_retries ) ;
applog ( LOG_ERR , " Failed %d retries ...terminating workio thread " , opt_retries ) ;
kill_work ( ) ;
kill_work ( ) ;
goto out ;
goto out_free ;
}
}
/* pause, then restart work-request loop */
/* pause, then restart work-request loop */
@ -698,7 +706,8 @@ static void *submit_work_thread(void *userdata)
opt_fail_pause ) ;
opt_fail_pause ) ;
sleep ( opt_fail_pause ) ;
sleep ( opt_fail_pause ) ;
}
}
out_free :
free ( hexstr ) ;
out :
out :
workio_cmd_free ( wc ) ;
workio_cmd_free ( wc ) ;
return NULL ;
return NULL ;
@ -715,6 +724,61 @@ static bool workio_submit_work(struct workio_cmd *wc)
return true ;
return true ;
}
}
static void * stage_thread ( void * userdata )
{
struct thr_info * mythr = userdata ;
bool ok = true ;
unsigned int i ;
for ( i = 0 ; i < 36 ; i + + ) {
strcat ( current_block , " 0 " ) ;
strcat ( blank , " 0 " ) ;
}
while ( ok ) {
struct work * work = NULL ;
char * hexstr ;
work = tq_pop ( mythr - > q , NULL ) ;
if ( unlikely ( ! work ) ) {
applog ( LOG_ERR , " Failed to tq_pop in stage_thread " ) ;
ok = false ;
break ;
}
hexstr = bin2hex ( work - > data , 36 ) ;
if ( unlikely ( ! hexstr ) ) {
applog ( LOG_ERR , " stage_thread OOM " ) ;
break ;
}
/* current_block is blanked out on successful longpoll */
if ( likely ( strncmp ( current_block , blank , 36 ) ) ) {
if ( unlikely ( strncmp ( hexstr , current_block , 36 ) ) ) {
if ( want_longpoll )
applog ( LOG_WARNING , " New block detected, possible missed longpoll, flushing work queue " ) ;
else
applog ( LOG_WARNING , " New block detected, flushing work queue " ) ;
/* As we can't flush the work from here, signal
* the wakeup thread to restart all the
* threads */
work_restart [ stage_thr_id ] . restart = 1 ;
}
}
memcpy ( current_block , hexstr , 36 ) ;
free ( hexstr ) ;
if ( unlikely ( ! tq_push ( thr_info [ 0 ] . q , work ) ) ) {
applog ( LOG_ERR , " Failed to tq_push work in stage_thread " ) ;
ok = false ;
break ;
}
}
tq_freeze ( mythr - > q ) ;
return NULL ;
}
static void * workio_thread ( void * userdata )
static void * workio_thread ( void * userdata )
{
{
struct thr_info * mythr = userdata ;
struct thr_info * mythr = userdata ;
@ -884,11 +948,19 @@ static bool discard_request(void)
return true ;
return true ;
}
}
static void flush_requests ( void )
static void flush_requests ( bool longpoll )
{
{
int i , extra ;
int i , extra ;
extra = requests_queued ( ) ;
extra = requests_queued ( ) ;
/* When flushing from longpoll, we don't know the new work yet. When
* not flushing from longpoll , the first work item is valid so do not
* discard it */
if ( longpoll )
memcpy ( current_block , blank , 36 ) ;
else
extra - - ;
for ( i = 0 ; i < extra ; i + + ) {
for ( i = 0 ; i < extra ; i + + ) {
/* Queue a whole batch of new requests */
/* Queue a whole batch of new requests */
if ( unlikely ( ! queue_request ( ) ) ) {
if ( unlikely ( ! queue_request ( ) ) ) {
@ -928,7 +1000,7 @@ retry:
dec_queued ( ) ;
dec_queued ( ) ;
memcpy ( work , work_heap , sizeof ( * work ) ) ;
memcpy ( work , work_heap , sizeof ( * work ) ) ;
memcpy ( current_block , work - > data , 36 ) ;
ret = true ;
ret = true ;
free ( work_heap ) ;
free ( work_heap ) ;
out :
out :
@ -1340,12 +1412,12 @@ out:
}
}
# endif /* HAVE_OPENCL */
# endif /* HAVE_OPENCL */
static void restart_threads ( void )
static void restart_threads ( bool longpoll )
{
{
int i ;
int i ;
/* Discard old queued requests and get new ones */
/* Discard old queued requests and get new ones */
flush_requests ( ) ;
flush_requests ( longpoll ) ;
for ( i = 0 ; i < opt_n_threads + gpu_threads ; i + + )
for ( i = 0 ; i < opt_n_threads + gpu_threads ; i + + )
work_restart [ i ] . restart = 1 ;
work_restart [ i ] . restart = 1 ;
@ -1399,10 +1471,8 @@ static void *longpoll_thread(void *userdata)
failures = 0 ;
failures = 0 ;
json_decref ( val ) ;
json_decref ( val ) ;
if ( ! opt_quiet )
applog ( LOG_WARNING , " LONGPOLL detected new block " ) ;
printf ( " LONGPOLL detected new block \n " ) ;
restart_threads ( true ) ;
applog ( LOG_INFO , " LONGPOLL detected new block " ) ;
restart_threads ( ) ;
} else {
} else {
if ( failures + + < 10 ) {
if ( failures + + < 10 ) {
sleep ( 30 ) ;
sleep ( 30 ) ;
@ -1437,6 +1507,10 @@ static void *wakeup_thread(void *userdata)
while ( 1 ) {
while ( 1 ) {
sleep ( interval ) ;
sleep ( interval ) ;
hashmeter ( - 1 , & zero_tv , 0 ) ;
hashmeter ( - 1 , & zero_tv , 0 ) ;
if ( unlikely ( work_restart [ stage_thr_id ] . restart ) ) {
restart_threads ( false ) ;
work_restart [ stage_thr_id ] . restart = 0 ;
}
}
}
return NULL ;
return NULL ;
@ -1510,11 +1584,11 @@ int main (int argc, char *argv[])
openlog ( " cpuminer " , LOG_PID , LOG_USER ) ;
openlog ( " cpuminer " , LOG_PID , LOG_USER ) ;
# endif
# endif
work_restart = calloc ( opt_n_threads + gpu_threads , sizeof ( * work_restart ) ) ;
work_restart = calloc ( opt_n_threads + 4 + gpu_threads , sizeof ( * work_restart ) ) ;
if ( ! work_restart )
if ( ! work_restart )
return 1 ;
return 1 ;
thr_info = calloc ( opt_n_threads + 3 + gpu_threads , sizeof ( * thr ) ) ;
thr_info = calloc ( opt_n_threads + 4 + gpu_threads , sizeof ( * thr ) ) ;
if ( ! thr_info )
if ( ! thr_info )
return 1 ;
return 1 ;
@ -1568,6 +1642,17 @@ int main (int argc, char *argv[])
}
}
}
}
stage_thr_id = opt_n_threads + gpu_threads + 3 ;
thr = & thr_info [ stage_thr_id ] ;
thr - > q = tq_new ( ) ;
if ( ! thr - > q )
return 1 ;
/* start stage thread */
if ( pthread_create ( & thr - > pth , NULL , stage_thread , thr ) ) {
applog ( LOG_ERR , " stage thread create failed " ) ;
return 1 ;
}
/* Put enough work in the queue */
/* Put enough work in the queue */
for ( i = 0 ; i < opt_queue + opt_n_threads + gpu_threads ; i + + ) {
for ( i = 0 ; i < opt_queue + opt_n_threads + gpu_threads ; i + + ) {
if ( unlikely ( ! queue_request ( ) ) ) {
if ( unlikely ( ! queue_request ( ) ) ) {