api.c V1.9 add 'restart' + redesign 'quit' so thread exits cleanly
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
diff --git a/README b/README
index d5260f8..c5155ea 100644
--- a/README
+++ b/README
@@ -647,7 +647,7 @@ The STATUS section is:
This defaults to the cgminer version but is the value of --api-description
if it was specified at runtime.
-For API version 1.8:
+For API version 1.9:
The list of requests - a (*) means it requires privileged access - and replies are:
@@ -768,7 +768,7 @@ The list of requests - a (*) means it requires privileged access - and replies a
stating success or failure saving the cgminer config
to filename
- quit (*) none There is no status section but just a single "BYE|"
+ quit (*) none There is no status section but just a single "BYE"
reply before cgminer quits
notify NOTIFY The last status and history count of each devices problem
@@ -798,6 +798,9 @@ The list of requests - a (*) means it requires privileged access - and replies a
by the 'devs' command
e.g. DEVDETAILS=0,Name=GPU,ID=0,Driver=opencl,...|
+ restart (*) none There is no status section but just a single "RESTART"
+ reply before cgminer restarts
+
When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window
diff --git a/api.c b/api.c
index 72a1a21..6c02a97 100644
--- a/api.c
+++ b/api.c
@@ -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);
}