Browse Source

Events framework

Added the ability to have users run commands, reboot the system or quit sgminer based on system events. These events can be defined and placed throughout the sgminer source. So far the events are: "gpu_sick", "gpu_dead" and "idle". I will document further shortly. Config example available here: http://pastebin.com/2rRv3EzH
djm34
ystarnaud 10 years ago committed by troky
parent
commit
81d9c9e574
  1. 1
      Makefile.am
  2. 2
      config_parser.c
  3. 148
      doc/configuration.md
  4. 270
      events.c
  5. 23
      events.h
  6. 36
      sgminer.c
  7. 2
      winbuild/sgminer.vcxproj
  8. 6
      winbuild/sgminer.vcxproj.filters

1
Makefile.am

@ -43,6 +43,7 @@ sgminer_SOURCES += adl.c adl.h adl_functions.h @@ -43,6 +43,7 @@ sgminer_SOURCES += adl.c adl.h adl_functions.h
sgminer_SOURCES += pool.c pool.h
sgminer_SOURCES += algorithm.c algorithm.h
sgminer_SOURCES += config_parser.c config_parser.h
sgminer_SOURCES += events.c events.h
sgminer_SOURCES += ocl/patch_kernel.c ocl/patch_kernel.h
sgminer_SOURCES += ocl/build_kernel.c ocl/build_kernel.h
sgminer_SOURCES += ocl/binary_kernel.c ocl/binary_kernel.h

2
config_parser.c

@ -662,7 +662,7 @@ static char *parse_config_array(json_t *obj, char *parentkey, bool fileconf) @@ -662,7 +662,7 @@ static char *parse_config_array(json_t *obj, char *parentkey, bool fileconf)
json_t *val;
//fix parent key - remove extra "s" to match opt names (e.g. --pool-gpu-memclock not --pools-gpu-memclock)
if(!strcasecmp(parentkey, "pools") || !strcasecmp(parentkey, "profiles"))
if(!strcasecmp(parentkey, "pools") || !strcasecmp(parentkey, "profiles") || !strcasecmp(parentkey, "events"))
parentkey[(strlen(parentkey) - 1)] = '\0';
json_array_foreach(obj, idx, val)

148
doc/configuration.md

