Browse Source

Refactoring of timeout reaction. Some preparations for watchdog implementation.

git-svn-id: https://klish.googlecode.com/svn/trunk@496 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 12 years ago
parent
commit
4376b117de

+ 22 - 9
Makefile.in

@@ -215,6 +215,7 @@ am_libclish_la_OBJECTS = clish/libclish_la-callback_access.lo \
 	clish/shell/libclish_la-shell_file.lo \
 	clish/shell/libclish_la-shell_spawn.lo \
 	clish/shell/libclish_la-shell_startup.lo \
+	clish/shell/libclish_la-shell_wdog.lo \
 	clish/shell/libclish_la-shell_pwd.lo \
 	clish/shell/libclish_la-shell_tinyrl.lo \
 	clish/shell/shell_tinyxml.lo clish/view/libclish_la-view.lo \
@@ -727,15 +728,15 @@ libclish_la_SOURCES = clish/callback_access.c clish/callback_script.c \
 	clish/shell/shell_help.c clish/shell/shell_new.c \
 	clish/shell/shell_parse.c clish/shell/shell_file.c \
 	clish/shell/shell_spawn.c clish/shell/shell_startup.c \
-	clish/shell/shell_pwd.c clish/shell/shell_tinyrl.c \
-	clish/shell/shell_tinyxml.cpp clish/shell/private.h \
-	clish/view/view.c clish/view/view_dump.c clish/view/private.h \
-	clish/nspace/nspace.c clish/nspace/nspace_dump.c \
-	clish/nspace/private.h clish/var/var.c clish/var/var_dump.c \
-	clish/var/private.h clish/action/action.c \
-	clish/action/action_dump.c clish/action/private.h \
-	clish/config/config.c clish/config/config_dump.c \
-	clish/config/private.h
+	clish/shell/shell_wdog.c clish/shell/shell_pwd.c \
+	clish/shell/shell_tinyrl.c clish/shell/shell_tinyxml.cpp \
+	clish/shell/private.h clish/view/view.c clish/view/view_dump.c \
+	clish/view/private.h clish/nspace/nspace.c \
+	clish/nspace/nspace_dump.c clish/nspace/private.h \
+	clish/var/var.c clish/var/var_dump.c clish/var/private.h \
+	clish/action/action.c clish/action/action_dump.c \
+	clish/action/private.h clish/config/config.c \
+	clish/config/config_dump.c clish/config/private.h
 libclish_la_CFLAGS = @LUB_CFLAGS@ @LUBHEAP_CFLAGS@ $(DEBUG_CFLAGS)
 libclish_la_LIBADD = \
 	liblub.la \
@@ -1035,6 +1036,8 @@ clish/shell/libclish_la-shell_spawn.lo: clish/shell/$(am__dirstamp) \
 	clish/shell/$(DEPDIR)/$(am__dirstamp)
 clish/shell/libclish_la-shell_startup.lo: clish/shell/$(am__dirstamp) \
 	clish/shell/$(DEPDIR)/$(am__dirstamp)
+clish/shell/libclish_la-shell_wdog.lo: clish/shell/$(am__dirstamp) \
+	clish/shell/$(DEPDIR)/$(am__dirstamp)
 clish/shell/libclish_la-shell_pwd.lo: clish/shell/$(am__dirstamp) \
 	clish/shell/$(DEPDIR)/$(am__dirstamp)
 clish/shell/libclish_la-shell_tinyrl.lo: clish/shell/$(am__dirstamp) \
@@ -1665,6 +1668,8 @@ mostlyclean-compile:
 	-rm -f clish/shell/libclish_la-shell_var.lo
 	-rm -f clish/shell/libclish_la-shell_view.$(OBJEXT)
 	-rm -f clish/shell/libclish_la-shell_view.lo
+	-rm -f clish/shell/libclish_la-shell_wdog.$(OBJEXT)
+	-rm -f clish/shell/libclish_la-shell_wdog.lo
 	-rm -f clish/shell/shell_tinyxml.$(OBJEXT)
 	-rm -f clish/shell/shell_tinyxml.lo
 	-rm -f clish/var/libclish_la-var.$(OBJEXT)
