2 * Copyright 2010 Jeff Garzik
3 * Copyright 2012-2014 pooler
4 * Copyright 2014 Lucas Jones
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version. See COPYING for more details.
12 #include "cpuminer-config.h"
28 #include <sys/resource.h>
30 #include <sys/types.h>
32 #include <sys/param.h>
34 #include <sys/sysctl.h>
38 #include <curl/curl.h>
42 #define PROGRAM_NAME "minerd"
43 #define LP_SCANTIME 60
44 #define JSON_BUF_LEN 345
46 #ifdef __linux /* Linux specific policy and affinity management */
48 static inline void drop_policy(void) {
49 struct sched_param param;
50 param.sched_priority = 0;
53 if (unlikely(sched_setscheduler(0, SCHED_IDLE, ¶m) == -1))
56 sched_setscheduler(0, SCHED_BATCH, ¶m);
60 static inline void affine_to_cpu(int id, int cpu) {
65 sched_setaffinity(0, sizeof(set), &set);
67 #elif defined(__FreeBSD__) /* FreeBSD specific policy and affinity management */
68 #include <sys/cpuset.h>
69 static inline void drop_policy(void)
73 static inline void affine_to_cpu(int id, int cpu)
78 cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), &set);
81 static inline void drop_policy(void)
85 static inline void affine_to_cpu(int id, int cpu)
90 enum workio_commands {
91 WC_GET_WORK, WC_SUBMIT_WORK,
95 enum workio_commands cmd;
103 ALGO_SCRYPT, /* scrypt(1024,1,1) */
104 ALGO_SHA256D, /* SHA-256d */
105 ALGO_KECCAK, /* Keccak */
106 ALGO_HEAVY, /* Heavy */
107 ALGO_QUARK, /* Quark */
108 ALGO_SKEIN, /* Skein */
109 ALGO_SHAVITE3, /* Shavite3 */
110 ALGO_BLAKE, /* Blake */
111 ALGO_FRESH, /* Fresh */
115 ALGO_X15, /* X15 Whirlpool */
116 ALGO_CRYPTONIGHT, /* CryptoNight */
119 static const char *algo_names[] = {
120 [ALGO_SCRYPT] = "scrypt",
121 [ALGO_SHA256D] = "sha256d",
122 [ALGO_KECCAK] = "keccak",
123 [ALGO_HEAVY] = "heavy",
124 [ALGO_QUARK] = "quark",
125 [ALGO_SKEIN] = "skein",
126 [ALGO_SHAVITE3] = "shavite3",
127 [ALGO_BLAKE] = "blake",
128 [ALGO_FRESH] = "fresh",
133 [ALGO_CRYPTONIGHT] = "cryptonight",
136 bool opt_debug = false;
137 bool opt_protocol = false;
138 static bool opt_benchmark = false;
139 bool opt_redirect = true;
140 bool want_longpoll = true;
141 bool have_longpoll = false;
142 bool want_stratum = true;
143 bool have_stratum = false;
144 static bool submit_old = false;
145 bool use_syslog = false;
146 static bool opt_background = false;
147 static bool opt_quiet = false;
148 static int opt_retries = -1;
149 static int opt_fail_pause = 10;
150 bool jsonrpc_2 = false;
152 static int opt_scantime = 5;
153 static json_t *opt_config;
154 static const bool opt_time = true;
155 static enum algos opt_algo = ALGO_SCRYPT;
156 static int opt_scrypt_n = 1024;
157 static int opt_n_threads;
158 static int num_processors;
159 static char *rpc_url;
160 static char *rpc_userpass;
161 static char *rpc_user, *rpc_pass;
165 struct thr_info *thr_info;
166 static int work_thr_id;
167 int longpoll_thr_id = -1;
168 int stratum_thr_id = -1;
169 struct work_restart *work_restart = NULL;
170 static struct stratum_ctx stratum;
171 static char rpc2_id[64] = "";
172 static char *rpc2_blob = NULL;
173 static int rpc2_bloblen = 0;
174 static uint32_t rpc2_target = 0;
175 static char *rpc2_job_id = NULL;
176 bool aes_ni_supported = false;
178 pthread_mutex_t applog_lock;
179 static pthread_mutex_t stats_lock;
180 static pthread_mutex_t rpc2_job_lock;
181 static pthread_mutex_t rpc2_login_lock;
183 static unsigned long accepted_count = 0L;
184 static unsigned long rejected_count = 0L;
185 static double *thr_hashrates;
187 #ifdef HAVE_GETOPT_LONG
198 static char const usage[] =
200 Usage: " PROGRAM_NAME " [OPTIONS]\n\
202 -a, --algo=ALGO specify the algorithm to use\n\
203 scrypt scrypt(1024, 1, 1) (default)\n\
204 scrypt:N scrypt(N, 1, 1)\n\
217 cryptonight CryptoNight\n\
218 -o, --url=URL URL of mining server\n\
219 -O, --userpass=U:P username:password pair for mining server\n\
220 -u, --user=USERNAME username for mining server\n\
221 -p, --pass=PASSWORD password for mining server\n\
222 --cert=FILE certificate for mining server using SSL\n\
223 -x, --proxy=[PROTOCOL://]HOST[:PORT] connect through a proxy\n\
224 -t, --threads=N number of miner threads (default: number of processors)\n\
225 -r, --retries=N number of times to retry if a network call fails\n\
226 (default: retry indefinitely)\n\
227 -R, --retry-pause=N time to pause between retries, in seconds (default: 30)\n\
228 -T, --timeout=N timeout for long polling, in seconds (default: none)\n\
229 -s, --scantime=N upper bound on time spent scanning current work when\n\
230 long polling is unavailable, in seconds (default: 5)\n\
231 --no-longpoll disable X-Long-Polling support\n\
232 --no-stratum disable X-Stratum support\n\
233 --no-redirect ignore requests to change the URL of the mining server\n\
234 -q, --quiet disable per-thread hashmeter output\n\
235 -D, --debug enable debug output\n\
236 -P, --protocol-dump verbose dump of protocol-level activities\n"
239 -S, --syslog use system log for output messages\n"
243 -B, --background run the miner in the background\n"
246 --benchmark run in offline benchmark mode\n\
247 -c, --config=FILE load a JSON-format configuration file\n\
248 -V, --version display version information and exit\n\
249 -h, --help display this help text and exit\n\
252 static char const short_options[] =
259 "a:c:Dhp:Px:qr:R:s:t:T:o:u:O:V";
261 static struct option const options[] = {
262 { "algo", 1, NULL, 'a' },
264 { "background", 0, NULL, 'B' },
266 { "benchmark", 0, NULL, 1005 },
267 { "cert", 1, NULL, 1001 },
268 { "config", 1, NULL, 'c' },
269 { "debug", 0, NULL, 'D' },
270 { "help", 0, NULL, 'h' },
271 { "no-longpoll", 0, NULL, 1003 },
272 { "no-redirect", 0, NULL, 1009 },
273 { "no-stratum", 0, NULL, 1007 },
274 { "pass", 1, NULL, 'p' },
275 { "protocol-dump", 0, NULL, 'P' },
276 { "proxy", 1, NULL, 'x' },
277 { "quiet", 0, NULL, 'q' },
278 { "retries", 1, NULL, 'r' },
279 { "retry-pause", 1, NULL, 'R' },
280 { "scantime", 1, NULL, 's' },
282 { "syslog", 0, NULL, 'S' },
284 { "threads", 1, NULL, 't' },
285 { "timeout", 1, NULL, 'T' },
286 { "url", 1, NULL, 'o' },
287 { "user", 1, NULL, 'u' },
288 { "userpass", 1, NULL, 'O' },
289 { "version", 0, NULL, 'V' },
293 static struct work g_work;
294 static time_t g_work_time;
295 static pthread_mutex_t g_work_lock;
297 static bool rpc2_login(CURL *curl);
298 static void workio_cmd_free(struct workio_cmd *wc);
300 json_t *json_rpc2_call_recur(CURL *curl, const char *url,
301 const char *userpass, json_t *rpc_req,
302 int *curl_err, int flags, int recur) {
305 applog(LOG_DEBUG, "Failed to call rpc command after %i tries", recur);
308 if(!strcmp(rpc2_id, "")) {
310 applog(LOG_DEBUG, "Tried to call rpc2 command before authentication");
313 json_t *params = json_object_get(rpc_req, "params");
315 json_t *auth_id = json_object_get(params, "id");
317 json_string_set(auth_id, rpc2_id);
320 json_t *res = json_rpc_call(curl, url, userpass, json_dumps(rpc_req, 0),
321 curl_err, flags | JSON_RPC_IGNOREERR);
323 json_t *error = json_object_get(res, "error");
326 if(json_is_string(error))
329 message = json_object_get(error, "message");
330 if(!message || !json_is_string(message)) goto end;
331 const char *mes = json_string_value(message);
332 if(!strcmp(mes, "Unauthenticated")) {
333 pthread_mutex_lock(&rpc2_login_lock);
336 pthread_mutex_unlock(&rpc2_login_lock);
337 return json_rpc2_call_recur(curl, url, userpass, rpc_req,
338 curl_err, flags, recur + 1);
339 } else if(!strcmp(mes, "Low difficulty share") || !strcmp(mes, "Block expired") || !strcmp(mes, "Invalid job id") || !strcmp(mes, "Duplicate share")) {
340 json_t *result = json_object_get(res, "result");
344 json_object_set(result, "reject-reason", json_string(mes));
346 applog(LOG_ERR, "json_rpc2.0 error: %s", mes);
353 json_t *json_rpc2_call(CURL *curl, const char *url,
354 const char *userpass, const char *rpc_req,
355 int *curl_err, int flags) {
356 json_t* req_json = JSON_LOADS(rpc_req, NULL);
357 json_t* res = json_rpc2_call_recur(curl, url, userpass, req_json,
359 json_decref(req_json);
363 static inline void work_free(struct work *w) {
368 static inline void work_copy(struct work *dest, const struct work *src) {
369 memcpy(dest, src, sizeof(struct work));
371 dest->job_id = strdup(src->job_id);
373 dest->xnonce2 = malloc(src->xnonce2_len);
374 memcpy(dest->xnonce2, src->xnonce2, src->xnonce2_len);
378 static bool jobj_binary(const json_t *obj, const char *key, void *buf,
383 tmp = json_object_get(obj, key);
384 if (unlikely(!tmp)) {
385 applog(LOG_ERR, "JSON key '%s' not found", key);
388 hexstr = json_string_value(tmp);
389 if (unlikely(!hexstr)) {
390 applog(LOG_ERR, "JSON key '%s' is not a string", key);
393 if (!hex2bin(buf, hexstr, buflen))
399 bool rpc2_job_decode(const json_t *job, struct work *work) {
401 applog(LOG_ERR, "Tried to decode job without JSON-RPC 2.0");
405 tmp = json_object_get(job, "job_id");
407 applog(LOG_ERR, "JSON inval job id");
410 const char *job_id = json_string_value(tmp);
411 tmp = json_object_get(job, "blob");
413 applog(LOG_ERR, "JSON inval blob");
416 const char *hexblob = json_string_value(tmp);
417 int blobLen = strlen(hexblob);
418 if (blobLen % 2 != 0 || ((blobLen / 2) < 40 && blobLen != 0) || (blobLen / 2) > 128) {
419 applog(LOG_ERR, "JSON invalid blob length");
423 pthread_mutex_lock(&rpc2_job_lock);
424 char *blob = malloc(blobLen / 2);
425 if (!hex2bin(blob, hexblob, blobLen / 2)) {
426 applog(LOG_ERR, "JSON inval blob");
427 pthread_mutex_unlock(&rpc2_job_lock);
433 rpc2_bloblen = blobLen / 2;
434 rpc2_blob = malloc(rpc2_bloblen);
435 memcpy(rpc2_blob, blob, blobLen / 2);
440 jobj_binary(job, "target", &target, 4);
441 if(rpc2_target != target) {
443 pthread_mutex_lock(&stats_lock);
444 for (size_t i = 0; i < opt_n_threads; i++)
445 hashrate += thr_hashrates[i];
446 pthread_mutex_unlock(&stats_lock);
447 double difficulty = (((double) 0xffffffff) / target);
448 applog(LOG_INFO, "Pool set diff to %g", difficulty);
449 rpc2_target = target;
455 rpc2_job_id = strdup(job_id);
456 pthread_mutex_unlock(&rpc2_job_lock);
460 applog(LOG_ERR, "Requested work before work was received");
463 memcpy(work->data, rpc2_blob, rpc2_bloblen);
464 memset(work->target, 0xff, sizeof(work->target));
465 work->target[7] = rpc2_target;
468 work->job_id = strdup(rpc2_job_id);
476 static bool work_decode(const json_t *val, struct work *work) {
480 return rpc2_job_decode(val, work);
483 if (unlikely(!jobj_binary(val, "data", work->data, sizeof(work->data)))) {
484 applog(LOG_ERR, "JSON inval data");
487 if (unlikely(!jobj_binary(val, "target", work->target, sizeof(work->target)))) {
488 applog(LOG_ERR, "JSON inval target");
492 for (i = 0; i < ARRAY_SIZE(work->data); i++)
493 work->data[i] = le32dec(work->data + i);
494 for (i = 0; i < ARRAY_SIZE(work->target); i++)
495 work->target[i] = le32dec(work->target + i);
499 err_out: return false;
502 bool rpc2_login_decode(const json_t *val) {
506 json_t *res = json_object_get(val, "result");
508 applog(LOG_ERR, "JSON invalid result");
513 tmp = json_object_get(res, "id");
515 applog(LOG_ERR, "JSON inval id");
518 id = json_string_value(tmp);
520 applog(LOG_ERR, "JSON id is not a string");
524 memcpy(&rpc2_id, id, 64);
527 applog(LOG_DEBUG, "Auth id: %s", id);
529 tmp = json_object_get(res, "status");
531 applog(LOG_ERR, "JSON inval status");
534 s = json_string_value(tmp);
536 applog(LOG_ERR, "JSON status is not a string");
539 if(strcmp(s, "OK")) {
540 applog(LOG_ERR, "JSON returned status \"%s\"", s);
546 err_out: return false;
549 static void share_result(int result, struct work *work, const char *reason) {
555 pthread_mutex_lock(&stats_lock);
556 for (i = 0; i < opt_n_threads; i++)
557 hashrate += thr_hashrates[i];
558 result ? accepted_count++ : rejected_count++;
559 pthread_mutex_unlock(&stats_lock);
562 case ALGO_CRYPTONIGHT:
563 applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %.2f H/s at diff %g %s",
564 accepted_count, accepted_count + rejected_count,
565 100. * accepted_count / (accepted_count + rejected_count), hashrate,
566 (((double) 0xffffffff) / (work ? work->target[7] : rpc2_target)),
567 result ? "(yay!!!)" : "(booooo)");
570 sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", 1e-3 * hashrate);
571 applog(LOG_INFO, "accepted: %lu/%lu (%.2f%%), %s khash/s %s",
572 accepted_count, accepted_count + rejected_count,
573 100. * accepted_count / (accepted_count + rejected_count), s,
574 result ? "(yay!!!)" : "(booooo)");
578 if (opt_debug && reason)
579 applog(LOG_DEBUG, "DEBUG: reject reason: %s", reason);
582 static bool submit_upstream_work(CURL *curl, struct work *work) {
584 json_t *val, *res, *reason;
585 char s[JSON_BUF_LEN];
589 /* pass if the previous hash is not the current previous hash */
590 if (!submit_old && memcmp(work->data + 1, g_work.data + 1, 32)) {
592 applog(LOG_DEBUG, "DEBUG: stale work detected, discarding");
597 uint32_t ntime, nonce;
598 char *ntimestr, *noncestr, *xnonce2str;
601 noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4);
604 case ALGO_CRYPTONIGHT:
606 cryptonight_hash(hash, work->data, 76);
608 char *hashhex = bin2hex(hash, 32);
609 snprintf(s, JSON_BUF_LEN,
610 "{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":1}\r\n",
611 rpc2_id, work->job_id, noncestr, hashhex);
614 le32enc(&ntime, work->data[17]);
615 le32enc(&nonce, work->data[19]);
616 ntimestr = bin2hex((const unsigned char *) (&ntime), 4);
617 noncestr = bin2hex((const unsigned char *) (&nonce), 4);
618 xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
619 snprintf(s, JSON_BUF_LEN,
620 "{\"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":4}",
621 rpc_user, work->job_id, xnonce2str, ntimestr, noncestr);
627 if (unlikely(!stratum_send_line(&stratum, s))) {
628 applog(LOG_ERR, "submit_upstream_work stratum_send_line failed");
632 /* build JSON-RPC request */
634 char *noncestr = bin2hex(((const unsigned char*)work->data) + 39, 4);
637 case ALGO_CRYPTONIGHT:
639 cryptonight_hash(hash, work->data, 76);
641 char *hashhex = bin2hex(hash, 32);
642 snprintf(s, JSON_BUF_LEN,
643 "{\"method\": \"submit\", \"params\": {\"id\": \"%s\", \"job_id\": \"%s\", \"nonce\": \"%s\", \"result\": \"%s\"}, \"id\":1}\r\n",
644 rpc2_id, work->job_id, noncestr, hashhex);
648 /* issue JSON-RPC request */
649 val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0);
650 if (unlikely(!val)) {
651 applog(LOG_ERR, "submit_upstream_work json_rpc_call failed");
654 res = json_object_get(val, "result");
655 json_t *status = json_object_get(res, "status");
656 reason = json_object_get(res, "reject-reason");
657 share_result(!strcmp(status ? json_string_value(status) : "", "OK"), work,
658 reason ? json_string_value(reason) : NULL );
660 /* build hex string */
661 for (i = 0; i < 76; i++)
662 le32enc(((char*)work->data) + i, *((uint32_t*) (((char*)work->data) + i)));
663 str = bin2hex((unsigned char *) work->data, 76);
664 if (unlikely(!str)) {
665 applog(LOG_ERR, "submit_upstream_work OOM");
668 snprintf(s, JSON_BUF_LEN,
669 "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n",
672 /* issue JSON-RPC request */
673 val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0);
674 if (unlikely(!val)) {
675 applog(LOG_ERR, "submit_upstream_work json_rpc_call failed");
678 res = json_object_get(val, "result");
679 reason = json_object_get(val, "reject-reason");
680 share_result(json_is_true(res), work,
681 reason ? json_string_value(reason) : NULL );
693 static const char *rpc_req =
694 "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
696 static bool get_upstream_work(CURL *curl, struct work *work) {
699 struct timeval tv_start, tv_end, diff;
701 gettimeofday(&tv_start, NULL );
705 snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id);
706 val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, NULL, 0);
708 val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req, NULL, 0);
710 gettimeofday(&tv_end, NULL );
721 rc = work_decode(json_object_get(val, "result"), work);
723 if (opt_debug && rc) {
724 timeval_subtract(&diff, &tv_end, &tv_start);
725 applog(LOG_DEBUG, "DEBUG: got new work in %d ms",
726 diff.tv_sec * 1000 + diff.tv_usec / 1000);
734 static bool rpc2_login(CURL *curl) {
740 struct timeval tv_start, tv_end, diff;
741 char s[JSON_BUF_LEN];
743 snprintf(s, JSON_BUF_LEN, "{\"method\": \"login\", \"params\": {\"login\": \"%s\", \"pass\": \"%s\", \"agent\": \"cpuminer-multi/0.1\"}, \"id\": 1}", rpc_user, rpc_pass);
745 gettimeofday(&tv_start, NULL );
746 val = json_rpc_call(curl, rpc_url, rpc_userpass, s, NULL, 0);
747 gettimeofday(&tv_end, NULL );
752 // applog(LOG_DEBUG, "JSON value: %s", json_dumps(val, 0));
754 rc = rpc2_login_decode(val);
756 json_t *result = json_object_get(val, "result");
758 if(!result) goto end;
760 json_t *job = json_object_get(result, "job");
762 if(!rpc2_job_decode(job, &g_work)) {
766 if (opt_debug && rc) {
767 timeval_subtract(&diff, &tv_end, &tv_start);
768 applog(LOG_DEBUG, "DEBUG: authenticated in %d ms",
769 diff.tv_sec * 1000 + diff.tv_usec / 1000);
778 static void workio_cmd_free(struct workio_cmd *wc) {
784 work_free(wc->u.work);
787 default: /* do nothing */
791 memset(wc, 0, sizeof(*wc)); /* poison */
795 static bool workio_get_work(struct workio_cmd *wc, CURL *curl) {
796 struct work *ret_work;
799 ret_work = calloc(1, sizeof(*ret_work));
803 /* obtain new work from bitcoin via JSON-RPC */
804 while (!get_upstream_work(curl, ret_work)) {
805 if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
806 applog(LOG_ERR, "json_rpc_call failed, terminating workio thread");
811 /* pause, then restart work-request loop */
812 applog(LOG_ERR, "getwork failed, retry after %d seconds",
814 sleep(opt_fail_pause);
817 /* send work to requesting thread */
818 if (!tq_push(wc->thr->q, ret_work))
824 static bool workio_submit_work(struct workio_cmd *wc, CURL *curl) {
827 /* submit solution to bitcoin via JSON-RPC */
828 while (!submit_upstream_work(curl, wc->u.work)) {
829 if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
830 applog(LOG_ERR, "...terminating workio thread");
834 /* pause, then restart work-request loop */
835 applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause);
836 sleep(opt_fail_pause);
842 static bool workio_login(CURL *curl) {
845 /* submit solution to bitcoin via JSON-RPC */
846 pthread_mutex_lock(&rpc2_login_lock);
847 while (!rpc2_login(curl)) {
848 if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
849 applog(LOG_ERR, "...terminating workio thread");
850 pthread_mutex_unlock(&rpc2_login_lock);
854 /* pause, then restart work-request loop */
855 applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause);
856 sleep(opt_fail_pause);
857 pthread_mutex_unlock(&rpc2_login_lock);
858 pthread_mutex_lock(&rpc2_login_lock);
860 pthread_mutex_unlock(&rpc2_login_lock);
865 static void *workio_thread(void *userdata) {
866 struct thr_info *mythr = userdata;
870 curl = curl_easy_init();
871 if (unlikely(!curl)) {
872 applog(LOG_ERR, "CURL initialization failed");
877 ok = workio_login(curl);
881 struct workio_cmd *wc;
883 /* wait for workio_cmd sent to us, on our queue */
884 wc = tq_pop(mythr->q, NULL );
890 /* process workio_cmd */
893 ok = workio_get_work(wc, curl);
896 ok = workio_submit_work(wc, curl);
899 default: /* should never happen */
908 curl_easy_cleanup(curl);
913 static bool get_work(struct thr_info *thr, struct work *work) {
914 struct workio_cmd *wc;
915 struct work *work_heap;
918 memset(work->data, 0x55, 76);
919 work->data[17] = swab32(time(NULL ));
920 memset(work->data + 19, 0x00, 52);
921 work->data[20] = 0x80000000;
922 work->data[31] = 0x00000280;
923 memset(work->target, 0x00, sizeof(work->target));
927 /* fill out work request message */
928 wc = calloc(1, sizeof(*wc));
932 wc->cmd = WC_GET_WORK;
935 /* send work request to workio thread */
936 if (!tq_push(thr_info[work_thr_id].q, wc)) {
941 /* wait for response, a unit of work */
942 work_heap = tq_pop(thr->q, NULL );
946 /* copy returned work into storage provided by caller */
947 memcpy(work, work_heap, sizeof(*work));
953 static bool submit_work(struct thr_info *thr, const struct work *work_in) {
954 struct workio_cmd *wc;
956 /* fill out work request message */
957 wc = calloc(1, sizeof(*wc));
961 wc->u.work = malloc(sizeof(*work_in));
965 wc->cmd = WC_SUBMIT_WORK;
967 work_copy(wc->u.work, work_in);
969 /* send solution to workio thread */
970 if (!tq_push(thr_info[work_thr_id].q, wc))
975 err_out: workio_cmd_free(wc);
979 static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) {
980 unsigned char merkle_root[64];
983 pthread_mutex_lock(&sctx->work_lock);
987 memcpy(work, &sctx->work, sizeof(struct work));
988 work->job_id = strdup(sctx->work.job_id);
989 pthread_mutex_unlock(&sctx->work_lock);
992 work->job_id = strdup(sctx->job.job_id);
993 work->xnonce2_len = sctx->xnonce2_size;
994 work->xnonce2 = realloc(work->xnonce2, sctx->xnonce2_size);
995 memcpy(work->xnonce2, sctx->job.xnonce2, sctx->xnonce2_size);
997 /* Generate merkle root */
998 sha256d(merkle_root, sctx->job.coinbase, sctx->job.coinbase_size);
999 for (i = 0; i < sctx->job.merkle_count; i++) {
1000 memcpy(merkle_root + 32, sctx->job.merkle[i], 32);
1001 sha256d(merkle_root, merkle_root, 64);
1004 /* Increment extranonce2 */
1005 for (i = 0; i < sctx->xnonce2_size && !++sctx->job.xnonce2[i]; i++)
1008 /* Assemble block header */
1009 memset(work->data, 0, 128);
1010 work->data[0] = le32dec(sctx->job.version);
1011 for (i = 0; i < 8; i++)
1012 work->data[1 + i] = le32dec((uint32_t *) sctx->job.prevhash + i);
1013 for (i = 0; i < 8; i++)
1014 work->data[9 + i] = be32dec((uint32_t *) merkle_root + i);
1015 work->data[17] = le32dec(sctx->job.ntime);
1016 work->data[18] = le32dec(sctx->job.nbits);
1017 work->data[20] = 0x80000000;
1018 work->data[31] = 0x00000280;
1020 pthread_mutex_unlock(&sctx->work_lock);
1023 char *xnonce2str = bin2hex(work->xnonce2, work->xnonce2_len);
1024 applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x",
1025 work->job_id, xnonce2str, swab32(work->data[17]));
1029 if (opt_algo == ALGO_SCRYPT)
1030 diff_to_target(work->target, sctx->job.diff / 65536.0);
1032 diff_to_target(work->target, sctx->job.diff);
1036 static void *miner_thread(void *userdata) {
1037 struct thr_info *mythr = userdata;
1038 int thr_id = mythr->id;
1039 struct work work = { { 0 } };
1041 uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 0x20;
1042 unsigned char *scratchbuf = NULL;
1046 /* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
1047 * and if that fails, then SCHED_BATCH. No need for this to be an
1048 * error if it fails */
1049 if (!opt_benchmark) {
1050 setpriority(PRIO_PROCESS, 0, 19);
1054 /* Cpu affinity only makes sense if the number of threads is a multiple
1055 * of the number of CPUs */
1056 if (num_processors > 1 && opt_n_threads % num_processors == 0) {
1058 applog(LOG_INFO, "Binding thread %d to cpu %d", thr_id,
1059 thr_id % num_processors);
1060 affine_to_cpu(thr_id, thr_id % num_processors);
1063 if (opt_algo == ALGO_SCRYPT) {
1064 scratchbuf = scrypt_buffer_alloc(opt_scrypt_n);
1066 applog(LOG_ERR, "scrypt buffer allocation failed");
1067 pthread_mutex_lock(&applog_lock);
1071 uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + (jsonrpc_2 ? 39 : 76));
1074 uint64_t hashes_done;
1075 struct timeval tv_start, tv_end, diff;
1080 while (!jsonrpc_2 && time(NULL) >= g_work_time + 120)
1082 pthread_mutex_lock(&g_work_lock);
1083 if ((*nonceptr) >= end_nonce
1084 && !(jsonrpc_2 ? memcmp(work.data, g_work.data, 39) ||
1085 memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33)
1086 : memcmp(work.data, g_work.data, 76)))
1087 stratum_gen_work(&stratum, &g_work);
1089 /* obtain new work from internal workio thread */
1090 pthread_mutex_lock(&g_work_lock);
1093 || time(NULL ) >= g_work_time + LP_SCANTIME * 3 / 4
1094 || *nonceptr >= end_nonce))) {
1095 if (unlikely(!get_work(mythr, &g_work))) {
1096 applog(LOG_ERR, "work retrieval failed, exiting "
1097 "mining thread %d", mythr->id);
1098 pthread_mutex_unlock(&g_work_lock);
1101 g_work_time = have_stratum ? 0 : time(NULL );
1104 pthread_mutex_unlock(&g_work_lock);
1108 if (jsonrpc_2 ? memcmp(work.data, g_work.data, 39) || memcmp(((uint8_t*) work.data) + 43, ((uint8_t*) g_work.data) + 43, 33) : memcmp(work.data, g_work.data, 76)) {
1110 work_copy(&work, &g_work);
1111 nonceptr = (uint32_t*) (((char*)work.data) + (jsonrpc_2 ? 39 : 76));
1112 *nonceptr = 0xffffffffU / opt_n_threads * thr_id;
1115 pthread_mutex_unlock(&g_work_lock);
1116 work_restart[thr_id].restart = 0;
1118 /* adjust max_nonce to meet target scan time */
1120 max64 = LP_SCANTIME;
1122 max64 = g_work_time + (have_longpoll ? LP_SCANTIME : opt_scantime)
1124 max64 *= thr_hashrates[thr_id];
1128 max64 = opt_scrypt_n < 16 ? 0x3ffff : 0x3fffff / opt_scrypt_n;
1130 case ALGO_CRYPTONIGHT:
1150 if (*nonceptr + max64 > end_nonce)
1151 max_nonce = end_nonce;
1153 max_nonce = *nonceptr + max64;
1156 gettimeofday(&tv_start, NULL );
1158 /* scan nonces for a proof-of-work hash */
1161 rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target,
1162 max_nonce, &hashes_done, opt_scrypt_n);
1166 rc = scanhash_sha256d(thr_id, work.data, work.target, max_nonce,
1171 rc = scanhash_keccak(thr_id, work.data, work.target, max_nonce,
1176 rc = scanhash_heavy(thr_id, work.data, work.target, max_nonce,
1181 rc = scanhash_quark(thr_id, work.data, work.target, max_nonce,
1186 rc = scanhash_skein(thr_id, work.data, work.target, max_nonce,
1190 rc = scanhash_ink(thr_id, work.data, work.target, max_nonce,
1194 rc = scanhash_blake(thr_id, work.data, work.target, max_nonce,
1198 rc = scanhash_fresh(thr_id, work.data, work.target, max_nonce,
1202 rc = scanhash_x11(thr_id, work.data, work.target, max_nonce,
1206 rc = scanhash_x13(thr_id, work.data, work.target, max_nonce,
1210 rc = scanhash_x14(thr_id, work.data, work.target, max_nonce,
1214 rc = scanhash_x15(thr_id, work.data, work.target, max_nonce,
1217 case ALGO_CRYPTONIGHT:
1218 rc = scanhash_cryptonight(thr_id, work.data, work.target,
1219 max_nonce, &hashes_done);
1223 /* should never happen */
1227 /* record scanhash elapsed time */
1228 gettimeofday(&tv_end, NULL);
1229 timeval_subtract(&diff, &tv_end, &tv_start);
1230 if (diff.tv_usec || diff.tv_sec) {
1231 pthread_mutex_lock(&stats_lock);
1232 thr_hashrates[thr_id] =
1233 hashes_done / (diff.tv_sec + diff.tv_usec * 1e-6);
1234 pthread_mutex_unlock(&stats_lock);
1238 case ALGO_CRYPTONIGHT:
1239 applog(LOG_INFO, "thread %d: %lu hashes, %.2f H/s", thr_id,
1240 hashes_done, thr_hashrates[thr_id]);
1243 sprintf(s, thr_hashrates[thr_id] >= 1e6 ? "%.0f" : "%.2f",
1244 thr_hashrates[thr_id] / 1e3);
1245 applog(LOG_INFO, "thread %d: %llu hashes, %s khash/s", thr_id,
1250 if (opt_benchmark && thr_id == opt_n_threads - 1) {
1251 double hashrate = 0.;
1252 for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++)
1253 hashrate += thr_hashrates[i];
1254 if (i == opt_n_threads) {
1256 case ALGO_CRYPTONIGHT:
1257 applog(LOG_INFO, "Total: %s H/s", hashrate);
1260 sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000);
1261 applog(LOG_INFO, "Total: %s khash/s", s);
1267 /* if nonce found, submit work */
1268 if (rc && !opt_benchmark && !submit_work(mythr, &work))
1272 out: tq_freeze(mythr->q);
1277 static void restart_threads(void) {
1280 for (i = 0; i < opt_n_threads; i++)
1281 work_restart[i].restart = 1;
1284 static void *longpoll_thread(void *userdata) {
1285 struct thr_info *mythr = userdata;
1287 char *copy_start, *hdr_path = NULL, *lp_url = NULL;
1288 bool need_slash = false;
1290 curl = curl_easy_init();
1291 if (unlikely(!curl)) {
1292 applog(LOG_ERR, "CURL initialization failed");
1296 start: hdr_path = tq_pop(mythr->q, NULL );
1301 if (strstr(hdr_path, "://")) {
1306 /* absolute path, on current server */
1308 copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path;
1309 if (rpc_url[strlen(rpc_url) - 1] != '/')
1312 lp_url = malloc(strlen(rpc_url) + strlen(copy_start) + 2);
1316 sprintf(lp_url, "%s%s%s", rpc_url, need_slash ? "/" : "", copy_start);
1319 applog(LOG_INFO, "Long-polling activated for %s", lp_url);
1322 json_t *val, *soval;
1326 pthread_mutex_lock(&rpc2_login_lock);
1327 if(!strcmp(rpc2_id, "")) {
1332 snprintf(s, 128, "{\"method\": \"getjob\", \"params\": {\"id\": \"%s\"}, \"id\":1}\r\n", rpc2_id);
1333 pthread_mutex_unlock(&rpc2_login_lock);
1334 val = json_rpc2_call(curl, rpc_url, rpc_userpass, s, &err, JSON_RPC_LONGPOLL);
1336 val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req, &err, JSON_RPC_LONGPOLL);
1345 soval = json_object_get(json_object_get(val, "result"),
1347 submit_old = soval ? json_is_true(soval) : false;
1349 pthread_mutex_lock(&g_work_lock);
1350 char *start_job_id = strdup(g_work.job_id);
1351 if (work_decode(json_object_get(val, "result"), &g_work)) {
1352 if (strcmp(start_job_id, g_work.job_id)) {
1353 applog(LOG_INFO, "LONGPOLL detected new block");
1355 applog(LOG_DEBUG, "DEBUG: got new work");
1361 pthread_mutex_unlock(&g_work_lock);
1364 pthread_mutex_lock(&g_work_lock);
1365 g_work_time -= LP_SCANTIME;
1366 pthread_mutex_unlock(&g_work_lock);
1367 if (err == CURLE_OPERATION_TIMEDOUT) {
1370 have_longpoll = false;
1375 sleep(opt_fail_pause);
1381 out: free(hdr_path);
1383 tq_freeze(mythr->q);
1385 curl_easy_cleanup(curl);
1390 static bool stratum_handle_response(char *buf) {
1391 json_t *val, *err_val, *res_val, *id_val;
1396 val = JSON_LOADS(buf, &err);
1398 applog(LOG_INFO, "JSON decode failed(%d): %s", err.line, err.text);
1402 res_val = json_object_get(val, "result");
1403 err_val = json_object_get(val, "error");
1404 id_val = json_object_get(val, "id");
1406 if (!id_val || json_is_null(id_val) || !res_val)
1410 json_t *status = json_object_get(res_val, "status");
1412 const char *s = json_string_value(status);
1413 valid = !strcmp(s, "OK") && json_is_null(err_val);
1415 valid = json_is_null(err_val);
1418 valid = json_is_true(res_val);
1421 share_result(valid, NULL,
1422 err_val ? (jsonrpc_2 ? json_string_value(err_val) : json_string_value(json_array_get(err_val, 1))) : NULL );
1431 static void *stratum_thread(void *userdata) {
1432 struct thr_info *mythr = userdata;
1435 stratum.url = tq_pop(mythr->q, NULL );
1438 applog(LOG_INFO, "Starting Stratum on %s", stratum.url);
1443 while (!stratum.curl) {
1444 pthread_mutex_lock(&g_work_lock);
1446 pthread_mutex_unlock(&g_work_lock);
1449 if (!stratum_connect(&stratum, stratum.url)
1450 || !stratum_subscribe(&stratum)
1451 || !stratum_authorize(&stratum, rpc_user, rpc_pass)) {
1452 stratum_disconnect(&stratum);
1453 if (opt_retries >= 0 && ++failures > opt_retries) {
1454 applog(LOG_ERR, "...terminating workio thread");
1455 tq_push(thr_info[work_thr_id].q, NULL );
1458 applog(LOG_ERR, "...retry after %d seconds", opt_fail_pause);
1459 sleep(opt_fail_pause);
1464 if (stratum.work.job_id
1466 || strcmp(stratum.work.job_id, g_work.job_id))) {
1467 pthread_mutex_lock(&g_work_lock);
1468 stratum_gen_work(&stratum, &g_work);
1470 pthread_mutex_unlock(&g_work_lock);
1471 applog(LOG_INFO, "Stratum detected new block");
1475 if (stratum.job.job_id
1477 || strcmp(stratum.job.job_id, g_work.job_id))) {
1478 pthread_mutex_lock(&g_work_lock);
1479 stratum_gen_work(&stratum, &g_work);
1481 pthread_mutex_unlock(&g_work_lock);
1482 if (stratum.job.clean) {
1483 applog(LOG_INFO, "Stratum detected new block");
1489 if (!stratum_socket_full(&stratum, 120)) {
1490 applog(LOG_ERR, "Stratum connection timed out");
1493 s = stratum_recv_line(&stratum);
1495 stratum_disconnect(&stratum);
1496 applog(LOG_ERR, "Stratum connection interrupted");
1499 if (!stratum_handle_method(&stratum, s))
1500 stratum_handle_response(s);
1507 static void show_version_and_exit(void) {
1508 printf(PACKAGE_STRING "\n built on " __DATE__ "\n features:"
1509 #if defined(USE_ASM) && defined(__i386__)
1512 #if defined(USE_ASM) && defined(__x86_64__)
1515 #if defined(USE_ASM) && defined(__i386__) || defined(__x86_64__)
1518 #if defined(__x86_64__) && defined(USE_AVX)
1521 #if defined(__x86_64__) && defined(USE_AVX2)
1524 #if defined(__x86_64__) && defined(USE_XOP)
1527 #if defined(USE_ASM) && defined(__arm__) && defined(__APCS_32__)
1529 #if defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || \
1530 defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_6__) || \
1531 defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || \
1532 defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_6T2__) || \
1533 defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || \
1534 defined(__ARM_ARCH_7__) || \
1535 defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
1536 defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
1539 #if defined(__ARM_NEON__)
1545 printf("%s\n", curl_version());
1546 #ifdef JANSSON_VERSION
1547 printf("libjansson %s\n", JANSSON_VERSION);
1552 static void show_usage_and_exit(int status) {
1555 "Try `" PROGRAM_NAME " --help' for more information.\n");
1561 static void parse_arg(int key, char *arg) {
1567 for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
1568 v = strlen(algo_names[i]);
1569 if (!strncmp(arg, algo_names[i], v)) {
1570 if (arg[v] == '\0') {
1574 if (arg[v] == ':' && i == ALGO_SCRYPT) {
1576 v = strtol(arg+v+1, &ep, 10);
1577 if (*ep || v & (v-1) || v < 2)
1585 if (i == ARRAY_SIZE(algo_names))
1586 show_usage_and_exit(1);
1589 opt_background = true;
1594 json_decref(opt_config);
1595 #if JANSSON_VERSION_HEX >= 0x020000
1596 opt_config = json_load_file(arg, 0, &err);
1598 opt_config = json_load_file(arg, &err);
1600 if (!json_is_object(opt_config)) {
1601 applog(LOG_ERR, "JSON decode of %s failed", arg);
1614 rpc_pass = strdup(arg);
1617 opt_protocol = true;
1621 if (v < -1 || v > 9999) /* sanity check */
1622 show_usage_and_exit(1);
1627 if (v < 1 || v > 9999) /* sanity check */
1628 show_usage_and_exit(1);
1633 if (v < 1 || v > 9999) /* sanity check */
1634 show_usage_and_exit(1);
1639 if (v < 1 || v > 99999) /* sanity check */
1640 show_usage_and_exit(1);
1645 if (v < 1 || v > 9999) /* sanity check */
1646 show_usage_and_exit(1);
1651 rpc_user = strdup(arg);
1653 case 'o': /* --url */
1654 p = strstr(arg, "://");
1656 if (strncasecmp(arg, "http://", 7)
1657 && strncasecmp(arg, "https://", 8)
1658 && strncasecmp(arg, "stratum+tcp://", 14))
1659 show_usage_and_exit(1);
1661 rpc_url = strdup(arg);
1663 if (!strlen(arg) || *arg == '/')
1664 show_usage_and_exit(1);
1666 rpc_url = malloc(strlen(arg) + 8);
1667 sprintf(rpc_url, "http://%s", arg);
1669 p = strrchr(rpc_url, '@');
1673 ap = strstr(rpc_url, "://") + 3;
1674 sp = strchr(ap, ':');
1677 rpc_userpass = strdup(ap);
1679 rpc_user = calloc(sp - ap + 1, 1);
1680 strncpy(rpc_user, ap, sp - ap);
1682 rpc_pass = strdup(sp + 1);
1685 rpc_user = strdup(ap);
1687 memmove(ap, p + 1, strlen(p + 1) + 1);
1689 have_stratum = !opt_benchmark && !strncasecmp(rpc_url, "stratum", 7);
1691 case 'O': /* --userpass */
1692 p = strchr(arg, ':');
1694 show_usage_and_exit(1);
1696 rpc_userpass = strdup(arg);
1698 rpc_user = calloc(p - arg + 1, 1);
1699 strncpy(rpc_user, arg, p - arg);
1701 rpc_pass = strdup(p + 1);
1703 case 'x': /* --proxy */
1704 if (!strncasecmp(arg, "socks4://", 9))
1705 opt_proxy_type = CURLPROXY_SOCKS4;
1706 else if (!strncasecmp(arg, "socks5://", 9))
1707 opt_proxy_type = CURLPROXY_SOCKS5;
1708 #if LIBCURL_VERSION_NUM >= 0x071200
1709 else if (!strncasecmp(arg, "socks4a://", 10))
1710 opt_proxy_type = CURLPROXY_SOCKS4A;
1711 else if (!strncasecmp(arg, "socks5h://", 10))
1712 opt_proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
1715 opt_proxy_type = CURLPROXY_HTTP;
1717 opt_proxy = strdup(arg);
1721 opt_cert = strdup(arg);
1724 opt_benchmark = true;
1725 want_longpoll = false;
1726 want_stratum = false;
1727 have_stratum = false;
1730 want_longpoll = false;
1733 want_stratum = false;
1736 opt_redirect = false;
1742 show_version_and_exit();
1744 show_usage_and_exit(0);
1746 show_usage_and_exit(1);
1750 static void parse_config(void) {
1754 if (!json_is_object(opt_config))
1757 for (i = 0; i < ARRAY_SIZE(options); i++) {
1758 if (!options[i].name)
1760 if (!strcmp(options[i].name, "config"))
1763 val = json_object_get(opt_config, options[i].name);
1767 if (options[i].has_arg && json_is_string(val)) {
1768 char *s = strdup(json_string_value(val));
1771 parse_arg(options[i].val, s);
1773 } else if (!options[i].has_arg && json_is_true(val))
1774 parse_arg(options[i].val, "");
1776 applog(LOG_ERR, "JSON option %s invalid", options[i].name);
1780 static void parse_cmdline(int argc, char *argv[]) {
1784 #if HAVE_GETOPT_LONG
1785 key = getopt_long(argc, argv, short_options, options, NULL );
1787 key = getopt(argc, argv, short_options);
1792 parse_arg(key, optarg);
1794 if (optind < argc) {
1795 fprintf(stderr, "%s: unsupported non-option argument '%s'\n", argv[0],
1797 show_usage_and_exit(1);
1804 static void signal_handler(int sig) {
1807 applog(LOG_INFO, "SIGHUP received");
1810 applog(LOG_INFO, "SIGINT received, exiting");
1814 applog(LOG_INFO, "SIGTERM received, exiting");
1821 static inline int cpuid(int code, uint32_t where[4]) {
1822 asm volatile("cpuid":"=a"(*where),"=b"(*(where+1)),
1823 "=c"(*(where+2)),"=d"(*(where+3)):"a"(code));
1824 return (int)where[0];
1827 static bool has_aes_ni()
1829 uint32_t cpu_info[4];
1831 return cpu_info[2] & (1 << 25);
1834 int main(int argc, char *argv[]) {
1835 struct thr_info *thr;
1839 rpc_user = strdup("");
1840 rpc_pass = strdup("");
1842 /* parse command line */
1843 parse_cmdline(argc, argv);
1845 if (opt_algo == ALGO_QUARK) {
1846 init_quarkhash_contexts();
1847 } else if (opt_algo == ALGO_BLAKE) {
1848 init_blakehash_contexts();
1849 } else if(opt_algo == ALGO_CRYPTONIGHT) {
1851 aes_ni_supported = has_aes_ni();
1852 applog(LOG_INFO, "Using JSON-RPC 2.0");
1853 applog(LOG_INFO, "CPU Supports AES-NI: %s", aes_ni_supported ? "YES" : "NO");
1857 if (!opt_benchmark && !rpc_url) {
1858 fprintf(stderr, "%s: no URL supplied\n", argv[0]);
1859 show_usage_and_exit(1);
1862 if (!rpc_userpass) {
1863 rpc_userpass = malloc(strlen(rpc_user) + strlen(rpc_pass) + 2);
1866 sprintf(rpc_userpass, "%s:%s", rpc_user, rpc_pass);
1869 pthread_mutex_init(&applog_lock, NULL );
1870 pthread_mutex_init(&stats_lock, NULL );
1871 pthread_mutex_init(&g_work_lock, NULL );
1872 pthread_mutex_init(&rpc2_job_lock, NULL );
1873 pthread_mutex_init(&stratum.sock_lock, NULL );
1874 pthread_mutex_init(&stratum.work_lock, NULL );
1876 flags = !opt_benchmark && strncmp(rpc_url, "https:", 6) ?
1877 (CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL) : CURL_GLOBAL_ALL;
1878 if (curl_global_init(flags)) {
1879 applog(LOG_ERR, "CURL initialization failed");
1884 if (opt_background) {
1892 applog(LOG_ERR, "setsid() failed (errno = %d)", errno);
1895 applog(LOG_ERR, "chdir() failed (errno = %d)", errno);
1896 signal(SIGHUP, signal_handler);
1897 signal(SIGINT, signal_handler);
1898 signal(SIGTERM, signal_handler);
1903 SYSTEM_INFO sysinfo;
1904 GetSystemInfo(&sysinfo);
1905 num_processors = sysinfo.dwNumberOfProcessors;
1906 #elif defined(_SC_NPROCESSORS_CONF)
1907 num_processors = sysconf(_SC_NPROCESSORS_CONF);
1908 #elif defined(CTL_HW) && defined(HW_NCPU)
1909 int req[] = {CTL_HW, HW_NCPU};
1910 size_t len = sizeof(num_processors);
1911 sysctl(req, 2, &num_processors, &len, NULL, 0);
1915 if (num_processors < 1)
1918 opt_n_threads = num_processors - 1;
1920 #ifdef HAVE_SYSLOG_H
1922 openlog("cpuminer", LOG_PID, LOG_USER);
1925 work_restart = calloc(opt_n_threads, sizeof(*work_restart));
1929 thr_info = calloc(opt_n_threads + 3, sizeof(*thr));
1933 thr_hashrates = (double *) calloc(opt_n_threads, sizeof(double));
1937 /* init workio thread info */
1938 work_thr_id = opt_n_threads;
1939 thr = &thr_info[work_thr_id];
1940 thr->id = work_thr_id;
1945 /* start work I/O thread */
1946 if (pthread_create(&thr->pth, NULL, workio_thread, thr)) {
1947 applog(LOG_ERR, "workio thread create failed");
1951 if (want_longpoll && !have_stratum) {
1952 /* init longpoll thread info */
1953 longpoll_thr_id = opt_n_threads + 1;
1954 thr = &thr_info[longpoll_thr_id];
1955 thr->id = longpoll_thr_id;
1960 /* start longpoll thread */
1961 if (unlikely(pthread_create(&thr->pth, NULL, longpoll_thread, thr))) {
1962 applog(LOG_ERR, "longpoll thread create failed");
1967 /* init stratum thread info */
1968 stratum_thr_id = opt_n_threads + 2;
1969 thr = &thr_info[stratum_thr_id];
1970 thr->id = stratum_thr_id;
1975 /* start stratum thread */
1976 if (unlikely(pthread_create(&thr->pth, NULL, stratum_thread, thr))) {
1977 applog(LOG_ERR, "stratum thread create failed");
1982 tq_push(thr_info[stratum_thr_id].q, strdup(rpc_url));
1985 /* start mining threads */
1986 for (i = 0; i < opt_n_threads; i++) {
1994 if (unlikely(pthread_create(&thr->pth, NULL, miner_thread, thr))) {
1995 applog(LOG_ERR, "thread %d create failed", i);
2000 applog(LOG_INFO, "%d miner threads started, "
2001 "using '%s' algorithm.", opt_n_threads, algo_names[opt_algo]);
2003 /* main loop - simply wait for workio thread to exit */
2004 pthread_join(thr_info[work_thr_id].pth, NULL );
2006 applog(LOG_INFO, "workio thread dead, exiting.");