cpu-miner.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  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 <getopt.h>
  22. #include <jansson.h>
  23. #include <curl/curl.h>
  24. #include "compat.h"
  25. #include "miner.h"
  26. #define PROGRAM_NAME "minerd"
  27. #define DEF_RPC_URL "http://127.0.0.1:8332/"
  28. #define DEF_RPC_USERPASS "rpcuser:rpcpass"
  29. enum workio_commands {
  30. WC_GET_WORK,
  31. WC_SUBMIT_WORK,
  32. };
  33. struct workio_cmd {
  34. enum workio_commands cmd;
  35. struct thr_info *thr;
  36. union {
  37. struct work *work;
  38. } u;
  39. };
  40. enum sha256_algos {
  41. ALGO_C, /* plain C */
  42. ALGO_4WAY, /* parallel SSE2 */
  43. ALGO_VIA, /* VIA padlock */
  44. ALGO_CRYPTOPP, /* Crypto++ (C) */
  45. ALGO_CRYPTOPP_ASM32, /* Crypto++ 32-bit assembly */
  46. ALGO_SSE2_64, /* SSE2 for x86_64 */
  47. };
  48. static const char *algo_names[] = {
  49. [ALGO_C] = "c",
  50. #ifdef WANT_SSE2_4WAY
  51. [ALGO_4WAY] = "4way",
  52. #endif
  53. #ifdef WANT_VIA_PADLOCK
  54. [ALGO_VIA] = "via",
  55. #endif
  56. [ALGO_CRYPTOPP] = "cryptopp",
  57. #ifdef WANT_CRYPTOPP_ASM32
  58. [ALGO_CRYPTOPP_ASM32] = "cryptopp_asm32",
  59. #endif
  60. #ifdef WANT_X8664_SSE2
  61. [ALGO_SSE2_64] = "sse2_64",
  62. #endif
  63. };
  64. bool opt_debug = false;
  65. bool opt_protocol = false;
  66. bool want_longpoll = true;
  67. bool have_longpoll = false;
  68. bool use_syslog = false;
  69. static bool opt_quiet = false;
  70. static int opt_retries = 10;
  71. static int opt_fail_pause = 30;
  72. int opt_scantime = 5;
  73. static json_t *opt_config;
  74. static const bool opt_time = true;
  75. static enum sha256_algos opt_algo = ALGO_C;
  76. static int opt_n_threads = 1;
  77. static char *rpc_url;
  78. static char *userpass;
  79. struct thr_info *thr_info;
  80. static int work_thr_id;
  81. int longpoll_thr_id;
  82. struct work_restart *work_restart = NULL;
  83. pthread_mutex_t time_lock;
  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. { "no-longpoll",
  116. "Disable X-Long-Polling support (default: enabled)" },
  117. { "protocol-dump",
  118. "(-P) Verbose dump of protocol-level activities (default: off)" },
  119. { "retries N",
  120. "(-r N) Number of times to retry, if JSON-RPC call fails\n"
  121. "\t(default: 10; use -1 for \"never\")" },
  122. { "retry-pause N",
  123. "(-R N) Number of seconds to pause, between retries\n"
  124. "\t(default: 30)" },
  125. { "scantime N",
  126. "(-s N) Upper bound on time spent scanning current work,\n"
  127. "\tin seconds. (default: 5)" },
  128. #ifdef HAVE_SYSLOG_H
  129. { "syslog",
  130. "Use system log for output messages (default: standard error)" },
  131. #endif
  132. { "threads N",
  133. "(-t N) Number of miner threads (default: 1)" },
  134. { "url URL",
  135. "URL for bitcoin JSON-RPC server "
  136. "(default: " DEF_RPC_URL ")" },
  137. { "userpass USERNAME:PASSWORD",
  138. "Username:Password pair for bitcoin JSON-RPC server "
  139. "(default: " DEF_RPC_USERPASS ")" },
  140. };
  141. static struct option options[] = {
  142. { "help", 0, NULL, 'h' },
  143. { "algo", 1, NULL, 'a' },
  144. { "config", 1, NULL, 'c' },
  145. { "quiet", 0, NULL, 'q' },
  146. { "debug", 0, NULL, 'D' },
  147. { "protocol-dump", 0, NULL, 'P' },
  148. { "threads", 1, NULL, 't' },
  149. { "retries", 1, NULL, 'r' },
  150. { "retry-pause", 1, NULL, 'R' },
  151. { "scantime", 1, NULL, 's' },
  152. { "url", 1, NULL, 1001 },
  153. { "userpass", 1, NULL, 1002 },
  154. { "no-longpoll", 0, NULL, 1003 },
  155. #ifdef HAVE_SYSLOG_H
  156. { "syslog", 0, NULL, 1004 },
  157. #endif
  158. { }
  159. };
  160. struct work {
  161. unsigned char data[128];
  162. unsigned char hash1[64];
  163. unsigned char midstate[32];
  164. unsigned char target[32];
  165. unsigned char hash[32];
  166. };
  167. static bool jobj_binary(const json_t *obj, const char *key,
  168. void *buf, size_t buflen)
  169. {
  170. const char *hexstr;
  171. json_t *tmp;
  172. tmp = json_object_get(obj, key);
  173. if (!tmp) {
  174. fprintf(stderr, "JSON key '%s' not found\n", key);
  175. return false;
  176. }
  177. hexstr = json_string_value(tmp);
  178. if (!hexstr) {
  179. fprintf(stderr, "JSON key '%s' is not a string\n", key);
  180. return false;
  181. }
  182. if (!hex2bin(buf, hexstr, buflen))
  183. return false;
  184. return true;
  185. }
  186. static bool work_decode(const json_t *val, struct work *work)
  187. {
  188. if (!jobj_binary(val, "midstate",
  189. work->midstate, sizeof(work->midstate))) {
  190. fprintf(stderr, "JSON inval midstate\n");
  191. goto err_out;
  192. }
  193. if (!jobj_binary(val, "data", work->data, sizeof(work->data))) {
  194. fprintf(stderr, "JSON inval data\n");
  195. goto err_out;
  196. }
  197. if (!jobj_binary(val, "hash1", work->hash1, sizeof(work->hash1))) {
  198. fprintf(stderr, "JSON inval hash1\n");
  199. goto err_out;
  200. }
  201. if (!jobj_binary(val, "target", work->target, sizeof(work->target))) {
  202. fprintf(stderr, "JSON inval target\n");
  203. goto err_out;
  204. }
  205. memset(work->hash, 0, sizeof(work->hash));
  206. return true;
  207. err_out:
  208. return false;
  209. }
  210. static bool submit_upstream_work(CURL *curl, const struct work *work)
  211. {
  212. char *hexstr = NULL;
  213. json_t *val, *res;
  214. char s[345];
  215. bool rc = false;
  216. /* build hex string */
  217. hexstr = bin2hex(work->data, sizeof(work->data));
  218. if (!hexstr) {
  219. fprintf(stderr, "submit_upstream_work OOM\n");
  220. goto out;
  221. }
  222. /* build JSON-RPC request */
  223. sprintf(s,
  224. "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n",
  225. hexstr);
  226. if (opt_debug)
  227. fprintf(stderr, "DBG: sending RPC call:\n%s", s);
  228. /* issue JSON-RPC request */
  229. val = json_rpc_call(curl, rpc_url, userpass, s, false, false);
  230. if (!val) {
  231. fprintf(stderr, "submit_upstream_work json_rpc_call failed\n");
  232. goto out;
  233. }
  234. res = json_object_get(val, "result");
  235. applog(LOG_INFO, "PROOF OF WORK RESULT: %s",
  236. json_is_true(res) ? "true (yay!!!)" : "false (booooo)");
  237. json_decref(val);
  238. rc = true;
  239. out:
  240. free(hexstr);
  241. return rc;
  242. }
  243. static const char *rpc_req =
  244. "{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
  245. static bool get_upstream_work(CURL *curl, struct work *work)
  246. {
  247. json_t *val;
  248. bool rc;
  249. val = json_rpc_call(curl, rpc_url, userpass, rpc_req,
  250. want_longpoll, false);
  251. if (!val)
  252. return false;
  253. rc = work_decode(json_object_get(val, "result"), work);
  254. json_decref(val);
  255. return rc;
  256. }
  257. static void workio_cmd_free(struct workio_cmd *wc)
  258. {
  259. if (!wc)
  260. return;
  261. switch (wc->cmd) {
  262. case WC_SUBMIT_WORK:
  263. free(wc->u.work);
  264. break;
  265. default: /* do nothing */
  266. break;
  267. }
  268. memset(wc, 0, sizeof(*wc)); /* poison */
  269. free(wc);
  270. }
  271. static bool workio_get_work(struct workio_cmd *wc, CURL *curl)
  272. {
  273. struct work *ret_work;
  274. int failures = 0;
  275. ret_work = calloc(1, sizeof(*ret_work));
  276. if (!ret_work)
  277. return false;
  278. /* obtain new work from bitcoin via JSON-RPC */
  279. while (!get_upstream_work(curl, ret_work)) {
  280. fprintf(stderr, "json_rpc_call failed, ");
  281. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  282. fprintf(stderr, "terminating workio thread\n");
  283. free(ret_work);
  284. return false;
  285. }
  286. /* pause, then restart work-request loop */
  287. fprintf(stderr, "retry after %d seconds\n",
  288. opt_fail_pause);
  289. sleep(opt_fail_pause);
  290. }
  291. /* send work to requesting thread */
  292. if (!tq_push(wc->thr->q, ret_work))
  293. free(ret_work);
  294. return true;
  295. }
  296. static bool workio_submit_work(struct workio_cmd *wc, CURL *curl)
  297. {
  298. int failures = 0;
  299. /* submit solution to bitcoin via JSON-RPC */
  300. while (!submit_upstream_work(curl, wc->u.work)) {
  301. if ((opt_retries >= 0) && (++failures > opt_retries)) {
  302. fprintf(stderr, "...terminating workio thread\n");
  303. return false;
  304. }
  305. /* pause, then restart work-request loop */
  306. fprintf(stderr, "...retry after %d seconds\n",
  307. opt_fail_pause);
  308. sleep(opt_fail_pause);
  309. }
  310. return true;
  311. }
  312. static void *workio_thread(void *userdata)
  313. {
  314. struct thr_info *mythr = userdata;
  315. CURL *curl;
  316. bool ok = true;
  317. curl = curl_easy_init();
  318. if (!curl) {
  319. fprintf(stderr, "CURL initialization failed\n");
  320. return NULL;
  321. }
  322. while (ok) {
  323. struct workio_cmd *wc;
  324. /* wait for workio_cmd sent to us, on our queue */
  325. wc = tq_pop(mythr->q, NULL);
  326. if (!wc) {
  327. ok = false;
  328. break;
  329. }
  330. /* process workio_cmd */
  331. switch (wc->cmd) {
  332. case WC_GET_WORK:
  333. ok = workio_get_work(wc, curl);
  334. break;
  335. case WC_SUBMIT_WORK:
  336. ok = workio_submit_work(wc, curl);
  337. break;
  338. default: /* should never happen */
  339. ok = false;
  340. break;
  341. }
  342. workio_cmd_free(wc);
  343. }
  344. tq_freeze(mythr->q);
  345. curl_easy_cleanup(curl);
  346. return NULL;
  347. }
  348. static void hashmeter(int thr_id, const struct timeval *diff,
  349. unsigned long hashes_done)
  350. {
  351. double khashes, secs;
  352. khashes = hashes_done / 1000.0;
  353. secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0);
  354. if (!opt_quiet)
  355. applog(LOG_INFO, "thread %d: %lu hashes, %.2f khash/sec\n",
  356. thr_id, hashes_done,
  357. khashes / secs);
  358. }
  359. static bool get_work(struct thr_info *thr, struct work *work)
  360. {
  361. struct workio_cmd *wc;
  362. struct work *work_heap;
  363. /* fill out work request message */
  364. wc = calloc(1, sizeof(*wc));
  365. if (!wc)
  366. return false;
  367. wc->cmd = WC_GET_WORK;
  368. wc->thr = thr;
  369. /* send work request to workio thread */
  370. if (!tq_push(thr_info[work_thr_id].q, wc)) {
  371. workio_cmd_free(wc);
  372. return false;
  373. }
  374. /* wait for response, a unit of work */
  375. work_heap = tq_pop(thr->q, NULL);
  376. if (!work_heap)
  377. return false;
  378. /* copy returned work into storage provided by caller */
  379. memcpy(work, work_heap, sizeof(*work));
  380. free(work_heap);
  381. return true;
  382. }
  383. static bool submit_work(struct thr_info *thr, const struct work *work_in)
  384. {
  385. struct workio_cmd *wc;
  386. /* fill out work request message */
  387. wc = calloc(1, sizeof(*wc));
  388. if (!wc)
  389. return false;
  390. wc->u.work = malloc(sizeof(*work_in));
  391. if (!wc->u.work)
  392. goto err_out;
  393. wc->cmd = WC_SUBMIT_WORK;
  394. wc->thr = thr;
  395. memcpy(wc->u.work, work_in, sizeof(*work_in));
  396. /* send solution to workio thread */
  397. if (!tq_push(thr_info[work_thr_id].q, wc))
  398. goto err_out;
  399. return true;
  400. err_out:
  401. workio_cmd_free(wc);
  402. return false;
  403. }
  404. static void *miner_thread(void *userdata)
  405. {
  406. struct thr_info *mythr = userdata;
  407. int thr_id = mythr->id;
  408. uint32_t max_nonce = 0xffffff;
  409. while (1) {
  410. struct work work __attribute__((aligned(128)));
  411. unsigned long hashes_done;
  412. struct timeval tv_start, tv_end, diff;
  413. uint64_t max64;
  414. bool rc;
  415. /* obtain new work from internal workio thread */
  416. if (!get_work(mythr, &work)) {
  417. fprintf(stderr, "work retrieval failed, exiting "
  418. "mining thread %d\n", mythr->id);
  419. goto out;
  420. }
  421. hashes_done = 0;
  422. gettimeofday(&tv_start, NULL);
  423. /* scan nonces for a proof-of-work hash */
  424. switch (opt_algo) {
  425. case ALGO_C:
  426. rc = scanhash_c(thr_id, work.midstate, work.data + 64,
  427. work.hash1, work.hash, work.target,
  428. max_nonce, &hashes_done);
  429. break;
  430. #ifdef WANT_X8664_SSE2
  431. case ALGO_SSE2_64: {
  432. unsigned int rc5 =
  433. scanhash_sse2_64(thr_id, work.midstate, work.data + 64,
  434. work.hash1, work.hash,
  435. work.target,
  436. max_nonce, &hashes_done);
  437. rc = (rc5 == -1) ? false : true;
  438. }
  439. break;
  440. #endif
  441. #ifdef WANT_SSE2_4WAY
  442. case ALGO_4WAY: {
  443. unsigned int rc4 =
  444. ScanHash_4WaySSE2(thr_id, work.midstate, work.data + 64,
  445. work.hash1, work.hash,
  446. work.target,
  447. max_nonce, &hashes_done);
  448. rc = (rc4 == -1) ? false : true;
  449. }
  450. break;
  451. #endif
  452. #ifdef WANT_VIA_PADLOCK
  453. case ALGO_VIA:
  454. rc = scanhash_via(thr_id, work.data, work.target,
  455. max_nonce, &hashes_done);
  456. break;
  457. #endif
  458. case ALGO_CRYPTOPP:
  459. rc = scanhash_cryptopp(thr_id, work.midstate, work.data + 64,
  460. work.hash1, work.hash, work.target,
  461. max_nonce, &hashes_done);
  462. break;
  463. #ifdef WANT_CRYPTOPP_ASM32
  464. case ALGO_CRYPTOPP_ASM32:
  465. rc = scanhash_asm32(thr_id, work.midstate, work.data + 64,
  466. work.hash1, work.hash, work.target,
  467. max_nonce, &hashes_done);
  468. break;
  469. #endif
  470. default:
  471. /* should never happen */
  472. goto out;
  473. }
  474. /* record scanhash elapsed time */
  475. gettimeofday(&tv_end, NULL);
  476. timeval_subtract(&diff, &tv_end, &tv_start);
  477. hashmeter(thr_id, &diff, hashes_done);
  478. /* adjust max_nonce to meet target scan time */
  479. max64 = ((uint64_t)hashes_done * opt_scantime) / diff.tv_sec;
  480. if (max64 > 0xfffffffaULL)
  481. max64 = 0xfffffffaULL;
  482. max_nonce = max64;
  483. /* if nonce found, submit work */
  484. if (rc && !submit_work(mythr, &work))
  485. break;
  486. }
  487. out:
  488. tq_freeze(mythr->q);
  489. return NULL;
  490. }
  491. static void restart_threads(void)
  492. {
  493. int i;
  494. for (i = 0; i < opt_n_threads; i++)
  495. work_restart[i].restart = 1;
  496. }
  497. static void *longpoll_thread(void *userdata)
  498. {
  499. struct thr_info *mythr = userdata;
  500. CURL *curl = NULL;
  501. char *copy_start, *hdr_path, *lp_url = NULL;
  502. bool need_slash = false;
  503. int failures = 0;
  504. hdr_path = tq_pop(mythr->q, NULL);
  505. if (!hdr_path)
  506. goto out;
  507. copy_start = (*hdr_path == '/') ? (hdr_path + 1) : hdr_path;
  508. if (rpc_url[strlen(rpc_url) - 1] != '/')
  509. need_slash = true;
  510. lp_url = malloc(strlen(rpc_url) + strlen(copy_start) + 2);
  511. if (!lp_url)
  512. goto out;
  513. sprintf(lp_url, "%s%s%s", rpc_url, need_slash ? "/" : "", copy_start);
  514. applog(LOG_INFO, "Long-polling activated for %s", lp_url);
  515. curl = curl_easy_init();
  516. if (!curl) {
  517. fprintf(stderr, "CURL initialization failed\n");
  518. goto out;
  519. }
  520. while (1) {
  521. json_t *val;
  522. val = json_rpc_call(curl, lp_url, userpass, rpc_req,
  523. false, true);
  524. if (val) {
  525. failures = 0;
  526. json_decref(val);
  527. applog(LOG_INFO, "LONGPOLL detected new block");
  528. restart_threads();
  529. } else {
  530. if (failures++ < 10) {
  531. sleep(30);
  532. fprintf(stderr,
  533. "longpoll failed, sleeping for 30s\n");
  534. } else {
  535. fprintf(stderr,
  536. "longpoll failed, ending thread\n");
  537. goto out;
  538. }
  539. }
  540. }
  541. out:
  542. free(hdr_path);
  543. free(lp_url);
  544. tq_freeze(mythr->q);
  545. if (curl)
  546. curl_easy_cleanup(curl);
  547. return NULL;
  548. }
  549. static void show_usage(void)
  550. {
  551. int i;
  552. printf("minerd version %s\n\n", VERSION);
  553. printf("Usage:\tminerd [options]\n\nSupported options:\n");
  554. for (i = 0; i < ARRAY_SIZE(options_help); i++) {
  555. struct option_help *h;
  556. h = &options_help[i];
  557. printf("--%s\n%s\n\n", h->name, h->helptext);
  558. }
  559. exit(1);
  560. }
  561. static void parse_arg (int key, char *arg)
  562. {
  563. int v, i;
  564. switch(key) {
  565. case 'a':
  566. for (i = 0; i < ARRAY_SIZE(algo_names); i++) {
  567. if (algo_names[i] &&
  568. !strcmp(arg, algo_names[i])) {
  569. opt_algo = i;
  570. break;
  571. }
  572. }
  573. if (i == ARRAY_SIZE(algo_names))
  574. show_usage();
  575. break;
  576. case 'c': {
  577. json_error_t err;
  578. if (opt_config)
  579. json_decref(opt_config);
  580. opt_config = json_load_file(arg, &err);
  581. if (!json_is_object(opt_config)) {
  582. fprintf(stderr, "JSON decode of %s failed\n", arg);
  583. show_usage();
  584. }
  585. break;
  586. }
  587. case 'q':
  588. opt_quiet = true;
  589. break;
  590. case 'D':
  591. opt_debug = true;
  592. break;
  593. case 'P':
  594. opt_protocol = true;
  595. break;
  596. case 'r':
  597. v = atoi(arg);
  598. if (v < -1 || v > 9999) /* sanity check */
  599. show_usage();
  600. opt_retries = v;
  601. break;
  602. case 'R':
  603. v = atoi(arg);
  604. if (v < 1 || v > 9999) /* sanity check */
  605. show_usage();
  606. opt_fail_pause = v;
  607. break;
  608. case 's':
  609. v = atoi(arg);
  610. if (v < 1 || v > 9999) /* sanity check */
  611. show_usage();
  612. opt_scantime = v;
  613. break;
  614. case 't':
  615. v = atoi(arg);
  616. if (v < 1 || v > 9999) /* sanity check */
  617. show_usage();
  618. opt_n_threads = v;
  619. break;
  620. case 1001: /* --url */
  621. if (strncmp(arg, "http://", 7) &&
  622. strncmp(arg, "https://", 8))
  623. show_usage();
  624. free(rpc_url);
  625. rpc_url = strdup(arg);
  626. break;
  627. case 1002: /* --userpass */
  628. if (!strchr(arg, ':'))
  629. show_usage();
  630. free(userpass);
  631. userpass = strdup(arg);
  632. break;
  633. case 1003:
  634. want_longpoll = false;
  635. break;
  636. case 1004:
  637. use_syslog = true;
  638. break;
  639. default:
  640. show_usage();
  641. }
  642. }
  643. static void parse_config(void)
  644. {
  645. int i;
  646. json_t *val;
  647. if (!json_is_object(opt_config))
  648. return;
  649. for (i = 0; i < ARRAY_SIZE(options); i++) {
  650. if (!options[i].name)
  651. break;
  652. if (!strcmp(options[i].name, "config"))
  653. continue;
  654. val = json_object_get(opt_config, options[i].name);
  655. if (!val)
  656. continue;
  657. if (options[i].has_arg && json_is_string(val)) {
  658. char *s = strdup(json_string_value(val));
  659. if (!s)
  660. break;
  661. parse_arg(options[i].val, s);
  662. free(s);
  663. } else if (!options[i].has_arg && json_is_true(val))
  664. parse_arg(options[i].val, "");
  665. else
  666. fprintf(stderr, "JSON option %s invalid\n",
  667. options[i].name);
  668. }
  669. }
  670. static void parse_cmdline(int argc, char *argv[])
  671. {
  672. int key;
  673. while (1) {
  674. key = getopt_long(argc, argv, "a:c:qDPr:s:t:h?", options, NULL);
  675. if (key < 0)
  676. break;
  677. parse_arg(key, optarg);
  678. }
  679. parse_config();
  680. }
  681. int main (int argc, char *argv[])
  682. {
  683. struct thr_info *thr;
  684. int i;
  685. rpc_url = strdup(DEF_RPC_URL);
  686. userpass = strdup(DEF_RPC_USERPASS);
  687. /* parse command line */
  688. parse_cmdline(argc, argv);
  689. pthread_mutex_init(&time_lock, NULL);
  690. #ifdef HAVE_SYSLOG_H
  691. if (use_syslog)
  692. openlog("cpuminer", LOG_PID, LOG_USER);
  693. #endif
  694. /* set our priority to the highest (aka "nicest, least intrusive") */
  695. if (setpriority(PRIO_PROCESS, 0, 19))
  696. perror("setpriority");
  697. work_restart = calloc(opt_n_threads, sizeof(*work_restart));
  698. if (!work_restart)
  699. return 1;
  700. thr_info = calloc(opt_n_threads + 2, sizeof(*thr));
  701. if (!thr_info)
  702. return 1;
  703. /* init workio thread info */
  704. work_thr_id = opt_n_threads;
  705. thr = &thr_info[work_thr_id];
  706. thr->id = work_thr_id;
  707. thr->q = tq_new();
  708. if (!thr->q)
  709. return 1;
  710. /* start work I/O thread */
  711. if (pthread_create(&thr->pth, NULL, workio_thread, thr)) {
  712. fprintf(stderr, "workio thread create failed\n");
  713. return 1;
  714. }
  715. /* init longpoll thread info */
  716. if (want_longpoll) {
  717. longpoll_thr_id = opt_n_threads + 1;
  718. thr = &thr_info[longpoll_thr_id];
  719. thr->id = longpoll_thr_id;
  720. thr->q = tq_new();
  721. if (!thr->q)
  722. return 1;
  723. /* start longpoll thread */
  724. if (pthread_create(&thr->pth, NULL, longpoll_thread, thr)) {
  725. fprintf(stderr, "longpoll thread create failed\n");
  726. return 1;
  727. }
  728. } else
  729. longpoll_thr_id = -1;
  730. /* start mining threads */
  731. for (i = 0; i < opt_n_threads; i++) {
  732. thr = &thr_info[i];
  733. thr->id = i;
  734. thr->q = tq_new();
  735. if (!thr->q)
  736. return 1;
  737. if (pthread_create(&thr->pth, NULL, miner_thread, thr)) {
  738. fprintf(stderr, "thread %d create failed\n", i);
  739. return 1;
  740. }
  741. sleep(1); /* don't pound RPC server all at once */
  742. }
  743. applog(LOG_INFO, "%d miner threads started, "
  744. "using SHA256 '%s' algorithm.\n",
  745. opt_n_threads,
  746. algo_names[opt_algo]);
  747. /* main loop - simply wait for workio thread to exit */
  748. pthread_join(thr_info[work_thr_id].pth, NULL);
  749. applog(LOG_INFO, "workio thread dead, exiting.");
  750. return 0;
  751. }