@@ -1967,6 +1972,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_tinyrl.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_var.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_view.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_wdog.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/shell_tinyxml.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/var/$(DEPDIR)/libclish_la-var.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/var/$(DEPDIR)/libclish_la-var_dump.Plo@am__quote@
@@ -2294,6 +2300,13 @@ clish/shell/libclish_la-shell_startup.lo: clish/shell/shell_startup.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -c -o clish/shell/libclish_la-shell_startup.lo `test -f 'clish/shell/shell_startup.c' || echo '$(srcdir)/'`clish/shell/shell_startup.c
 
+clish/shell/libclish_la-shell_wdog.lo: clish/shell/shell_wdog.c
+@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -MT clish/shell/libclish_la-shell_wdog.lo -MD -MP -MF clish/shell/$(DEPDIR)/libclish_la-shell_wdog.Tpo -c -o clish/shell/libclish_la-shell_wdog.lo `test -f 'clish/shell/shell_wdog.c' || echo '$(srcdir)/'`clish/shell/shell_wdog.c
+@am__fastdepCC_TRUE@	$(am__mv) clish/shell/$(DEPDIR)/libclish_la-shell_wdog.Tpo clish/shell/$(DEPDIR)/libclish_la-shell_wdog.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='clish/shell/shell_wdog.c' object='clish/shell/libclish_la-shell_wdog.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -c -o clish/shell/libclish_la-shell_wdog.lo `test -f 'clish/shell/shell_wdog.c' || echo '$(srcdir)/'`clish/shell/shell_wdog.c
+
 clish/shell/libclish_la-shell_pwd.lo: clish/shell/shell_pwd.c
 @am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -MT clish/shell/libclish_la-shell_pwd.lo -MD -MP -MF clish/shell/$(DEPDIR)/libclish_la-shell_pwd.Tpo -c -o clish/shell/libclish_la-shell_pwd.lo `test -f 'clish/shell/shell_pwd.c' || echo '$(srcdir)/'`clish/shell/shell_pwd.c
 @am__fastdepCC_TRUE@	$(am__mv) clish/shell/$(DEPDIR)/libclish_la-shell_pwd.Tpo clish/shell/$(DEPDIR)/libclish_la-shell_pwd.Plo

+ 15 - 0
clish.xsd

@@ -17,6 +17,7 @@
     <xs:element name="NAMESPACE" type="namespace_t"/>
     <xs:element name="CONFIG" type="config_t"/>
     <xs:element name="VAR" type="var_t"/>
+    <xs:element name="WATCHDOG" type="wdog_t"/>
 
     <!--
 ***********************************************************
@@ -463,4 +464,18 @@
         <xs:attribute name="dynamic" type="bool_t" use="optional" default="false"/>
     </xs:complexType>
 
+<!--
+*******************************************************
+* <WATCHDOG> is used to recover system after errors.
+*
+********************************************************
+-->
+    <xs:complexType name="wdog_t">
+        <xs:sequence>
+            <xs:element ref="ACTION" minOccurs="1"/>
+        </xs:sequence>
+        <xs:attribute name="timeout" type="xs:string" use="required"/>
+    </xs:complexType>
+
+
 </xs:schema>

+ 4 - 0
clish/shell.h

@@ -348,6 +348,10 @@ char *clish_shell__get_full_line(clish_context_t *context);
 char *clish_shell__get_params(clish_context_t *context);
 void clish_shell__set_log(clish_shell_t *instance, bool_t log);
 bool_t clish_shell__get_log(const clish_shell_t *instance);
+int clish_shell_wdog(clish_shell_t *instance);
+void clish_shell__set_wdog_timeout(clish_shell_t *instance,
+	unsigned int timeout);
+unsigned int clish_shell__get_wdog_timeout(const clish_shell_t *instance);
 
 _END_C_DECL
 

+ 1 - 0
clish/shell/module.am

@@ -11,6 +11,7 @@ libclish_la_SOURCES += \
 	clish/shell/shell_file.c \
 	clish/shell/shell_spawn.c \
 	clish/shell/shell_startup.c \
+	clish/shell/shell_wdog.c \
 	clish/shell/shell_pwd.c \
 	clish/shell/shell_tinyrl.c \
 	clish/shell/shell_tinyxml.cpp \

+ 12 - 9
clish/shell/private.h

