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
    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
 
 

+ 83 - 14
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
 
 
@@ -476,9 +478,15 @@ struct CODES {
 };
 };
 
 
 static int my_thr_id = 0;
 static int my_thr_id = 0;
-static int bye = 0;
+static bool bye;
 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 bool do_a_quit;
+static bool do_a_restart;
+
 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 = 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)
 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,12 +2054,13 @@ 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)
 {
 {
-	bye = 1;
+	mutex_lock(&quit_restart_lock);
+
+	bye = true;
 
 
 	if (sock != INVSOCK) {
 	if (sock != INVSOCK) {
 		shutdown(sock, SHUT_RDWR);
 		shutdown(sock, SHUT_RDWR);
@@ -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;
 
 
@@ -2276,7 +2323,7 @@ void api(int api_thr_id)
 	io_buffer = malloc(MYBUFSIZ+1);
 	io_buffer = malloc(MYBUFSIZ+1);
 	msg_buffer = malloc(MYBUFSIZ+1);
 	msg_buffer = malloc(MYBUFSIZ+1);
 
 
-	while (bye == 0) {
+	while (!bye) {
 		clisiz = sizeof(cli);
 		clisiz = sizeof(cli);
 		if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
 		if (SOCKETFAIL(c = accept(sock, (struct sockaddr *)(&cli), &clisiz))) {
 			applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 			applog(LOG_ERR, "API failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
@@ -2408,4 +2455,26 @@ 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) {
+		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)
 static bool icarus_detect_one(const char *devpath)
 {
 {
-	struct timeval tv1, tv2;
+	struct timeval tv_start, tv_finish;
 	int fd;
 	int fd;
 
 
 	// Block 171874 nonce = (0xa2870100) = 0x000187a2
 	// 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));
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, 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));
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	icarus_gets(nonce_bin, sizeof(nonce_bin), fd, -1, 1);
 	icarus_gets(nonce_bin, sizeof(nonce_bin), fd, -1, 1);
-	gettimeofday(&tv2, NULL);
+	gettimeofday(&tv_finish, NULL);
 
 
 	icarus_close(fd);
 	icarus_close(fd);
 
 
@@ -315,7 +315,9 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	char *ob_hex, *nonce_hex;
 	char *ob_hex, *nonce_hex;
 	uint32_t nonce;
 	uint32_t nonce;
 	uint32_t hash_count;
 	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;
 	icarus = thr->cgpu;
 	fd = icarus->device_fd;
 	fd = icarus->device_fd;
@@ -329,30 +331,37 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	tcflush(fd, TCOFLUSH);
 	tcflush(fd, TCOFLUSH);
 #endif
 #endif
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
-	gettimeofday(&tv1, NULL);
+	if (opt_debug)
+		gettimeofday(&tv_start, NULL);
 	if (ret)
 	if (ret)
 		return 0;	/* This should never happen */
 		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));
 	memset(nonce_bin, 0, sizeof(nonce_bin));
 	ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, thr_id,
 	ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, thr_id,
 						ICARUS_READ_COUNT_DEFAULT);
 						ICARUS_READ_COUNT_DEFAULT);
-	gettimeofday(&tv2, NULL);
+
+	if (opt_debug)
+		gettimeofday(&tv_finish, NULL);
 
 
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
 
 
 	// aborted before becoming idle, get new work
 	// aborted before becoming idle, get new work
         if (nonce == 0 && ret) {
         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;
 		return ESTIMATE_HASHES;
 	}
 	}
 
 
@@ -363,27 +372,26 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	work->blk.nonce = 0xffffffff;
 	work->blk.nonce = 0xffffffff;
 	submit_nonce(thr, work, nonce);
 	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);
 	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;
         return hash_count;
 }
 }