|
|
@@ -158,7 +158,7 @@ static const char SEPARATOR = '|';
|
|
|
#define SEPSTR "|"
|
|
|
static const char GPUSEP = ',';
|
|
|
|
|
|
-static const char *APIVERSION = "1.8";
|
|
|
+static const char *APIVERSION = "1.9";
|
|
|
static const char *DEAD = "Dead";
|
|
|
static const char *SICK = "Sick";
|
|
|
static const char *NOSTART = "NoStart";
|
|
|
@@ -229,6 +229,7 @@ static const char *OSINFO =
|
|
|
#define _NOTIFY "NOTIFY"
|
|
|
#define _DEVDETAILS "DEVDETAILS"
|
|
|
#define _BYE "BYE"
|
|
|
+#define _RESTART "RESTART"
|
|
|
|
|
|
static const char ISJSON = '{';
|
|
|
#define JSON0 "{"
|
|
|
@@ -260,6 +261,7 @@ static const char ISJSON = '{';
|
|
|
#define JSON_NOTIFY JSON1 _NOTIFY JSON2
|
|
|
#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2
|
|
|
#define JSON_BYE JSON1 _BYE JSON1
|
|
|
+#define JSON_RESTART JSON1 _RESTART JSON1
|
|
|
#define JSON_CLOSE JSON3
|
|
|
#define JSON_END JSON4
|
|
|
|
|
|
@@ -479,6 +481,12 @@ static int my_thr_id = 0;
|
|
|
static int bye = 0;
|
|
|
static bool ping = true;
|
|
|
|
|
|
+// Used to control quit restart access to shutdown variables
|
|
|
+static pthread_mutex_t quit_restart_lock;
|
|
|
+
|
|
|
+static int do_a_quit = 0;
|
|
|
+static int do_a_restart = 0;
|
|
|
+
|
|
|
static time_t when = 0; // when the request occurred
|
|
|
|
|
|
struct IP4ACCESS {
|
|
|
@@ -612,7 +620,7 @@ static int pgadevice(int pgaid)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-// All replies (except BYE) start with a message
|
|
|
+// All replies (except BYE and RESTART) start with a message
|
|
|
// thus for JSON, message() inserts JSON_START at the front
|
|
|
// and send_result() adds JSON_END at the end
|
|
|
static char *message(int messageid, int paramid, char *param2, bool isjson)
|
|
|
@@ -1811,22 +1819,26 @@ static void gpuvddc(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-static void send_result(SOCKETTYPE c, bool isjson);
|
|
|
-
|
|
|
-void doquit(SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+void doquit(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
{
|
|
|
if (isjson)
|
|
|
strcpy(io_buffer, JSON_START JSON_BYE);
|
|
|
else
|
|
|
strcpy(io_buffer, _BYE);
|
|
|
|
|
|
- send_result(c, isjson);
|
|
|
- *io_buffer = '\0';
|
|
|
bye = 1;
|
|
|
+ do_a_quit = 1;
|
|
|
+}
|
|
|
|
|
|
- PTH(&thr_info[my_thr_id]) = 0L;
|
|
|
+void dorestart(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
+{
|
|
|
+ if (isjson)
|
|
|
+ strcpy(io_buffer, JSON_START JSON_RESTART);
|
|
|
+ else
|
|
|
+ strcpy(io_buffer, _RESTART);
|
|
|
|
|
|
- kill_work();
|
|
|
+ bye = 1;
|
|
|
+ do_a_restart = 1;
|
|
|
}
|
|
|
|
|
|
void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
|
|
|
@@ -2017,6 +2029,7 @@ struct CMDS {
|
|
|
{ "privileged", privileged, true },
|
|
|
{ "notify", notify, false },
|
|
|
{ "devdetails", devdetails, false },
|
|
|
+ { "restart", dorestart, true },
|
|
|
{ NULL, NULL, false }
|
|
|
};
|
|
|
|
|
|
@@ -2041,11 +2054,12 @@ static void send_result(SOCKETTYPE c, bool isjson)
|
|
|
else
|
|
|
applog(LOG_DEBUG, "API: sent %d", n);
|
|
|
}
|
|
|
-
|
|
|
}
|
|
|
|
|
|
static void tidyup(__maybe_unused void *arg)
|
|
|
{
|
|
|
+ mutex_lock(&quit_restart_lock);
|
|
|
+
|
|
|
bye = 1;
|
|
|
|
|
|
if (sock != INVSOCK) {
|
|
|
@@ -2068,6 +2082,8 @@ static void tidyup(__maybe_unused void *arg)
|
|
|
free(io_buffer);
|
|
|
io_buffer = NULL;
|
|
|
}
|
|
|
+
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -2172,8 +2188,37 @@ popipo:
|
|
|
free(buf);
|
|
|
}
|
|
|
|
|
|
+static void *quit_thread(__maybe_unused void *userdata)
|
|
|
+{
|
|
|
+ // allow thread creator to finish whatever it's doing
|
|
|
+ mutex_lock(&quit_restart_lock);
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
+
|
|
|
+ if (opt_debug)
|
|
|
+ applog(LOG_DEBUG, "API: killing cgminer");
|
|
|
+
|
|
|
+ kill_work();
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static void *restart_thread(__maybe_unused void *userdata)
|
|
|
+{
|
|
|
+ // allow thread creator to finish whatever it's doing
|
|
|
+ mutex_lock(&quit_restart_lock);
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
+
|
|
|
+ if (opt_debug)
|
|
|
+ applog(LOG_DEBUG, "API: restarting cgminer");
|
|
|
+
|
|
|
+ app_restart();
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
void api(int api_thr_id)
|
|
|
{
|
|
|
+ struct thr_info bye_thr;
|
|
|
char buf[BUFSIZ];
|
|
|
char param_buf[BUFSIZ];
|
|
|
const char *localaddr = "127.0.0.1";
|
|
|
@@ -2197,6 +2242,8 @@ void api(int api_thr_id)
|
|
|
bool did;
|
|
|
int i;
|
|
|
|
|
|
+ mutex_init(&quit_restart_lock);
|
|
|
+
|
|
|
pthread_cleanup_push(tidyup, NULL);
|
|
|
my_thr_id = api_thr_id;
|
|
|
|
|
|
@@ -2408,4 +2455,33 @@ void api(int api_thr_id)
|
|
|
}
|
|
|
die:
|
|
|
pthread_cleanup_pop(true);
|
|
|
+
|
|
|
+ if (opt_debug)
|
|
|
+ applog(LOG_DEBUG, "API: terminating due to: %s",
|
|
|
+ do_a_quit ? "QUIT" : (do_a_restart ? "RESTART" : (bye ? "BYE" : "UNKNOWN!")));
|
|
|
+
|
|
|
+ mutex_lock(&quit_restart_lock);
|
|
|
+
|
|
|
+ if (do_a_restart != 0) {
|
|
|
+
|
|
|
+ if (thr_info_create(&bye_thr, NULL, restart_thread, &bye_thr)) {
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
+ quit(1, "API failed to initiate a restart - aborting");
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_detach(bye_thr.pth);
|
|
|
+
|
|
|
+ } else
|
|
|
+ if (do_a_quit != 0) {
|
|
|
+
|
|
|
+ if (thr_info_create(&bye_thr, NULL, quit_thread, &bye_thr)) {
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
+ quit(1, "API failed to initiate a clean quit - aborting");
|
|
|
+ }
|
|
|
+
|
|
|
+ pthread_detach(bye_thr.pth);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ mutex_unlock(&quit_restart_lock);
|
|
|
}
|