mirror of
https://github.com/GOSTSec/sgminer
synced 2025-09-13 06:31:51 +00:00
Signal handling in dns lookup code is responsible for libcurl crashes when multithreading.
Disable signal handling and use many curl handles instead, thus making work more asynchronous. Theoretically a curl can wait forever on a dns lookup with this but it's extremely unlikely.
This commit is contained in:
parent
8a0bbf31d4
commit
af6e7937ca
113
main.c
113
main.c
@ -336,19 +336,25 @@ err_out:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool submit_upstream_work(CURL *curl, const struct work *work)
|
static bool submit_upstream_work(const struct work *work)
|
||||||
{
|
{
|
||||||
char *hexstr = NULL;
|
char *hexstr = NULL;
|
||||||
json_t *val, *res;
|
json_t *val, *res;
|
||||||
char s[345];
|
char s[345];
|
||||||
bool rc = false;
|
bool rc = false;
|
||||||
struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu;
|
struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu;
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
|
||||||
|
if (unlikely(!curl)) {
|
||||||
|
applog(LOG_ERR, "CURL initialisation failed");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* build hex string */
|
/* build hex string */
|
||||||
hexstr = bin2hex(work->data, sizeof(work->data));
|
hexstr = bin2hex(work->data, sizeof(work->data));
|
||||||
if (unlikely(!hexstr)) {
|
if (unlikely(!hexstr)) {
|
||||||
applog(LOG_ERR, "submit_upstream_work OOM");
|
applog(LOG_ERR, "submit_upstream_work OOM");
|
||||||
goto out;
|
goto out_nofree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build JSON-RPC request */
|
/* build JSON-RPC request */
|
||||||
@ -388,30 +394,39 @@ static bool submit_upstream_work(CURL *curl, const struct work *work)
|
|||||||
json_decref(val);
|
json_decref(val);
|
||||||
|
|
||||||
rc = true;
|
rc = true;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(hexstr);
|
free(hexstr);
|
||||||
|
out_nofree:
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *rpc_req =
|
static const char *rpc_req =
|
||||||
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
||||||
|
|
||||||
static bool get_upstream_work(CURL *curl, struct work *work)
|
static bool get_upstream_work(struct work *work)
|
||||||
{
|
{
|
||||||
json_t *val;
|
json_t *val;
|
||||||
bool rc;
|
bool rc = false;
|
||||||
|
CURL *curl = curl_easy_init();
|
||||||
|
|
||||||
|
if (unlikely(!curl)) {
|
||||||
|
applog(LOG_ERR, "CURL initialisation failed");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req,
|
val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req,
|
||||||
want_longpoll, false);
|
want_longpoll, false);
|
||||||
if (unlikely(!val)) {
|
if (unlikely(!val)) {
|
||||||
applog(LOG_ERR, "Failed json_rpc_call in get_upstream_work");
|
applog(LOG_ERR, "Failed json_rpc_call in get_upstream_work");
|
||||||
return false;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = work_decode(json_object_get(val, "result"), work);
|
rc = work_decode(json_object_get(val, "result"), work);
|
||||||
|
|
||||||
json_decref(val);
|
json_decref(val);
|
||||||
|
out:
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -454,23 +469,15 @@ static void kill_work(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct io_data{
|
|
||||||
struct workio_cmd *wc;
|
|
||||||
CURL *curl;
|
|
||||||
};
|
|
||||||
|
|
||||||
static pthread_t *get_thread = NULL;
|
|
||||||
static pthread_t *submit_thread = NULL;
|
|
||||||
static char current_block[36];
|
static char current_block[36];
|
||||||
|
|
||||||
static void *get_work_thread(void *userdata)
|
static void *get_work_thread(void *userdata)
|
||||||
{
|
{
|
||||||
struct io_data *io_data = (struct io_data *)userdata;
|
struct workio_cmd *wc = (struct workio_cmd *)userdata;
|
||||||
struct workio_cmd *wc = io_data->wc;
|
|
||||||
CURL *curl = io_data->curl;
|
|
||||||
struct work *ret_work;
|
struct work *ret_work;
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
|
|
||||||
|
pthread_detach(pthread_self());
|
||||||
ret_work = calloc(1, sizeof(*ret_work));
|
ret_work = calloc(1, sizeof(*ret_work));
|
||||||
if (unlikely(!ret_work)) {
|
if (unlikely(!ret_work)) {
|
||||||
applog(LOG_ERR, "Failed to calloc ret_work in workio_get_work");
|
applog(LOG_ERR, "Failed to calloc ret_work in workio_get_work");
|
||||||
@ -479,7 +486,7 @@ static void *get_work_thread(void *userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* obtain new work from bitcoin via JSON-RPC */
|
/* obtain new work from bitcoin via JSON-RPC */
|
||||||
while (!get_upstream_work(curl, ret_work)) {
|
while (!get_upstream_work(ret_work)) {
|
||||||
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
|
if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
|
||||||
applog(LOG_ERR, "json_rpc_call failed, terminating workio thread");
|
applog(LOG_ERR, "json_rpc_call failed, terminating workio thread");
|
||||||
free(ret_work);
|
free(ret_work);
|
||||||
@ -501,35 +508,16 @@ static void *get_work_thread(void *userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(io_data);
|
|
||||||
workio_cmd_free(wc);
|
workio_cmd_free(wc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool workio_get_work(struct workio_cmd *wc, CURL *curl)
|
static bool workio_get_work(struct workio_cmd *wc)
|
||||||
{
|
{
|
||||||
struct io_data *id = malloc(sizeof(struct io_data));
|
pthread_t get_thread;
|
||||||
|
|
||||||
if (unlikely(!id)) {
|
if (unlikely(pthread_create(&get_thread, NULL, get_work_thread, (void *)wc))) {
|
||||||
applog(LOG_ERR, "Failed to malloc id in workio_get_work");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
id->wc = wc;
|
|
||||||
id->curl = curl;
|
|
||||||
|
|
||||||
if (unlikely(!get_thread)) {
|
|
||||||
/* This is only instantiated once at startup */
|
|
||||||
get_thread = malloc(sizeof(get_thread));
|
|
||||||
if (unlikely(!get_thread)) {
|
|
||||||
applog(LOG_ERR, "Failed to malloc get_thread in workio_get_work");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
pthread_join(*get_thread, NULL);
|
|
||||||
|
|
||||||
if (unlikely(pthread_create(get_thread, NULL, get_work_thread, (void *)id))) {
|
|
||||||
applog(LOG_ERR, "Failed to create get_work_thread");
|
applog(LOG_ERR, "Failed to create get_work_thread");
|
||||||
free(id);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -537,18 +525,17 @@ static bool workio_get_work(struct workio_cmd *wc, CURL *curl)
|
|||||||
|
|
||||||
static void *submit_work_thread(void *userdata)
|
static void *submit_work_thread(void *userdata)
|
||||||
{
|
{
|
||||||
struct io_data *io_data = (struct io_data *)userdata;
|
struct workio_cmd *wc = (struct workio_cmd *)userdata;
|
||||||
struct workio_cmd *wc = io_data->wc;
|
|
||||||
CURL *curl = io_data->curl;
|
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
|
|
||||||
|
pthread_detach(pthread_self());
|
||||||
if (unlikely(strncmp((const char *)wc->u.work->data, current_block, 36))) {
|
if (unlikely(strncmp((const char *)wc->u.work->data, current_block, 36))) {
|
||||||
applog(LOG_INFO, "Stale work detected, discarding");
|
applog(LOG_INFO, "Stale work detected, discarding");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* submit solution to bitcoin via JSON-RPC */
|
/* submit solution to bitcoin via JSON-RPC */
|
||||||
while (!submit_upstream_work(curl, 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((const char *)wc->u.work->data, current_block, 36))) {
|
||||||
applog(LOG_INFO, "Stale work detected, discarding");
|
applog(LOG_INFO, "Stale work detected, discarding");
|
||||||
goto out;
|
goto out;
|
||||||
@ -567,33 +554,15 @@ static void *submit_work_thread(void *userdata)
|
|||||||
|
|
||||||
out:
|
out:
|
||||||
workio_cmd_free(wc);
|
workio_cmd_free(wc);
|
||||||
free(io_data);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool workio_submit_work(struct workio_cmd *wc, CURL *curl)
|
static bool workio_submit_work(struct workio_cmd *wc)
|
||||||
{
|
{
|
||||||
struct io_data *id = malloc(sizeof(struct io_data));
|
pthread_t submit_thread;
|
||||||
|
|
||||||
if (unlikely(!id)) {
|
if (unlikely(pthread_create(&submit_thread, NULL, submit_work_thread, (void *)wc))) {
|
||||||
applog(LOG_ERR, "Failed to malloc id in workio_submit_work");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
id->wc = wc;
|
|
||||||
id->curl = curl;
|
|
||||||
|
|
||||||
if (unlikely(!submit_thread)) {
|
|
||||||
submit_thread = malloc(sizeof(submit_thread));
|
|
||||||
if (unlikely(!submit_thread)) {
|
|
||||||
applog(LOG_ERR, "Failed to malloc submit_thread in workio_submit_work");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
pthread_join(*submit_thread, NULL);
|
|
||||||
|
|
||||||
if (unlikely(pthread_create(submit_thread, NULL, submit_work_thread, (void *)id))) {
|
|
||||||
applog(LOG_ERR, "Failed to create submit_work_thread");
|
applog(LOG_ERR, "Failed to create submit_work_thread");
|
||||||
free(id);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -603,14 +572,6 @@ static void *workio_thread(void *userdata)
|
|||||||
{
|
{
|
||||||
struct thr_info *mythr = userdata;
|
struct thr_info *mythr = userdata;
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
CURL *get_curl, *submit_curl;
|
|
||||||
|
|
||||||
get_curl = curl_easy_init();
|
|
||||||
submit_curl = curl_easy_init();
|
|
||||||
if (unlikely(!get_curl || !submit_curl)) {
|
|
||||||
applog(LOG_ERR, "CURL initialization failed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ok) {
|
while (ok) {
|
||||||
struct workio_cmd *wc;
|
struct workio_cmd *wc;
|
||||||
@ -625,10 +586,10 @@ static void *workio_thread(void *userdata)
|
|||||||
/* process workio_cmd */
|
/* process workio_cmd */
|
||||||
switch (wc->cmd) {
|
switch (wc->cmd) {
|
||||||
case WC_GET_WORK:
|
case WC_GET_WORK:
|
||||||
ok = workio_get_work(wc, get_curl);
|
ok = workio_get_work(wc);
|
||||||
break;
|
break;
|
||||||
case WC_SUBMIT_WORK:
|
case WC_SUBMIT_WORK:
|
||||||
ok = workio_submit_work(wc, submit_curl);
|
ok = workio_submit_work(wc);
|
||||||
break;
|
break;
|
||||||
case WC_DIE:
|
case WC_DIE:
|
||||||
default:
|
default:
|
||||||
@ -638,8 +599,6 @@ static void *workio_thread(void *userdata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tq_freeze(mythr->q);
|
tq_freeze(mythr->q);
|
||||||
curl_easy_cleanup(submit_curl);
|
|
||||||
curl_easy_cleanup(get_curl);
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1271,7 +1230,7 @@ static void *longpoll_thread(void *userdata)
|
|||||||
|
|
||||||
curl = curl_easy_init();
|
curl = curl_easy_init();
|
||||||
if (unlikely(!curl)) {
|
if (unlikely(!curl)) {
|
||||||
applog(LOG_ERR, "CURL initialization failed");
|
applog(LOG_ERR, "CURL initialisation failed");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
util.c
1
util.c
@ -225,6 +225,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
|
|||||||
|
|
||||||
if (opt_protocol)
|
if (opt_protocol)
|
||||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(curl, CURLOPT_ENCODING, "");
|
curl_easy_setopt(curl, CURLOPT_ENCODING, "");
|
||||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user