From 524e2fb8f26ec0d7e8820c5530dafa57b56415bc Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 2 May 2012 16:11:11 +1000 Subject: [PATCH] api.c V1.9 add 'restart' + redesign 'quit' so thread exits cleanly --- README | 7 +++-- api.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 91 insertions(+), 12 deletions(-) diff --git a/README b/README index d5260f82..c5155eaf 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 72a1a214..6c02a972 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); }