Browse Source

api.c V1.9 add 'restart' + redesign 'quit' so thread exits cleanly

Kano 14 years ago
parent
commit
4bf21de2fc
2 changed files with 91 additions and 12 deletions
  1. 5 2
      README
  2. 86 10
      api.c

+ 5 - 2
README

@@ -647,7 +647,7 @@ The STATUS section is:
    This defaults to the cgminer version but is the value of --api-description
    This defaults to the cgminer version but is the value of --api-description
    if it was specified at runtime.
    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:
 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
                               stating success or failure saving the cgminer config
                               to filename
                               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
                               reply before cgminer quits
 
 
  notify        NOTIFY         The last status and history count of each devices problem
  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
                               by the 'devs' command
                               e.g. DEVDETAILS=0,Name=GPU,ID=0,Driver=opencl,...|
                               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
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the cgminer status window
 in the cgminer status window
 
 

+ 86 - 10
api.c

@@ -158,7 +158,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 static const char GPUSEP = ',';
 
 
-static const char *APIVERSION = "1.8";
+static const char *APIVERSION = "1.9";
 static const char *DEAD = "Dead";
 static const char *DEAD = "Dead";
 static const char *SICK = "Sick";
 static const char *SICK = "Sick";
 static const char *NOSTART = "NoStart";
 static const char *NOSTART = "NoStart";
@@ -229,6 +229,7 @@ static const char *OSINFO =
 #define _NOTIFY		"NOTIFY"
 #define _NOTIFY		"NOTIFY"
 #define _DEVDETAILS	"DEVDETAILS"
 #define _DEVDETAILS	"DEVDETAILS"
 #define _BYE		"BYE"
 #define _BYE		"BYE"
+#define _RESTART	"RESTART"
 
 
 static const char ISJSON = '{';
 static const char ISJSON = '{';
 #define JSON0		"{"
 #define JSON0		"{"
@@ -260,6 +261,7 @@ static const char ISJSON = '{';
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
 #define JSON_NOTIFY	JSON1 _NOTIFY JSON2
 #define JSON_DEVDETAILS	JSON1 _DEVDETAILS JSON2
 #define JSON_DEVDETAILS	JSON1 _DEVDETAILS JSON2
 #define JSON_BYE	JSON1 _BYE JSON1
 #define JSON_BYE	JSON1 _BYE JSON1
+#define JSON_RESTART	JSON1 _RESTART JSON1
 #define JSON_CLOSE	JSON3
 #define JSON_CLOSE	JSON3
 #define JSON_END	JSON4
 #define JSON_END	JSON4
 
 
@@ -479,6 +481,12 @@ static int my_thr_id = 0;
 static int bye = 0;
 static int bye = 0;
 static bool ping = true;
 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
 static time_t when = 0;	// when the request occurred
 
 
 struct IP4ACCESS {
 struct IP4ACCESS {
@@ -612,7 +620,7 @@ static int pgadevice(int pgaid)
 }
 }
 #endif
 #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
 //  thus for JSON, message() inserts JSON_START at the front
 //  and send_result() adds JSON_END at the end
 //  and send_result() adds JSON_END at the end
 static char *message(int messageid, int paramid, char *param2, bool isjson)
 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
 #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)
 	if (isjson)
 		strcpy(io_buffer, JSON_START JSON_BYE);
 		strcpy(io_buffer, JSON_START JSON_BYE);
 	else
 	else
 		strcpy(io_buffer, _BYE);
 		strcpy(io_buffer, _BYE);
 
 
-	send_result(c, isjson);
-	*io_buffer = '\0';
 	bye = 1;
 	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)
 void privileged(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson)
@@ -2017,6 +2029,7 @@ struct CMDS {
 	{ "privileged",		privileged,	true },
 	{ "privileged",		privileged,	true },
 	{ "notify",		notify,		false },
 	{ "notify",		notify,		false },
 	{ "devdetails",		devdetails,	false },
 	{ "devdetails",		devdetails,	false },
+	{ "restart",		dorestart,	true },
 	{ NULL,			NULL,		false }
 	{ NULL,			NULL,		false }
 };
 };
 
 
@@ -2041,11 +2054,12 @@ static void send_result(SOCKETTYPE c, bool isjson)
 		else
 		else
 			applog(LOG_DEBUG, "API: sent %d", n);
 			applog(LOG_DEBUG, "API: sent %d", n);
 	}
 	}
-
 }
 }
 
 
 static void tidyup(__maybe_unused void *arg)
 static void tidyup(__maybe_unused void *arg)
 {
 {
+	mutex_lock(&quit_restart_lock);
+
 	bye = 1;
 	bye = 1;
 
 
 	if (sock != INVSOCK) {
 	if (sock != INVSOCK) {
@@ -2068,6 +2082,8 @@ static void tidyup(__maybe_unused void *arg)
 		free(io_buffer);
 		free(io_buffer);
 		io_buffer = NULL;
 		io_buffer = NULL;
 	}
 	}
+
+	mutex_unlock(&quit_restart_lock);
 }
 }
 
 
 /*
 /*
@@ -2172,8 +2188,37 @@ popipo:
 	free(buf);
 	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)
 void api(int api_thr_id)
 {
 {
+	struct thr_info bye_thr;
 	char buf[BUFSIZ];
 	char buf[BUFSIZ];
 	char param_buf[BUFSIZ];
 	char param_buf[BUFSIZ];
 	const char *localaddr = "127.0.0.1";
 	const char *localaddr = "127.0.0.1";
@@ -2197,6 +2242,8 @@ void api(int api_thr_id)
 	bool did;
 	bool did;
 	int i;
 	int i;
 
 
+	mutex_init(&quit_restart_lock);
+
 	pthread_cleanup_push(tidyup, NULL);
 	pthread_cleanup_push(tidyup, NULL);
 	my_thr_id = api_thr_id;
 	my_thr_id = api_thr_id;
 
 
@@ -2408,4 +2455,33 @@ void api(int api_thr_id)
 	}
 	}
 die:
 die:
 	pthread_cleanup_pop(true);
 	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);
 }
 }