@@ -40,15 +40,17 @@ struct clish_shell_s {
 	lub_bintree_t view_tree; /* Maintain a tree of views */
 	lub_bintree_t ptype_tree; /* Maintain a tree of ptypes */
 	lub_bintree_t var_tree; /* Maintain a tree of global variables */
-	const clish_shell_hooks_t *client_hooks;	/* Client callback hooks         */
-	void *client_cookie;	/* Client callback cookie        */
-	clish_view_t *global;	/* Reference to the global view. */
-	clish_command_t *startup;	/* This is the startup command   */
-	clish_shell_state_t state;	/* The current state               */
-	char *overview;		/* Overview text for this shell.  */
-	tinyrl_t *tinyrl;	/* Tiny readline instance          */
-	clish_shell_file_t *current_file;	/* file currently in use for input */
-	clish_shell_pwd_t **pwdv;	/* Levels for the config file structure */
+	const clish_shell_hooks_t *client_hooks; /* Client callback hooks */
+	void *client_cookie; /* Client callback cookie */
+	clish_view_t *global; /* Reference to the global view. */
+	clish_command_t *startup; /* This is the startup command */
+	clish_command_t *wdog; /* This is the watchdog command */
+	unsigned int wdog_timeout; /* This is the watchdog timeout */
+	clish_shell_state_t state; /* The current state */
+	char *overview; /* Overview text for this shell */
+	tinyrl_t *tinyrl; /* Tiny readline instance */
+	clish_shell_file_t *current_file; /* file currently in use for input */
+	clish_shell_pwd_t **pwdv; /* Levels for the config file structure */
 	unsigned int pwdc;
 	int depth;
 	konf_client_t *client;
@@ -116,3 +118,4 @@ void clish_shell__expand_viewid(const char *viewid, lub_bintree_t *tree,
 	clish_context_t *context);
 void clish_shell__init_pwd(clish_shell_pwd_t *pwd);
 void clish_shell__fini_pwd(clish_shell_pwd_t *pwd);
+int clish_shell_timeout_fn(tinyrl_t *tinyrl);

+ 6 - 1
clish/shell/shell_new.c

@@ -40,6 +40,8 @@ static void clish_shell_init(clish_shell_t * this,
 	this->client_cookie = cookie;
 	this->global = NULL;
 	this->startup = NULL;
+	this->wdog = NULL;
+	this->wdog_timeout = 0;
 	this->state = SHELL_STATE_INITIALISING;
 	this->overview = NULL;
 	this->tinyrl = clish_shell_tinyrl_new(istream, ostream, 0);
@@ -113,9 +115,12 @@ static void clish_shell_fini(clish_shell_t * this)
 	/* free the textual details */
 	lub_string_free(this->overview);
 
-	/* remove the startup command */
+	/* Remove the startup command */
 	if (this->startup)
 		clish_command_delete(this->startup);
+	/* Remove the watchdog command */
+	if (this->wdog)
+		clish_command_delete(this->wdog);
 	/* clean up the file stack */
 	while (!clish_shell_pop_file(this));
 	/* delete the tinyrl object */

+ 3 - 0
clish/shell/shell_tinyrl.c

@@ -353,6 +353,9 @@ static void clish_shell_tinyrl_init(tinyrl_t * this)
 	/* bind the <SPACE> key to auto-complete if necessary */
 	status = tinyrl_bind_key(this, ' ', clish_shell_tinyrl_key_space);
 	assert(status);
+
+	/* Assign timeout callback */
+	tinyrl__set_timeout_fn(this, clish_shell_timeout_fn);
 }
 
 /*-------------------------------------------------------- */

+ 27 - 1
clish/shell/shell_tinyxml.cpp

@@ -38,7 +38,8 @@ static PROCESS_FN
 	process_detail,
 	process_namespace,
 	process_config,
-	process_var;
+	process_var,
+	process_wdog;
 
 static clish_xml_cb_t xml_elements[] = {
 	{"CLISH_MODULE", process_clish_module},
@@ -53,6 +54,7 @@ static clish_xml_cb_t xml_elements[] = {
 	{"NAMESPACE", process_namespace},
 	{"CONFIG", process_config},
 	{"VAR", process_var},
+	{"WATCHDOG", process_wdog},
 	{NULL, NULL}
 };
 
@@ -696,6 +698,30 @@ static void process_var(clish_shell_t * shell, TiXmlElement * element, void *)
 	process_children(shell, element, var);
 }
 
+///////////////////////////////////////
+static void process_wdog(clish_shell_t *shell,
+	TiXmlElement *element, void *parent)
+{
+	clish_view_t *v = (clish_view_t *)parent;
+	clish_command_t *cmd = NULL;
+	const char *timeout = element->Attribute("timeout");
+
+	assert(!shell->wdog);
+	assert(timeout);
+
+	/* create a command with NULL help */
+	cmd = clish_view_new_command(v, "watchdog", NULL);
+	clish_command__set_lock(cmd, BOOL_FALSE);
+
+	/* Set watchdog timeout */
+	clish_shell__set_wdog_timeout(shell, atoi(timeout));
+
+	/* Remember this command */
+	shell->wdog = cmd;
+
+	process_children(shell, element, cmd);
+}
+
 ///////////////////////////////////////
 int clish_shell_xml_read(clish_shell_t * shell, const char *filename)
 {

+ 46 - 0
clish/shell/shell_wdog.c

@@ -0,0 +1,46 @@
+/*
+ * shell_startup.c
+ */
+#include "private.h"
+#include <assert.h>
+
+#include "tinyrl/tinyrl.h"
+#include "lub/string.h"
+
+/*----------------------------------------------------------------------- */
+int clish_shell_timeout_fn(tinyrl_t *this)
+{
+	tinyrl_crlf(this);
+	fprintf(stderr, "Warning: Activity timeout. The session will be closed.\n");
+	/* Return -1 to close session on timeout */
+	return -1;
+}
+
+/*----------------------------------------------------------- */
+int clish_shell_wdog(clish_shell_t *this)
+{
+	clish_context_t context;
+
+	assert(this->wdog);
+
+	context.shell = this;
+	context.cmd = this->wdog;
+	context.pargv = NULL;
+
+	/* Call watchdog script */
+	return clish_shell_execute(&context, NULL);
+}
+
+/*----------------------------------------------------------- */
+void clish_shell__set_wdog_timeout(clish_shell_t *this, unsigned int timeout)
+{
+	assert(this);
+	this->wdog_timeout = timeout;
+}
+
+/*----------------------------------------------------------- */
+unsigned int clish_shell__get_wdog_timeout(const clish_shell_t *this)
+{
+	assert(this);
+	return this->wdog_timeout;
+}

+ 1 - 0
tinyrl/private.h

@@ -18,6 +18,7 @@ struct _tinyrl {
 	unsigned point;
 	unsigned end;
 	tinyrl_completion_func_t *attempted_completion_function;
+	tinyrl_timeout_fn_t *timeout_fn; /* timeout callback */
 	int state;
 #define RL_STATE_COMPLETING (0x00000001)
 	char *kill_string;

+ 20 - 3
tinyrl/tinyrl.c

@@ -108,6 +108,13 @@ static void changed_line(tinyrl_t * this)
 	}
 }
 
+/*----------------------------------------------------------------------- */
+static int tinyrl_timeout_default(tinyrl_t *this)
+{
+	/* Return -1 to close session on timeout */
+	return -1;
+}
+
 /*----------------------------------------------------------------------- */
 static bool_t tinyrl_key_default(tinyrl_t * this, int key)
 {
@@ -445,6 +452,7 @@ tinyrl_init(tinyrl_t * this,
 	this->point = 0;
 	this->end = 0;
 	this->attempted_completion_function = complete_fn;
+	this->timeout_fn = tinyrl_timeout_default;
 	this->state = 0;
 	this->kill_string = NULL;
 	this->echo_char = '\0';
@@ -638,7 +646,7 @@ static char *internal_readline(tinyrl_t * this,
 	const char *prompt, void *context, const char *str)
 {
 	FILE *istream = tinyrl_vt100__get_istream(this->term);
-	int crlf = 1;		/* Enable crlf if result is NULL */
+	int crlf = 1; /* Enable crlf if result is NULL */
 	char *result = NULL;
 	int lerrno = 0;
 
@@ -662,7 +670,7 @@ static char *internal_readline(tinyrl_t * this,
 			/* get a key */
 			key = tinyrl_getchar(this);
 			/* has the input stream terminated? */
-			if (EOF != key) {
+			if (key >= 0) { /* Real key pressed */
 				/* call the handler for this key */
 				if (!this->handlers[key](this, key))
 					tinyrl_ding(this);
@@ -683,7 +691,10 @@ static char *internal_readline(tinyrl_t * this,
 						(UTF8_11 == (key & UTF8_MASK))))
 						tinyrl_redisplay(this);
 				}
-			} else {
+			} else { /* Error || EOF || Timeout */
+				if ((VT100_TIMEOUT == key) &&
+					!this->timeout_fn(this))
+					continue;
 				/* time to finish the session */
 				this->done = BOOL_TRUE;
 				this->line = NULL;
@@ -1303,6 +1314,12 @@ void tinyrl__set_timeout(tinyrl_t *this, int timeout)
 	tinyrl_vt100__set_timeout(this->term, timeout);
 }
 
+void tinyrl__set_timeout_fn(tinyrl_t *this,
+	tinyrl_timeout_fn_t *fn)
+{
+	this->timeout_fn = fn;
+}
+
 /*-------------------------------------------------------- */
 bool_t tinyrl_is_quoting(const tinyrl_t * this)
 {

+ 5 - 0
tinyrl/tinyrl.h

@@ -55,6 +55,9 @@ typedef int tinyrl_hook_func_t(tinyrl_t * instance);
 
 typedef char **tinyrl_completion_func_t(tinyrl_t * instance,
 	const char *text, unsigned start, unsigned end);
+
+typedef int tinyrl_timeout_fn_t(tinyrl_t *instance);
+
 /**
  * \return
  * - BOOL_TRUE if the action associated with the key has
@@ -109,6 +112,8 @@ extern bool_t tinyrl__get_utf8(const tinyrl_t * instance);
 extern void tinyrl__set_utf8(tinyrl_t * instance, bool_t utf8);
 
 extern void tinyrl__set_timeout(tinyrl_t *instance, int timeout);
+extern void tinyrl__set_timeout_fn(tinyrl_t *instance,
+	tinyrl_timeout_fn_t *fn);
 
 extern char *tinyrl_readline(tinyrl_t * instance,
 			     const char *prompt, void *context);

+ 5 - 0
tinyrl/vt100.h

@@ -80,6 +80,11 @@ typedef enum {
 	tinyrl_vt100_PGDOWN /**< No action at the moment */
 } tinyrl_vt100_escape_t;
 
+/* Return values from vt100_getchar() */
+#define VT100_EOF	-1
+#define VT100_TIMEOUT	-2
+#define VT100_ERR	-3
+
 extern tinyrl_vt100_t *tinyrl_vt100_new(FILE * instream, FILE * outstream);
 extern void tinyrl_vt100_delete(tinyrl_vt100_t * instance);
 

+ 17 - 8
tinyrl/vt100/vt100.c

@@ -8,6 +8,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/select.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -137,10 +138,13 @@ int tinyrl_vt100_getchar(const tinyrl_vt100_t *this)
 
 	/* Just wait for the input if no timeout */
 	if (this->timeout <= 0) {
-		res = read(istream_fd, &c, 1);
-		/* End of file */
+		while (((res = read(istream_fd, &c, 1)) < 0) &&
+			(EAGAIN == errno));
+		/* EOF or error */
+		if (res < 0)
+			return VT100_ERR;
 		if (!res)
-			return EOF;
+			return VT100_EOF;
 		return c;
 	}
 
@@ -149,15 +153,20 @@ int tinyrl_vt100_getchar(const tinyrl_vt100_t *this)
 	FD_SET(istream_fd, &rfds);
 	tv.tv_sec = this->timeout;
 	tv.tv_usec = 0;
-	retval = select(istream_fd + 1, &rfds, NULL, NULL, &tv);
+	while (((retval = select(istream_fd + 1, &rfds, NULL, NULL, &tv)) < 0) &&
+		(EAGAIN == errno));
 	/* Error or timeout */
-	if (retval <= 0)
-		return EOF;
+	if (retval < 0)
+		return VT100_ERR;
+	if (!retval)
+		return VT100_TIMEOUT;
 
 	res = read(istream_fd, &c, 1);
-	/* End of file */
+	/* EOF or error */
+	if (res < 0)
+		return VT100_ERR;
 	if (!res)
-		return EOF;
+		return VT100_EOF;
 
 	return c;
 }