@ -8,8 +8,11 @@ @@ -8,8 +8,11 @@
* [Globals and the Default Profile](#globals-and-the-default-profile)
* [Working with Profiles and Pool Specific Settings](#working-with-profiles-and-pool-specific-settings)
* [Include and Includes](#include-and-includes)
* [Events](#events)
* [CLI Only options](#cli-only-options)
* [Config-file and CLI options](#config-file-and-cli-options)
* [Event options](#event-options)
* [Event Types](#event-types)
---
@ -233,6 +236,34 @@ There is no limit as to how includes can be used as long as they follow proper j @@ -233,6 +236,34 @@ There is no limit as to how includes can be used as long as they follow proper j
---
## Events
Users can now execute commands or perform certain tasks when pre-defined events occur while mining.
For example, one might want their miner to email them via a script when the miner goes idle and reboot the computer when a GPU goes dead. This gives users a little more flexibility controlling their mining uptime without necessarily resorting to external watchdog programs that, in some cases, can be troublesome.
Here is a configuration example of the above scenario:
```
...
"events":[
{
"on":"idle",
"runcmd":"/bin/mailscript \"Miner Idle\" \"Hey! My miner went idle!\""
},
{
"on":"gpu_dead",
"reboot":"yes"
}
],
...
```
For more details on configuration options, see [Event Options](#event-options) below.
[Top](#configuration-and-command-line-options)
---
## CLI Only options
* [config](#config) `--config` or `-c`
@ -2446,3 +2477,120 @@ Displays extra work time debug information. @@ -2446,3 +2477,120 @@ Displays extra work time debug information.
*Default:* `false`
[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options)
---
## Event options
* [on](#on)
* [runcmd](#runcmd)
* [reboot](#reboot)
* [reboot-delay](#reboot-delay)
* [quit](#quit)
* [quit-message](#quit-message)
### on
Specify which event type to respond on. See below for a list of supported [event types](#event-types)
*Available*: Events
*Config File Syntax:* `"on":"<value>"`
*Command Line Syntax:* `--event-on <value>`
*Argument:* `string` Name of the event type
*Default:* None
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
### runcmd
Specify a command to run when the event occurs. Please remember to properly escape quotes (") with backslashes (\\) if you need to specify multi-word parameters enclosed in quotes (") for your commands: `\"`
*Available*: Events
*Config File Syntax:* `"runcmd":"<value>"`
*Command Line Syntax:* `--event-runcmd <value>`
*Argument:* `string` Command to execute on event
*Default:* None
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
### reboot
Reboot when event occurs.
*Available*: Events
*Config File Syntax:* `"reboot":"<value>"`
*Command Line Syntax:* `--event-reboot <value>`
*Argument:* `string` Yes: `"true"` `"yes"` `"1"` or No: `"false"` `"no"` `"0"`
*Default:* `false`
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
### reboot-delay
Wait a number of seconds before rebooting when event occurs. This is useful if you also want to fire off a script via `runcmd` prior to rebooting, giving it extra seconds to finish.
*Available*: Events
*Config File Syntax:* `"reboot-delay":"<value>"`
*Command Line Syntax:* `--event-reboot-delay <value>`
*Argument:* `number` Seconds to wait before reboot
*Default:* `0`
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
### quit
Exit sgminer when event occurs.
*Available*: Events
*Config File Syntax:* `"quit":"<value>"`
*Command Line Syntax:* `--event-quit <value>`
*Argument:* `string` Yes: `"true"` `"yes"` `"1"` or No: `"false"` `"no"` `"0"`
*Default:* `false`
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
### quit-message
Message to display on sgminer exit when event occurs.
*Available*: Events
*Config File Syntax:* `"quit-message":"<value>"`
*Command Line Syntax:* `--event-quit-message "<value>"`
*Argument:* `string` Message
*Default:* `event_type`
[Top](#configuration-and-command-line-options) :: [Event options](#event-options)
---
## Event Types
* `idle` Occurs when a GPU goes idle for not performing any work or when no work has been received in 10 minutes.
* `gpu_sick` Occurs when a GPU fails to respond for 2 minutes
* `gpu_dead` Occurs when a GPU fails to respond for 10 minutes
[Top](#configuration-and-command-line-options)

270
events.c

@ -0,0 +1,270 @@ @@ -0,0 +1,270 @@
/*
* Copyright 2013-2014 sgminer developers (see AUTHORS.md)
* Copyright 2011-2013 Con Kolivas
* Copyright 2011-2012 Luke Dashjr
* Copyright 2010 Jeff Garzik
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <math.h>
#include <stdarg.h>
#include <assert.h>
#include <signal.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "compat.h"
#include "miner.h"
#include "events.h"
#include "config_parser.h"
// global event list
event_t *events = NULL, *last_event = NULL;
/***************************************************
* Helper functions
**************************************************/
static void *cmd_thread(void *cmdp)
{
const char *cmd = (const char*)cmdp;
applog(LOG_DEBUG, "Executing command: %s", cmd);
system(cmd);
return NULL;
}
static void runcmd(const char *cmd)
{
if (empty_string(cmd))
return;
pthread_t pth;
pthread_create(&pth, NULL, cmd_thread, (void*)cmd);
}
/****************************************************
* Event list functions
****************************************************/
//find an event by event_type
static event_t *get_event(const char *event_type)
{
event_t *p = events;
while (p != NULL)
{
if(!strcasecmp(p->event_type, event_type))
return p;
p = p->next;
}
return NULL;
}
// add event to the list
static event_t *add_event(unsigned int id)
{
event_t *event;
// allocate memory
if (!(event = (event_t *)malloc(sizeof(event_t))))
quit(1, "malloc() failed in add_event()");
// set defaults
event->id = id;
event->event_type = "";
event->runcmd = "";
event->reboot = false;
event->reboot_delay = 0;
event->quit = false;
event->quit_msg = "";
event->prev = event->next = NULL;
// first event?
if(events == NULL)
{
events = event;
last_event = event;
}
// no, append to the list
else
{
last_event->next = event;
event->prev = last_event;
last_event = event;
}
return event;
}
// remove event from the list
static void remove_event(event_t *event)
{
// only event?
if(event == events && event == last_event)
events = last_event = NULL;
// first event?
else if(event == events)
{
event->next->prev = NULL;
events = event->next;
}
// last event?
else if(event == last_event)
{
event->prev->next = NULL;
last_event = event->prev;
}
// in the middle
else
{
event->prev->next = event->next;
event->next->prev = event->prev;
}
// free memory
free(event);
}
#ifndef EVENT_ADD_CHECK
#define EVENT_ADD_CHECK if (!last_event || (last_event->id != json_array_index)) add_event(json_array_index);
#endif
/********************************************
* Config functions
*********************************************/
char *set_event_type(const char *event_type)
{
event_t *event;
// make sure event type doesn't already exist
if ((event = get_event(event_type)) != NULL)
return NULL;
EVENT_ADD_CHECK;
last_event->event_type = event_type;
return NULL;
}
char *set_event_runcmd(const char *cmd)
{
EVENT_ADD_CHECK;
last_event->runcmd = cmd;
return NULL;
}
char *set_event_reboot(const char *arg)
{
EVENT_ADD_CHECK;
if (empty_string(arg))
return NULL;
last_event->reboot = strtobool(arg);
applog(LOG_NOTICE, "Event %s reboot = %s", last_event->event_type, ((last_event->reboot)?"true":"false"));
return NULL;
}
char *set_event_reboot_delay(const char *delay)
{
EVENT_ADD_CHECK;
last_event->reboot_delay = atoi(delay);
// if the reboot delay is greater than 0 seconds, automatically turn on reboot
if (last_event->reboot_delay > 0)
last_event->reboot = true;
return NULL;
}
char *set_event_quit(const char *arg)
{
EVENT_ADD_CHECK;
if (empty_string(arg))
return NULL;
last_event->quit = strtobool(arg);
applog(LOG_DEBUG, "Event %s quit = %s", last_event->event_type, ((last_event->quit)?"true":"false"));
return NULL;
}
char *set_event_quit_message(const char *msg)
{
EVENT_ADD_CHECK;
last_event->quit_msg = msg;
// if the quit message is set, automatically turn on quit
if (!empty_string(last_event->quit_msg))
last_event->quit = true;
return NULL;
}
/******************************************
* Event functions
*******************************************/
void event_notify(const char *event_type)
{
event_t *event;
// find an event of the specified type
if ((event = get_event(event_type)) == NULL)
return;
applog(LOG_DEBUG, "Executing event %s", event_type);
// run command if defined
if (!empty_string(event->runcmd))
runcmd(event->runcmd);
// reboot if set
if (event->reboot == true)
{
//wait specified amount of time
if (event->reboot_delay > 0)
{
applog(LOG_NOTICE, "waiting %d to reboot", event->reboot_delay);
sleep(event->reboot_delay);
}
#ifdef WIN32
runcmd("shutdown /r /t 0");
#else
applog(LOG_NOTICE, "running shutdown -r now");
runcmd("/sbin/shutdown -r now");
#endif
}
// quit sgminer if set
if (event->quit == true)
quit(0, ((empty_string(event->quit_msg))?event_type:event->quit_msg));
}

23
events.h

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
#ifndef EVENTS_H
#define EVENTS_H
typedef struct event {
unsigned int id;
const char *event_type;
const char *runcmd;
bool reboot;
unsigned int reboot_delay;
bool quit;
const char *quit_msg;
struct event *prev, *next;
} event_t;
extern char *set_event_type(const char *event_type);
extern char *set_event_runcmd(const char *cmd);
extern char *set_event_reboot(const char *arg);
extern char *set_event_reboot_delay(const char *delay);
extern char *set_event_quit(const char *arg);
extern char *set_event_quit_message(const char *msg);
extern void event_notify(const char *event_type);
#endif /* EVENTS_H */

36
sgminer.c

@ -59,6 +59,7 @@ char *curly = ":D"; @@ -59,6 +59,7 @@ char *curly = ":D";
#include "algorithm.h"
#include "pool.h"
#include "config_parser.h"
#include "events.h"
#if defined(unix) || defined(__APPLE__)
#include <errno.h>
@ -1378,6 +1379,27 @@ struct opt_table opt_config_table[] = { @@ -1378,6 +1379,27 @@ struct opt_table opt_config_table[] = {
OPT_WITH_ARG("--expiry|-E",
set_int_0_to_9999, opt_show_intval, &opt_expiry,
"Upper bound on how many seconds after getting work we consider a share from it stale"),
// event options
OPT_WITH_ARG("--event-on",
set_event_type, NULL, NULL,
"Select event type to perform task on"),
OPT_WITH_ARG("--event-runcmd",
set_event_runcmd, NULL, NULL,
"Command to perform on event"),
OPT_WITH_ARG("--event-reboot",
set_event_reboot, NULL, NULL,
"Reboot the system on event"),
OPT_WITH_ARG("--event-reboot-delay",
set_event_reboot_delay, NULL, NULL,
"Delay in seconds to wait before rebooting"),
OPT_WITH_ARG("--event-quit",
set_event_quit, NULL, NULL,
"Quit sgminer on event"),
OPT_WITH_ARG("--event-quit-message",
set_event_quit_message, NULL, NULL,
"Quit message when quitting sgminer on event"),
OPT_WITHOUT_ARG("--failover-only",
opt_set_bool, &opt_fail_only,
"Don't leak work to backup pools when primary pool is lagging"),
@ -1776,6 +1798,10 @@ struct opt_table opt_config_table[] = { @@ -1776,6 +1798,10 @@ struct opt_table opt_config_table[] = {
opt_set_bool, NULL, NULL, opt_hidden),
OPT_WITH_ARG("--profiles",
opt_set_bool, NULL, NULL, opt_hidden),
OPT_WITH_ARG("--includes",
opt_set_bool, NULL, NULL, opt_hidden),
OPT_WITH_ARG("--events",
opt_set_bool, NULL, NULL, opt_hidden),
OPT_WITH_ARG("--difficulty-multiplier",
set_difficulty_multiplier, NULL, NULL,
"(deprecated) Difficulty multiplier for jobs received from stratum pools"),
@ -5838,6 +5864,7 @@ static struct work *hash_pop(bool blocking) @@ -5838,6 +5864,7 @@ static struct work *hash_pop(bool blocking)
if (rc && !no_work) {
no_work = true;
applog(LOG_WARNING, "Waiting for work to be available from pools.");
event_notify("idle");
}
} while (!HASH_COUNT(staged_work));
}
@ -7019,6 +7046,7 @@ static void hash_sole_work(struct thr_info *mythr) @@ -7019,6 +7046,7 @@ static void hash_sole_work(struct thr_info *mythr)
applog(LOG_ERR, "%s %d failure, disabling!", drv->name, cgpu->device_id);
cgpu->deven = DEV_DISABLED;
dev_error(cgpu, REASON_THREAD_ZERO_HASH);
event_notify("idle");
cgpu->shutdown = true;
break;
}
@ -7516,6 +7544,11 @@ static void *watchdog_thread(void __maybe_unused *userdata) @@ -7516,6 +7544,11 @@ static void *watchdog_thread(void __maybe_unused *userdata)
cgtime(&now);
// check last getwork time if greater than 10 mins, declare idle...
if ((time(NULL) - last_getwork) >= 600) {
event_notify("idle");
}
if (!sched_paused && !should_run()) {
applog(LOG_WARNING, "Pausing execution as per stop time %02d:%02d scheduled",
schedstop.tm.tm_hour, schedstop.tm.tm_min);
@ -7594,6 +7627,8 @@ static void *watchdog_thread(void __maybe_unused *userdata) @@ -7594,6 +7627,8 @@ static void *watchdog_thread(void __maybe_unused *userdata)
cgtime(&thr->sick);
dev_error(cgpu, REASON_DEV_SICK_IDLE_60);
event_notify("gpu_sick");
#ifdef HAVE_ADL
if (adl_active && cgpu->has_adl && gpu_activity(gpu) > 50) {
applog(LOG_ERR, "GPU still showing activity suggesting a hard hang.");
@ -7610,6 +7645,7 @@ static void *watchdog_thread(void __maybe_unused *userdata) @@ -7610,6 +7645,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
cgtime(&thr->sick);
dev_error(cgpu, REASON_DEV_DEAD_IDLE_600);
event_notify("gpu_dead");
} else if (now.tv_sec - thr->sick.tv_sec > 60 &&
(cgpu->status == LIFE_SICK || cgpu->status == LIFE_DEAD)) {
/* Attempt to restart a GPU that's sick or dead once every minute */

2
winbuild/sgminer.vcxproj

@ -275,6 +275,7 @@ @@ -275,6 +275,7 @@
<ClCompile Include="..\algorithm\darkcoin.c" />
<ClCompile Include="..\config_parser.c" />
<ClCompile Include="..\driver-opencl.c" />
<ClCompile Include="..\events.c" />
<ClCompile Include="..\findnonce.c" />
<ClCompile Include="..\algorithm\fuguecoin.c" />
<ClCompile Include="..\algorithm\groestlcoin.c" />
@ -335,6 +336,7 @@ @@ -335,6 +336,7 @@
<ClInclude Include="..\config_parser.h" />
<ClInclude Include="..\driver-opencl.h" />
<ClInclude Include="..\elist.h" />
<ClInclude Include="..\events.h" />
<ClInclude Include="..\findnonce.h" />
<ClInclude Include="..\algorithm\fuguecoin.h" />
<ClInclude Include="..\algorithm\groestlcoin.h" />

6
winbuild/sgminer.vcxproj.filters

@ -200,6 +200,9 @@ @@ -200,6 +200,9 @@
<ClCompile Include="..\algorithm\neoscrypt.c">
<Filter>Source Files\algorithm</Filter>
</ClCompile>
<ClCompile Include="..\events.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\adl.h">
@ -379,6 +382,9 @@ @@ -379,6 +382,9 @@
<ClInclude Include="..\algorithm\neoscrypt.h">
<Filter>Header Files\algorithm</Filter>
</ClInclude>
<ClInclude Include="..\events.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="README.txt" />

Loading…
Cancel
Save