Browse Source

Merge pull request #187 from kanoi/master

api.c V1.9 add 'restart' + redesign 'quit' so thread exits cleanly
Con Kolivas 14 years ago
parent
commit
8c0c7ea148
3 changed files with 128 additions and 48 deletions
  1. 5 2
      README
  2. 83 14
      api.c
  3. 40 32
      driver-icarus.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
    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
 

+ 83 - 14
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
 
@@ -476,9 +478,15 @@ struct CODES {
 };
 
 static int my_thr_id = 0;
-static int bye = 0;
+static bool bye;
 static bool ping = true;
 
+// Used to control quit restart access to shutdown variables
+static pthread_mutex_t quit_restart_lock;
+
+static bool do_a_quit;
+static bool do_a_restart;
+
 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;
+	bye = true;
+	do_a_quit = true;
+}
 
-        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 = true;
+	do_a_restart = true;
 }
 
 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,12 +2054,13 @@ static void send_result(SOCKETTYPE c, bool isjson)
 		else
 			applog(LOG_DEBUG, "API: sent %d", n);
 	}
-
 }
 
 static void tidyup(__maybe_unused void *arg)
 {
-	bye = 1;
+	mutex_lock(&quit_restart_lock);
+
+	bye = true;
 
 	if (sock != INVSOCK) {
 		shutdown(sock, SHUT_RDWR);
@@ -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;
 
@@ -2276,7 +2323,7 @@ void api(int api_thr_id)
 	io_buffer = malloc(MYBUFSIZ+1);
 	msg_buffer = malloc(MYBUFSIZ+1);
 
-	while (bye == 0) {
+	while (!bye) {
 		clisiz = sizeof(cli);
 		if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
 			applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
@@ -2408,4 +2455,26 @@ 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) {
+		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) {
+		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);
 }

+ 40 - 32
driver-icarus.c

@@ -196,7 +196,7 @@ static int icarus_write(int fd, const void *buf, size_t bufLen)
 
 static bool icarus_detect_one(const char *devpath)
 {
-	struct timeval tv1, tv2;
+	struct timeval tv_start, tv_finish;
 	int fd;
 
 	// Block 171874 nonce = (0xa2870100) = 0x000187a2
@@ -225,11 +225,11 @@ static bool icarus_detect_one(const char *devpath)
 
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, sizeof(ob_bin));
-	gettimeofday(&tv1, NULL);
+	gettimeofday(&tv_start, NULL);
 
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	icarus_gets(nonce_bin, sizeof(nonce_bin), fd, -1, 1);
-	gettimeofday(&tv2, NULL);
+	gettimeofday(&tv_finish, NULL);
 
 	icarus_close(fd);
 
@@ -315,7 +315,9 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	char *ob_hex, *nonce_hex;
 	uint32_t nonce;
 	uint32_t hash_count;
-	struct timeval tv1, tv2, elapsed;
+	struct timeval tv_start, tv_finish, elapsed;
+
+	elapsed.tv_sec = elapsed.tv_usec = 0;
 
 	icarus = thr->cgpu;
 	fd = icarus->device_fd;
@@ -329,30 +331,37 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	tcflush(fd, TCOFLUSH);
 #endif
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
-	gettimeofday(&tv1, NULL);
+	if (opt_debug)
+		gettimeofday(&tv_start, NULL);
 	if (ret)
 		return 0;	/* This should never happen */
 
-	ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
-	if (ob_hex) {
-		applog(LOG_DEBUG, "Icarus %d sent: %s",
-		       icarus->device_id, ob_hex);
-		free(ob_hex);
+	if (opt_debug) {
+		ob_hex = bin2hex(ob_bin, sizeof(ob_bin));
+		if (ob_hex) {
+			applog(LOG_DEBUG, "Icarus %d sent: %s",
+			       icarus->device_id, ob_hex);
+			free(ob_hex);
+		}
 	}
 
-	/* Icarus will return 8 bytes nonces or nothing */
+	/* Icarus will return 4 bytes nonces or nothing */
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, thr_id,
 						ICARUS_READ_COUNT_DEFAULT);
-	gettimeofday(&tv2, NULL);
+
+	if (opt_debug)
+		gettimeofday(&tv_finish, NULL);
 
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
 
 	// aborted before becoming idle, get new work
         if (nonce == 0 && ret) {
-		timersub(&tv2, &tv1, &elapsed);
-		applog(LOG_DEBUG, "Icarus %d no nonce = 0x%08x hashes (%ld.%06lds)",
-			icarus->device_id, ESTIMATE_HASHES, elapsed.tv_sec, elapsed.tv_usec);
+		if (opt_debug) {
+			timersub(&tv_finish, &tv_start, &elapsed);
+			applog(LOG_DEBUG, "Icarus %d no nonce = 0x%08x hashes (%ld.%06lds)",
+				icarus->device_id, ESTIMATE_HASHES, elapsed.tv_sec, elapsed.tv_usec);
+		}
 		return ESTIMATE_HASHES;
 	}
 
@@ -363,27 +372,26 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	work->blk.nonce = 0xffffffff;
 	submit_nonce(thr, work, nonce);
 
-	timersub(&tv2, &tv1, &elapsed);
+	if (opt_debug) {
+		timersub(&tv_finish, &tv_start, &elapsed);
 
-	nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
-	if (nonce_hex) {
-		applog(LOG_DEBUG, "Icarus %d returned (elapsed %ld.%06ld seconds): %s",
-		       icarus->device_id, elapsed.tv_sec, elapsed.tv_usec, nonce_hex);
-		free(nonce_hex);
+		nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
+		if (nonce_hex) {
+			applog(LOG_DEBUG, "Icarus %d returned (elapsed %ld.%06ld seconds): %s",
+			       icarus->device_id, elapsed.tv_sec, elapsed.tv_usec, nonce_hex);
+			free(nonce_hex);
+		}
 	}
 
 	hash_count = (nonce & 0x7fffffff);
-        if (hash_count == 0)
-		hash_count = 2;
-        else {
-                if (hash_count++ == 0x7fffffff)
-                        hash_count = 0xffffffff;
-                else
-                        hash_count <<= 1;
-        }
-
-	applog(LOG_DEBUG, "Icarus %d nonce = 0x%08x = 0x%08x hashes (%ld.%06lds)",
-			icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
+	if (hash_count++ == 0x7fffffff)
+		hash_count = 0xffffffff;
+	else
+		hash_count <<= 1;
+
+	if (opt_debug)
+		applog(LOG_DEBUG, "Icarus %d nonce = 0x%08x = 0x%08x hashes (%ld.%06lds)",
+				icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
 
         return hash_count;
 }