cpu-miner.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /*
  2. * Copyright 2010 Jeff Garzik
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the Free
  6. * Software Foundation; either version 2 of the License, or (at your option)
  7. * any later version. See COPYING for more details.
  8. */
  9. #include "cpuminer-config.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <stdbool.h>
  14. #include <stdint.h>
  15. #include <unistd.h>
  16. #include <sys/time.h>
  17. #include <time.h>
  18. #ifndef WIN32
  19. #include <sys/resource.h>
  20. #endif
  21. #include <pthread.h>
  22. #include <getopt.h>
  23. #include <jansson.h>
  24. #include <curl/curl.h>
  25. #include "compat.h"
  26. #include "miner.h"
  27. #define PROGRAM_NAME "minerd"
  28. #define DEF_RPC_URL "http://127.0.0.1:8332/"
  29. #define DEF_RPC_USERPASS "rpcuser:rpcpass"
  30. struct thr_info {
  31. int id;
  32. pthread_t pth;
  33. struct thread_q *q;
  34. };
  35. enum workio_commands {
  36. WC_GET_WORK,
  37. WC_SUBMIT_WORK,
  38. };
  39. struct workio_cmd {
  40. enum workio_commands cmd;
  41. struct thr_info *thr;
  42. union {
  43. struct work *work;
  44. } u;
  45. };
  46. enum sha256_algos {
  47. ALGO_C, /* plain C */
  48. ALGO_4WAY, /* parallel SSE2 */
  49. ALGO_VIA, /* VIA padlock */
  50. ALGO_CRYPTOPP, /* Crypto++ (C) */
  51. ALGO_CRYPTOPP_ASM32, /* Crypto++ 32-bit assembly */
  52. ALGO_SSE2_64, /* SSE2 for x86_64 */
  53. };
  54. static const char *algo_names[] = {
  55. [ALGO_C] = "c",
  56. #ifdef WANT_SSE2_4WAY
  57. [ALGO_4WAY] = "4way",
  58. #endif
  59. #ifdef WANT_VIA_PADLOCK
  60. [ALGO_VIA] = "via",
  61. #endif
  62. [ALGO_CRYPTOPP] = "cryptopp",
  63. #ifdef WANT_CRYPTOPP_ASM32
  64. [ALGO_CRYPTOPP_ASM32] = "cryptopp_asm32",
  65. #endif
  66. #ifdef WANT_X8664_SSE2
  67. [ALGO_SSE2_64] = "sse2_64",
  68. #endif
  69. };
  70. bool opt_debug = false;
  71. bool opt_protocol = false;
  72. static bool opt_quiet = false;
  73. static int opt_retries = 10;
  74. static int opt_fail_pause = 30;
  75. static int opt_scantime = 5;
  76. static json_t *opt_config;
  77. static const bool opt_time = true;
  78. static enum sha256_algos opt_algo = ALGO_C;
  79. static int opt_n_threads = 1;
  80. static char *rpc_url;
  81. static char *userpass;
  82. static struct thr_info *thr_info;
  83. static int work_thr_id;
  84. struct option_help {
  85. const char *name;
  86. const char *helptext;
  87. };
  88. static struct option_help options_help[] = {
  89. { "help",
  90. "(-h) Display this help text" },
  91. { "config FILE",
  92. "(-c FILE) JSON-format configuration file (default: none)\n"
  93. "See example-cfg.json for an example configuration." },
  94. { "algo XXX",
  95. "(-a XXX) Specify sha256 implementation:\n"
  96. "\tc\t\tLinux kernel sha256, implemented in C (default)"
  97. #ifdef WANT_SSE2_4WAY
  98. "\n\t4way\t\ttcatm's 4-way SSE2 implementation"
  99. #endif
  100. #ifdef WANT_VIA_PADLOCK
  101. "\n\tvia\t\tVIA padlock implementation"
  102. #endif
  103. "\n\tcryptopp\tCrypto++ C/C++ implementation"
  104. #ifdef WANT_CRYPTOPP_ASM32
  105. "\n\tcryptopp_asm32\tCrypto++ 32-bit assembler implementation"
  106. #endif
  107. #ifdef WANT_X8664_SSE2
  108. "\n\tsse2_64\t\tSSE2 implementation for x86_64 machines"
  109. #endif
  110. },
  111. { "quiet",
  112. "(-q) Disable per-thread hashmeter output (default: off)" },
  113. { "debug",
  114. "(-D) Enable debug output (default: off)" },
  115. { "protocol-dump",
  116. "(-P) Verbose dump of protocol-level activities (default: off)" },
  117. { "retries N",
  118. "(-r N) Number of times to retry, if JSON-RPC call fails\n"
  119. "\t(default: 10; use -1 for \"never\")" },
  120. { "retry-pause N",
  121. "(-R N) Number of seconds to pause, between retries\n"
  122. "\t(default: 30)" },
  123. { "scantime N",
  124. "(-s N) Upper bound on time spent scanning current work,\n"
  125. "\tin seconds. (default: 5)" },
  126. { "threads N",
  127. "(-t N) Number of miner threads (default: 1)" },
  128. { "url URL",
  129. "URL for bitcoin JSON-RPC server "
  130. "(default: " DEF_RPC_URL ")" },
  131. { "userpass USERNAME:PASSWORD",
  132. "Username:Password pair for bitcoin JSON-RPC server "
  133. "(default: " DEF_RPC_USERPASS ")" },
  134. };
  135. static struct option options[] = {
  136. { "help", 0, NULL, 'h' },
  137. { "algo", 1, NULL, 'a' },
  138. { "config", 1, NULL, 'c' },
  139. { "quiet", 0, NULL, 'q' },
  140. { "debug", 0, NULL, 'D' },
  141. { "protocol-dump", 0, NULL, 'P' },
  142. { "threads", 1, NULL, 't' },
  143. { "retries", 1, NULL, 'r' },
  144. { "retry-pause", 1, NULL, 'R' },
  145. { "scantime", 1, NULL, 's' },
  146. { "url", 1, NULL, 1001 },
  147. { "userpass", 1, NULL, 1002 },
  148. { }
  149. };
  150. struct work {
  151. unsigned char data[128];
  152. unsigned char hash1[64];
  153. unsigned char midstate[32];
  154. unsigned char target[32];
  155. unsigned char hash[32];
  156. };
  157. static bool jobj_binary(const json_t *obj, const char *key,
  158. void *buf, size_t buflen)
  159. {
  160. const char *hexstr;
  161. json_t *tmp;
  162. tmp = json_object_get(obj, key);
  163. if (!tmp) {
  164. fprintf(stderr, "JSON key '%s' not found\n", key);
  165. return false;
  166. }
  167. hexstr = json_string_value(tmp);
  168. if (!hexstr) {
  169. fprintf(stderr, "JSON key '%s' is not a string\n", key);
  170. return false;
  171. }
  172. if (!hex2bin(buf, hexstr, buflen))
  173. return false;
  174. return true;
  175. }
  176. static bool work_decode(const json_t *val, struct work *work)
  177. {
  178. if (!jobj_binary(val, "midstate",
  179. work->midstate, sizeof(work->midstate))) {
  180. fprintf(stderr, "JSON inval midstate\n");
  181. goto err_out;
  182. }
  183. if (!jobj_binary(val, "data", work->data, sizeof(work->data))) {
  184. fprintf(stderr, "JSON inval data\n");
  185. goto err_out;
  186. }
  187. if (!jobj_binary(val, "hash1", work->hash1, sizeof(work->hash1))) {
  188. fprintf(stderr, "JSON inval hash1\n");
  189. goto err_out;
  190. }
  191. if (!jobj_binary(val, "target", work->target, sizeof(work->target))) {
  192. fprintf(stderr, "JSON inval target\n");
  193. goto err_out;
  194. }
  195. memset(work->hash, 0, sizeof(work->hash));
  196. return true;
  197. err_out:
  198. return false;
  199. }
  200. static bool submit_upstream_work(CURL *curl, const struct work *work)
  201. {
  202. char *hexstr = NULL;
  203. json_t *val, *res;
  204. char s[345], timestr[64];
  205. time_t now;
  206. struct tm *tm;
  207. bool rc = false;
  208. now = time(NULL);
  209. /* build hex string */
  210. hexstr = bin2hex(work->data, sizeof(work->data));
  211. if (!hexstr) {
  212. fprintf(stderr, "submit_upstream_work OOM\n");
  213. goto out;
  214. }
  215. /* build JSON-RPC request */
  216. sprintf(s,
  217. "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n",
  218. hexstr);
  219. if (opt_debug)
  220. fprintf(stderr, "DBG: sending RPC call:\n%s", s);
  221. /* issue JSON-RPC request */
  222. val = json_rpc_call(curl, rpc_url, userpass, s);
  223. if (!val) {
  224. fprintf(stderr, "submit_upstream_work json_rpc_call failed\n");
  225. goto out;
  226. }
  227. res = json_object_get(val, "result");
  228. tm = localtime(&now);
  229. strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tm);
  230. printf("[%s] PROOF OF WORK RESULT: %s\n",
  231. timestr, json_is_true(res) ? "true (yay!!!)" : "false (booooo)");
  232. json_decref(val);
  233. rc = true;
  234. out:
  235. free(hexstr);
  236. return rc;
  237. }
  238. static bool get_upstream_work(CURL *curl, struct work *work)
  239. {
  240. static const char *rpc_req =
  241. "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
  242. json_t *val;
  243. bool rc;
  244. val = json_rpc_call(curl, rpc_url, userpass, rpc_req);
  245. if (!val)
  246. return false;
  247. rc = work_decode(json_object_get(val, "result"), work);
  248. json_decref(val);
  249. return rc;
  250. }
  251. static void workio_cmd_free(struct workio_cmd *wc)
  252. {
  253. if (!wc)
  254. return;
  255. switch (wc->cmd) {
  256. case WC_SUBMIT_WORK:
  257. free(wc->u.work);
  258. break;
  259. default: /* do nothing */
  260. break;
  261. }
  262. memset(wc, 0, sizeof(*wc)); /* poison */
  263. free(wc);
  264. }
  265. static bool workio_get_work(struct workio_cmd *wc, CURL *curl)
  266. {
  267. struct work *ret_work;
  268. int failures = 0;
  269. ret_work = calloc(1, sizeof(*ret_work));
  270. if (!ret_work)
  271. return false;
  272. /* obtain new work from bitcoin via JSON-RPC */
  273. while (!get_upstream_work(curl, ret_work)) {
  274. fprintf(stderr, "json_rpc_call failed, ");
  275. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  276. fprintf(stderr, "terminating workio thread\n");
  277. free(ret_work);
  278. return false;
  279. }
  280. /* pause, then restart work-request loop */
  281. fprintf(stderr, "retry after %d seconds\n",
  282. opt_fail_pause);
  283. sleep(opt_fail_pause);
  284. }
  285. /* send work to requesting thread */
  286. if (!tq_push(wc->thr->q, ret_work))
  287. free(ret_work);
  288. return true;
  289. }
  290. static bool workio_submit_work(struct workio_cmd *wc, CURL *curl)
  291. {
  292. int failures = 0;
  293. /* submit solution to bitcoin via JSON-RPC */
  294. while (!submit_upstream_work(curl, wc->u.work)) {
  295. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  296. fprintf(stderr, "...terminating workio thread\n");
  297. return false;
  298. }
  299. /* pause, then restart work-request loop */
  300. fprintf(stderr, "...retry after %d seconds\n",
  301. opt_fail_pause);
  302. sleep(opt_fail_pause);
  303. }
  304. return true;
  305. }
  306. static void *workio_thread(void *userdata)
  307. {
  308. struct thr_info *mythr = userdata;
  309. CURL *curl;
  310. bool ok = true;
  311. curl = curl_easy_init();
  312. if (!curl) {
  313. fprintf(stderr, "CURL initialization failed\n");
  314. return NULL;
  315. }
  316. while (ok) {
  317. struct workio_cmd *wc;
  318. /* wait for workio_cmd sent to us, on our queue */
  319. wc = tq_pop(mythr->q, NULL);
  320. if (!wc) {
  321. ok = false;
  322. break;
  323. }
  324. /* process workio_cmd */
  325. switch (wc->cmd) {
  326. case WC_GET_WORK:
  327. ok = workio_get_work(wc, curl);
  328. break;
  329. case WC_SUBMIT_WORK:
  330. ok = workio_submit_work(wc, curl);
  331. break;
  332. default: /* should never happen */
  333. ok = false;
  334. break;
  335. }
  336. workio_cmd_free(wc);
  337. }
  338. tq_freeze(mythr->q);
  339. curl_easy_cleanup(curl);
  340. return NULL;
  341. }
  342. static void hashmeter(int thr_id, const struct timeval *diff,
  343. unsigned long hashes_done)
  344. {
  345. double khashes, secs;
  346. khashes = hashes_done / 1000.0;
  347. secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0);
  348. if (!opt_quiet)
  349. printf("HashMeter(%d): %lu hashes, %.2f khash/sec\n",
  350. thr_id, hashes_done,
  351. khashes / secs);
  352. }
  353. static bool get_work(struct thr_info *thr, struct work *work)
  354. {
  355. struct workio_cmd *wc;
  356. struct work *work_heap;
  357. /* fill out work request message */
  358. wc = calloc(1, sizeof(*wc));
  359. if (!wc)
  360. return false;
  361. wc->cmd = WC_GET_WORK;
  362. wc->thr = thr;
  363. /* send work request to workio thread */
  364. if (!tq_push(thr_info[work_thr_id].q, wc)) {
  365. workio_cmd_free(wc);
  366. return false;
  367. }
  368. /* wait for response, a unit of work */
  369. work_heap = tq_pop(thr->q, NULL);
  370. if (!work_heap)
  371. return false;
  372. /* copy returned work into storage provided by caller */
  373. memcpy(work, work_heap, sizeof(*work));
  374. free(work_heap);
  375. return true;
  376. }
  377. static bool submit_work(struct thr_info *thr, const struct work *work_in)
  378. {
  379. struct workio_cmd *wc;
  380. /* fill out work request message */
  381. wc = calloc(1, sizeof(*wc));
  382. if (!wc)
  383. return false;
  384. wc->u.work = malloc(sizeof(*work_in));
  385. if (!wc->u.work)
  386. goto err_out;
  387. wc->cmd = WC_SUBMIT_WORK;
  388. wc->thr = thr;
  389. memcpy(wc->u.work, work_in, sizeof(*work_in));
  390. /* send solution to workio thread */
  391. if (!tq_push(thr_info[work_thr_id].q, wc))
  392. goto err_out;
  393. return true;
  394. err_out:
  395. workio_cmd_free(wc);
  396. return false;
  397. }
  398. static void *miner_thread(void *userdata)
  399. {
  400. struct thr_info *mythr = userdata;
  401. int thr_id = mythr->id;
  402. uint32_t max_nonce = 0xffffff;
  403. while (1) {
  404. struct work work __attribute__((aligned(128)));
  405. unsigned long hashes_done;
  406. struct timeval tv_start, tv_end, diff;
  407. bool rc;
  408. /* obtain new work from internal workio thread */
  409. if (!get_work(mythr, &work)) {
  410. fprintf(stderr, "work retrieval failed, exiting "
  411. "mining thread %d\n", mythr->id);
  412. goto out;
  413. }
  414. hashes_done = 0;
  415. gettimeofday(&tv_start, NULL);
  416. /* scan nonces for a proof-of-work hash */
  417. switch (opt_algo) {
  418. case ALGO_C:
  419. rc = scanhash_c(work.midstate, work.data + 64,
  420. work.hash1, work.hash, work.target,
  421. max_nonce, &hashes_done);
  422. break;
  423. #ifdef WANT_X8664_SSE2
  424. case ALGO_SSE2_64: {
  425. unsigned int rc5 =
  426. scanhash_sse2_64(work.midstate, work.data + 64,
  427. work.hash1, work.hash,
  428. work.target,
  429. max_nonce, &hashes_done);
  430. rc = (rc5 == -1) ? false : true;
  431. }
  432. break;
  433. #endif
  434. #ifdef WANT_SSE2_4WAY
  435. case ALGO_4WAY: {
  436. unsigned int rc4 =
  437. ScanHash_4WaySSE2(work.midstate, work.data + 64,
  438. work.hash1, work.hash,
  439. work.target,
  440. max_nonce, &hashes_done);
  441. rc = (rc4 == -1) ? false : true;
  442. }
  443. break;
  444. #endif
  445. #ifdef WANT_VIA_PADLOCK
  446. case ALGO_VIA:
  447. rc = scanhash_via(work.data, work.target,
  448. max_nonce, &hashes_done);
  449. break;
  450. #endif
  451. case ALGO_CRYPTOPP:
  452. rc = scanhash_cryptopp(work.midstate, work.data + 64,
  453. work.hash1, work.hash, work.target,
  454. max_nonce, &hashes_done);
  455. break;
  456. #ifdef WANT_CRYPTOPP_ASM32
  457. case ALGO_CRYPTOPP_ASM32:
  458. rc = scanhash_asm32(work.midstate, work.data + 64,
  459. work.hash1, work.hash, work.target,
  460. max_nonce, &hashes_done);
  461. break;
  462. #endif
  463. default:
  464. /* should never happen */
  465. goto out;
  466. }
  467. /* record scanhash elapsed time */
  468. gettimeofday(&tv_end, NULL);
  469. timeval_subtract(&diff, &tv_end, &tv_start);
  470. hashmeter(thr_id, &diff, hashes_done);
  471. /* adjust max_nonce to meet target scan time */
  472. if (diff.tv_sec > (opt_scantime * 2))
  473. max_nonce /= 2; /* large decrease */
  474. else if ((diff.tv_sec > opt_scantime) &&
  475. (max_nonce > 1500000))
  476. max_nonce -= 1000000; /* small decrease */
  477. else if ((diff.tv_sec < opt_scantime) &&
  478. (max_nonce < 0xffffec76))
  479. max_nonce += 100000; /* small increase */
  480. /* if nonce found, submit work */
  481. if (rc && !submit_work(mythr, &work))
  482. break;
  483. }
  484. out:
  485. tq_freeze(mythr->q);
  486. return NULL;
  487. }
  488. static void show_usage(void)
  489. {
  490. int i;
  491. printf("minerd version %s\n\n", VERSION);
  492. printf("Usage:\tminerd [options]\n\nSupported options:\n");
  493. for (i = 0; i < ARRAY_SIZE(options_help); i++) {
  494. struct option_help *h;
  495. h = &options_help[i];
  496. printf("--%s\n%s\n\n", h->name, h->helptext);
  497. }
  498. exit(1);
  499. }
  500. static void parse_arg (int key, char *arg)
  501. {
  502. int v, i;
  503. switch(key) {
  504. case 'a':
  505. for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
  506. if (algo_names[i] &&
  507. !strcmp(arg, algo_names[i])) {
  508. opt_algo = i;
  509. break;
  510. }
  511. }
  512. if (i == ARRAY_SIZE(algo_names))
  513. show_usage();
  514. break;
  515. case 'c': {
  516. json_error_t err;
  517. if (opt_config)
  518. json_decref(opt_config);
  519. opt_config = json_load_file(arg, &err);
  520. if (!json_is_object(opt_config)) {
  521. fprintf(stderr, "JSON decode of %s failed\n", arg);
  522. show_usage();
  523. }
  524. break;
  525. }
  526. case 'q':
  527. opt_quiet = true;
  528. break;
  529. case 'D':
  530. opt_debug = true;
  531. break;
  532. case 'P':
  533. opt_protocol = true;
  534. break;
  535. case 'r':
  536. v = atoi(arg);
  537. if (v < -1 || v > 9999) /* sanity check */
  538. show_usage();
  539. opt_retries = v;
  540. break;
  541. case 'R':
  542. v = atoi(arg);
  543. if (v < 1 || v > 9999) /* sanity check */
  544. show_usage();
  545. opt_fail_pause = v;
  546. break;
  547. case 's':
  548. v = atoi(arg);
  549. if (v < 1 || v > 9999) /* sanity check */
  550. show_usage();
  551. opt_scantime = v;
  552. break;
  553. case 't':
  554. v = atoi(arg);
  555. if (v < 1 || v > 9999) /* sanity check */
  556. show_usage();
  557. opt_n_threads = v;
  558. break;
  559. case 1001: /* --url */
  560. if (strncmp(arg, "http://", 7) &&
  561. strncmp(arg, "https://", 8))
  562. show_usage();
  563. free(rpc_url);
  564. rpc_url = strdup(arg);
  565. break;
  566. case 1002: /* --userpass */
  567. if (!strchr(arg, ':'))
  568. show_usage();
  569. free(userpass);
  570. userpass = strdup(arg);
  571. break;
  572. default:
  573. show_usage();
  574. }
  575. }
  576. static void parse_config(void)
  577. {
  578. int i;
  579. json_t *val;
  580. if (!json_is_object(opt_config))
  581. return;
  582. for (i = 0; i < ARRAY_SIZE(options); i++) {
  583. if (!options[i].name)
  584. break;
  585. if (!strcmp(options[i].name, "config"))
  586. continue;
  587. val = json_object_get(opt_config, options[i].name);
  588. if (!val)
  589. continue;
  590. if (options[i].has_arg && json_is_string(val)) {
  591. char *s = strdup(json_string_value(val));
  592. if (!s)
  593. break;
  594. parse_arg(options[i].val, s);
  595. free(s);
  596. } else if (!options[i].has_arg && json_is_true(val))
  597. parse_arg(options[i].val, "");
  598. else
  599. fprintf(stderr, "JSON option %s invalid\n",
  600. options[i].name);
  601. }
  602. }
  603. static void parse_cmdline(int argc, char *argv[])
  604. {
  605. int key;
  606. while (1) {
  607. key = getopt_long(argc, argv, "a:c:qDPr:s:t:h?", options, NULL);
  608. if (key < 0)
  609. break;
  610. parse_arg(key, optarg);
  611. }
  612. parse_config();
  613. }
  614. int main (int argc, char *argv[])
  615. {
  616. struct thr_info *thr;
  617. int i;
  618. rpc_url = strdup(DEF_RPC_URL);
  619. userpass = strdup(DEF_RPC_USERPASS);
  620. /* parse command line */
  621. parse_cmdline(argc, argv);
  622. /* set our priority to the highest (aka "nicest, least intrusive") */
  623. if (setpriority(PRIO_PROCESS, 0, 19))
  624. perror("setpriority");
  625. thr_info = calloc(opt_n_threads + 1, sizeof(*thr));
  626. if (!thr_info)
  627. return 1;
  628. work_thr_id = opt_n_threads;
  629. thr = &thr_info[work_thr_id];
  630. thr->id = opt_n_threads;
  631. thr->q = tq_new();
  632. if (!thr->q)
  633. return 1;
  634. /* start work I/O thread */
  635. if (pthread_create(&thr->pth, NULL, workio_thread, thr)) {
  636. fprintf(stderr, "workio thread create failed\n");
  637. return 1;
  638. }
  639. /* start mining threads */
  640. for (i = 0; i < opt_n_threads; i++) {
  641. thr = &thr_info[i];
  642. thr->id = i;
  643. thr->q = tq_new();
  644. if (!thr->q)
  645. return 1;
  646. if (pthread_create(&thr->pth, NULL, miner_thread, thr)) {
  647. fprintf(stderr, "thread %d create failed\n", i);
  648. return 1;
  649. }
  650. sleep(1); /* don't pound RPC server all at once */
  651. }
  652. fprintf(stderr, "%d miner threads started, "
  653. "using SHA256 '%s' algorithm.\n",
  654. opt_n_threads,
  655. algo_names[opt_algo]);
  656. /* main loop - simply wait for workio thread to exit */
  657. pthread_join(thr_info[work_thr_id].pth, NULL);
  658. fprintf(stderr, "workio thread dead, exiting.\n");
  659. return 0;
  660. }