* Changed signal handling
* Moved clixon-proc sigchild handling from handler to clixon_events
This commit is contained in:
parent
dea3962cc0
commit
7762b10cbb
16 changed files with 268 additions and 126 deletions
|
|
@ -53,6 +53,8 @@ Developers may need to change their code
|
|||
|
||||
### Minor features
|
||||
|
||||
* Changed signal handling
|
||||
* Moved clixon-proc sigchild handling from handler to clixon_events
|
||||
* The base capability has been changed to "urn:ietf:params:netconf:base:1.1" following RFC6241.
|
||||
* Made a separate Clixon datastore XML/JSON top-level symbol
|
||||
* Replaces the hardcoded "config" keyword.
|
||||
|
|
|
|||
|
|
@ -166,13 +166,8 @@ backend_sig_term(int arg)
|
|||
static void
|
||||
backend_sig_child(int arg)
|
||||
{
|
||||
int status;
|
||||
int pid;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((pid = waitpid(-1, &status, 0)) != -1 && WIFEXITED(status)){
|
||||
}
|
||||
clicon_sig_ignore_set(1);
|
||||
clicon_sig_child_set(1);
|
||||
}
|
||||
|
||||
/*! Create backend server socket and register callback
|
||||
|
|
@ -1038,7 +1033,7 @@ main(int argc,
|
|||
goto done;
|
||||
if (stream_timer_setup(0, h) < 0)
|
||||
goto done;
|
||||
if (clixon_event_loop() < 0)
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
|
|
|
|||
|
|
@ -873,7 +873,7 @@ main(int argc,
|
|||
if (clixon_event_reg_timeout(t, timeout_fn, NULL, "timeout") < 0)
|
||||
goto done;
|
||||
}
|
||||
if (clixon_event_loop() < 0)
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -256,6 +256,7 @@ restconf_terminate(clicon_handle h)
|
|||
xpath_optimize_exit();
|
||||
restconf_handle_exit(h);
|
||||
clicon_log_exit();
|
||||
clicon_debug(1, "%s done", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,17 +160,6 @@ restconf_sig_term(int arg)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
static void
|
||||
restconf_sig_child(int arg)
|
||||
{
|
||||
int status;
|
||||
int pid;
|
||||
|
||||
if ((pid = waitpid(-1, &status, 0)) != -1 && WIFEXITED(status)){
|
||||
}
|
||||
clicon_sig_ignore_set(1);
|
||||
}
|
||||
|
||||
static char*
|
||||
evhtp_method2str(enum htp_method m)
|
||||
{
|
||||
|
|
@ -1286,11 +1275,6 @@ main(int argc,
|
|||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
goto done;
|
||||
}
|
||||
if (set_signal(SIGCHLD, restconf_sig_child, NULL) < 0){
|
||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Find and read configfile */
|
||||
if (clicon_options_main(h) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@
|
|||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <libgen.h>
|
||||
|
|
@ -146,9 +145,13 @@ restconf_sig_term(int arg)
|
|||
restconf_terminate(_CLICON_HANDLE);
|
||||
}
|
||||
clicon_exit_set(); /* checked in clixon_event_loop() */
|
||||
clicon_debug(1, "%s done", __FUNCTION__);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/*! Reap stream child
|
||||
* XXX The -1 should be changed to proper pid, see eg clixon_process_waitpid
|
||||
*/
|
||||
static void
|
||||
restconf_sig_child(int arg)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ api_stream(clicon_handle h,
|
|||
/* Poll upstream errors */
|
||||
stream_timeout(0, req);
|
||||
/* Start loop */
|
||||
clixon_event_loop();
|
||||
clixon_event_loop(h);
|
||||
close(s);
|
||||
clixon_event_unreg_fd(s, restconf_stream_cb);
|
||||
clixon_event_unreg_fd(rfcgi->listen_sock,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ int clicon_exit_reset(void);
|
|||
|
||||
int clicon_exit_get(void);
|
||||
|
||||
int clicon_sig_child_set(int val);
|
||||
|
||||
int clicon_sig_child_get(void);
|
||||
|
||||
int clicon_sig_ignore_set(int val);
|
||||
|
||||
int clicon_sig_ignore_get(void);
|
||||
|
|
@ -64,7 +68,7 @@ int clixon_event_unreg_timeout(int (*fn)(int, void*), void *arg);
|
|||
|
||||
int clixon_event_poll(int fd);
|
||||
|
||||
int clixon_event_loop(void);
|
||||
int clixon_event_loop(clicon_handle h);
|
||||
|
||||
int clixon_event_exit(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,5 +67,6 @@ int clixon_process_delete_all(clicon_handle h);
|
|||
int clixon_process_operation(clicon_handle h, const char *name, proc_operation op, const int wrapit, uint32_t *pid);
|
||||
int clixon_process_start_all(clicon_handle h);
|
||||
int clixon_process_sched_register(clicon_handle h);
|
||||
int clixon_process_waitpid(clicon_handle h);
|
||||
|
||||
#endif /* _CLIXON_PROC_H_ */
|
||||
|
|
|
|||
|
|
@ -54,8 +54,11 @@
|
|||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_sig.h"
|
||||
#include "clixon_proc.h"
|
||||
#include "clixon_event.h"
|
||||
|
||||
/*
|
||||
|
|
@ -89,6 +92,9 @@ static int _ee_unreg = 0;
|
|||
/* If set (eg by signal handler) exit select loop on next run and return 0 */
|
||||
static int _clicon_exit = 0;
|
||||
|
||||
/* If set (eg by signal handler) call waitpid on waiting processes, ignore EINTR, continue select loop */
|
||||
static int _clicon_sig_child = 0;
|
||||
|
||||
/* If set (eg by signal handler) ignore EINTR and continue select loop */
|
||||
static int _clicon_sig_ignore = 0;
|
||||
|
||||
|
|
@ -121,6 +127,19 @@ clicon_exit_get(void)
|
|||
return _clicon_exit;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_sig_child_set(int val)
|
||||
{
|
||||
_clicon_sig_child = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_sig_child_get(void)
|
||||
{
|
||||
return _clicon_sig_child;
|
||||
}
|
||||
|
||||
int
|
||||
clicon_sig_ignore_set(int val)
|
||||
{
|
||||
|
|
@ -308,7 +327,7 @@ clixon_event_poll(int fd)
|
|||
* @retval -1 Error: eg select, callback, timer,
|
||||
*/
|
||||
int
|
||||
clixon_event_loop(void)
|
||||
clixon_event_loop(clicon_handle h)
|
||||
{
|
||||
struct event_data *e;
|
||||
struct event_data *e_next;
|
||||
|
|
@ -321,6 +340,12 @@ clixon_event_loop(void)
|
|||
|
||||
while (!clicon_exit_get()){
|
||||
FD_ZERO(&fdset);
|
||||
if (clicon_sig_child_get()){
|
||||
/* Go through processes and wait for child processes */
|
||||
if (clixon_process_waitpid(h) < 0)
|
||||
goto err;
|
||||
clicon_sig_child_set(0);
|
||||
}
|
||||
for (e=ee; e; e=e->e_next)
|
||||
if (e->e_type == EVENT_FD)
|
||||
FD_SET(e->e_fd, &fdset);
|
||||
|
|
@ -342,7 +367,9 @@ clixon_event_loop(void)
|
|||
* (1) Signals that exit gracefully, the function returns 0
|
||||
* Must be registered such as by set_signal() of SIGTERM,SIGINT, etc with a handler that calls
|
||||
* clicon_exit_set().
|
||||
* (2) Signals that are ignored, and the select is rerun, eg SIGCHLD if handler calls clicon_sig_ignore()
|
||||
* (2) SIGCHILD Childs that exit(), go through clixon_proc list and cal waitpid
|
||||
* New select loop is called
|
||||
* (2) Signals are ignored, and the select is rerun, ie handler calls clicon_sig_ignore_get
|
||||
* New select loop is called
|
||||
* (3) Other signals result in an error and return -1.
|
||||
*/
|
||||
|
|
@ -351,6 +378,13 @@ clixon_event_loop(void)
|
|||
clicon_err(OE_EVENTS, errno, "select");
|
||||
retval = 0;
|
||||
}
|
||||
else if (clicon_sig_child_get()){
|
||||
/* Go through processes and wait for child processes */
|
||||
if (clixon_process_waitpid(h) < 0)
|
||||
goto err;
|
||||
clicon_sig_child_set(0);
|
||||
continue;
|
||||
}
|
||||
else if (clicon_sig_ignore_get()){
|
||||
clicon_sig_ignore_set(0);
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -69,9 +69,9 @@
|
|||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_sig.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_queue.h"
|
||||
|
|
@ -83,13 +83,17 @@
|
|||
|
||||
/* Process entry list */
|
||||
struct process_entry_t {
|
||||
qelem_t pe_qelem; /* List header */
|
||||
char *pe_name; /* Name of process used for internal use */
|
||||
char *pe_netns; /* Network namespace */
|
||||
char **pe_argv; /* argv with command as element 0 and NULL-terminated */
|
||||
pid_t pe_pid; /* Running process id (state) or 0 if dead */
|
||||
proc_operation pe_op; /* Operation pending? */
|
||||
proc_cb_t *pe_callback; /* Wrapper function, may be called from process_operation */
|
||||
qelem_t pe_qelem; /* List header */
|
||||
char *pe_name; /* Name of process used for internal use. Unique with exiting=0 */
|
||||
char *pe_netns; /* Network namespace */
|
||||
char **pe_argv; /* argv with command as element 0 and NULL-terminated */
|
||||
int pe_argc; /* Length of argc */
|
||||
pid_t pe_pid; /* Running process id (state) or 0 if dead (pid is set if exiting=1) */
|
||||
int pe_exiting; /* If set process is in the process of dying needs reaping */
|
||||
int pe_clone; /* Duplicate when restarting, delete when reaped */
|
||||
pid_t pe_status; /* Status on exit as defined in waitpid */
|
||||
proc_operation pe_op; /* Operation pending? */
|
||||
proc_cb_t *pe_callback; /* Wrapper function, may be called from process_operation */
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
@ -209,7 +213,7 @@ clixon_proc_background(char **argv,
|
|||
sigset_t oset;
|
||||
struct rlimit rlim = {0, };
|
||||
|
||||
clicon_debug(1, "%s netns:%s", __FUNCTION__, netns);
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (argv == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "argv is NULL");
|
||||
goto quit;
|
||||
|
|
@ -303,6 +307,58 @@ clixon_process_op_str2int(char *opstr)
|
|||
return clicon_str2int(proc_operation_map, opstr);
|
||||
}
|
||||
|
||||
/*! Make a copy of process-entry struct */
|
||||
static int
|
||||
clixon_process_register_dup(process_entry_t *pe0,
|
||||
process_entry_t **pnew)
|
||||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe1 = NULL;
|
||||
int i;
|
||||
|
||||
if (pe0 == NULL){
|
||||
clicon_err(OE_DB, EINVAL, "pe0 is NULL");
|
||||
goto done;
|
||||
}
|
||||
if (pnew == NULL){
|
||||
clicon_err(OE_DB, EINVAL, "pnew is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((pe1 = malloc(sizeof(process_entry_t))) == NULL) {
|
||||
clicon_err(OE_DB, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(pe1, 0, sizeof(*pe1));
|
||||
memcpy(pe1, pe0, sizeof(process_entry_t)); /* Note lots of malloced memory that needs to be handled after this copy*/
|
||||
pe1->pe_exiting = 0;
|
||||
pe1->pe_clone = 0;
|
||||
if ((pe1->pe_name = strdup(pe0->pe_name)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup name");
|
||||
goto done;
|
||||
}
|
||||
if (pe0->pe_netns && (pe1->pe_netns = strdup(pe0->pe_netns)) == NULL){
|
||||
clicon_err(OE_DB, errno, "strdup netns");
|
||||
goto done;
|
||||
}
|
||||
if ((pe1->pe_argv = calloc(pe0->pe_argc, sizeof(char *))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<pe0->pe_argc; i++){
|
||||
if (pe0->pe_argv[i] != NULL &&
|
||||
(pe1->pe_argv[i] = strdup(pe0->pe_argv[i])) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ADDQ(pe1, _proc_entry_list);
|
||||
*pnew = pe1;
|
||||
retval = 0;
|
||||
done:
|
||||
/* dealloc pe1 on error */
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Register an internal process
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
|
|
@ -348,6 +404,7 @@ clixon_process_register(clicon_handle h,
|
|||
clicon_err(OE_DB, errno, "strdup netns");
|
||||
goto done;
|
||||
}
|
||||
pe->pe_argc = argc;
|
||||
if ((pe->pe_argv = calloc(argc, sizeof(char *))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "calloc");
|
||||
goto done;
|
||||
|
|
@ -356,6 +413,7 @@ clixon_process_register(clicon_handle h,
|
|||
if (argv[i] != NULL &&
|
||||
(pe->pe_argv[i] = strdup(argv[i])) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
pe->pe_callback = callback;
|
||||
|
|
@ -365,32 +423,42 @@ clixon_process_register(clicon_handle h,
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
clixon_process_delete_only(process_entry_t *pe)
|
||||
{
|
||||
char **pa;
|
||||
|
||||
if (pe->pe_name)
|
||||
free(pe->pe_name);
|
||||
if (pe->pe_netns)
|
||||
free(pe->pe_netns);
|
||||
if (pe->pe_argv){
|
||||
for (pa = pe->pe_argv; *pa != NULL; pa++){
|
||||
if (*pa)
|
||||
free(*pa);
|
||||
}
|
||||
free(pe->pe_argv);
|
||||
}
|
||||
free(pe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Delete all Upgrade callbacks
|
||||
*/
|
||||
int
|
||||
clixon_process_delete_all(clicon_handle h)
|
||||
{
|
||||
process_entry_t *pe;
|
||||
char **pa;
|
||||
|
||||
while((pe = _proc_entry_list) != NULL) {
|
||||
DELQ(pe, _proc_entry_list, process_entry_t *);
|
||||
if (pe->pe_name)
|
||||
free(pe->pe_name);
|
||||
if (pe->pe_netns)
|
||||
free(pe->pe_netns);
|
||||
if (pe->pe_argv){
|
||||
for (pa = pe->pe_argv; *pa != NULL; pa++){
|
||||
if (*pa)
|
||||
free(*pa);
|
||||
}
|
||||
free(pe->pe_argv);
|
||||
}
|
||||
free(pe);
|
||||
clixon_process_delete_only(pe);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
*/
|
||||
static int
|
||||
proc_op_run(pid_t pid0,
|
||||
int *runp)
|
||||
|
|
@ -401,7 +469,7 @@ proc_op_run(pid_t pid0,
|
|||
|
||||
run = 0;
|
||||
if ((pid = pid0) != 0){ /* if 0 stopped */
|
||||
/* Check if lives */
|
||||
/* Check if alive */
|
||||
run = 1;
|
||||
if ((kill(pid, 0)) < 0){
|
||||
if (errno == ESRCH){
|
||||
|
|
@ -420,49 +488,6 @@ proc_op_run(pid_t pid0,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Perform process operation
|
||||
*
|
||||
* @param[in] op One of: start, stop, restart, status
|
||||
* @param[in] netns Network namespace
|
||||
* @param[in] argv NULL-terminated Argument vector
|
||||
* @param[out] pidp Process-id
|
||||
*/
|
||||
static int
|
||||
clixon_process_operation_one(const proc_operation op,
|
||||
const char *netns,
|
||||
char **argv,
|
||||
const char *name,
|
||||
pid_t *pidp)
|
||||
{
|
||||
int retval = -1;
|
||||
int run = 0;
|
||||
|
||||
/* Check if running */
|
||||
if (proc_op_run(*pidp, &run) < 0)
|
||||
goto done;
|
||||
if (op == PROC_OP_STOP || op == PROC_OP_RESTART){
|
||||
if (run){
|
||||
clicon_log(LOG_NOTICE, "Killing old daemon %s with pid: %d", name, *pidp);
|
||||
kill(*pidp, SIGTERM);
|
||||
}
|
||||
*pidp = 0; /* mark as dead */
|
||||
run = 0;
|
||||
}
|
||||
if (op == PROC_OP_START || op == PROC_OP_RESTART){
|
||||
if (run == 1){
|
||||
; /* Already runs */
|
||||
}
|
||||
else{
|
||||
if (clixon_proc_background(argv, netns, pidp) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s started pid:%d", __FUNCTION__, *pidp);
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Find process operation entry given name and op and perform operation if found
|
||||
*
|
||||
* @param[in] h clicon handle
|
||||
|
|
@ -495,8 +520,11 @@ clixon_process_operation(clicon_handle h,
|
|||
if (wrapit && pe->pe_callback != NULL)
|
||||
if (pe->pe_callback(h, pe, &op) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s name: %s pid:%d op: %s", __FUNCTION__,
|
||||
name, pe->pe_pid, clicon_int2str(proc_operation_map, op));
|
||||
if (op == PROC_OP_START || op == PROC_OP_STOP || op == PROC_OP_RESTART){
|
||||
pe->pe_op = op;
|
||||
clicon_debug(1, "%s scheduling %s pid:%d", __FUNCTION__, name, pe->pe_pid);
|
||||
sched++;
|
||||
}
|
||||
if (pid)
|
||||
|
|
@ -510,7 +538,7 @@ clixon_process_operation(clicon_handle h,
|
|||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(2, "%s retval:%d", __FUNCTION__, retval);
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -558,6 +586,7 @@ clixon_process_start_all(clicon_handle h)
|
|||
* (1) at startup, if started before deamoninization, process will get as child of 1
|
||||
* (2) edit changes or rpc restart especially of restconf where you may saw of your arm and terminate
|
||||
* return socket.
|
||||
* A special complexity is restarting processes, where the old is killed, but state must be kept until it is reaped
|
||||
*/
|
||||
static int
|
||||
clixon_process_sched(int fd,
|
||||
|
|
@ -565,25 +594,68 @@ clixon_process_sched(int fd,
|
|||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe;
|
||||
process_entry_t *pe1;
|
||||
proc_operation op;
|
||||
pid_t newpid;
|
||||
int run;
|
||||
|
||||
clicon_debug(2, "%s",__FUNCTION__);
|
||||
clicon_debug(1, "%s",__FUNCTION__);
|
||||
if (_proc_entry_list == NULL)
|
||||
goto ok;
|
||||
pe = _proc_entry_list;
|
||||
do {
|
||||
if ((op = pe->pe_op) != PROC_OP_NONE){
|
||||
if (clixon_process_operation_one(op, pe->pe_netns, pe->pe_argv, pe->pe_name, &pe->pe_pid) < 0)
|
||||
clicon_debug(1, "%s name: %s pid:%d op: %s", __FUNCTION__,
|
||||
pe->pe_name, pe->pe_pid, clicon_int2str(proc_operation_map, pe->pe_op));
|
||||
/* Execute pending operations and not already exiting */
|
||||
if ((op = pe->pe_op) != PROC_OP_NONE &&
|
||||
pe->pe_exiting == 0){
|
||||
/* Check if running */
|
||||
run = 0;
|
||||
clicon_debug(1, "%s run: %d", __FUNCTION__, run);
|
||||
if (proc_op_run(pe->pe_pid, &run) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s op:%s pid:%d", __FUNCTION__, clicon_int2str(proc_operation_map, op), pe->pe_pid);
|
||||
pe->pe_op = PROC_OP_NONE;
|
||||
switch (op){
|
||||
case PROC_OP_STOP:
|
||||
clicon_debug(1, "%s stop pid:%d", __FUNCTION__, pe->pe_pid);
|
||||
case PROC_OP_RESTART:
|
||||
if (run){
|
||||
clicon_log(LOG_NOTICE, "Killing old process %s with pid: %d", pe->pe_name, pe->pe_pid);
|
||||
kill(pe->pe_pid, SIGTERM);
|
||||
/* Cant wait here because it would block the backend and terminating may involve
|
||||
* some protocol handling, instead SIGCHLD is receoved and
|
||||
* clixon_process_waitpid is called that for waits/reaps the dead process */
|
||||
pe->pe_exiting = 1;
|
||||
}
|
||||
if (op == PROC_OP_STOP)
|
||||
break;
|
||||
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &newpid) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s restart pid:%d -> %d", __FUNCTION__, pe->pe_pid, newpid);
|
||||
/* Create a new pe */
|
||||
if (clixon_process_register_dup(pe, &pe1) < 0)
|
||||
goto done;
|
||||
pe->pe_clone = 1; /* Delete when reaped */
|
||||
pe1->pe_op = PROC_OP_NONE; /* Dont restart again */
|
||||
pe1->pe_pid = newpid;
|
||||
break;
|
||||
case PROC_OP_START:
|
||||
if (run) /* Already runs */
|
||||
break;
|
||||
if (clixon_proc_background(pe->pe_argv, pe->pe_netns, &pe->pe_pid) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s started pid:%d", __FUNCTION__, pe->pe_pid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
pe->pe_op = PROC_OP_NONE;
|
||||
pe = NEXTQ(process_entry_t *, pe);
|
||||
} while (pe != _proc_entry_list);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
clicon_debug(2, "%s retval:%d", __FUNCTION__, retval);
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -602,6 +674,7 @@ clixon_process_sched_register(clicon_handle h)
|
|||
struct timeval t;
|
||||
struct timeval t1 = {0, 1500}; /* See discussion ^*/
|
||||
|
||||
clicon_debug(2, "%s", __FUNCTION__);
|
||||
gettimeofday(&t, NULL);
|
||||
timeradd(&t, &t1, &t);
|
||||
if (clixon_event_reg_timeout(t, clixon_process_sched, h, "process") < 0)
|
||||
|
|
@ -611,3 +684,44 @@ clixon_process_sched_register(clicon_handle h)
|
|||
clicon_debug(2, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Go through processes and wait for child processes
|
||||
* Typically we know a child has been killed by SIGCHLD, but we do not know which process it is
|
||||
* Traverse all known processes and reap them, eg call waitpid() to avoid zombies.
|
||||
* @param[in] h Clixon handle
|
||||
*/
|
||||
int
|
||||
clixon_process_waitpid(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
process_entry_t *pe;
|
||||
int status = 0;
|
||||
pid_t wpid;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
pe = _proc_entry_list;
|
||||
do {
|
||||
if (pe->pe_pid != 0){
|
||||
clicon_debug(1, "%s waitpid(%d)", __FUNCTION__, pe->pe_pid);
|
||||
if ((wpid = waitpid(pe->pe_pid, &status, WNOHANG)) == pe->pe_pid){
|
||||
clicon_debug(1, "%s waitpid(%d) waited", __FUNCTION__, pe->pe_pid);
|
||||
pe->pe_exiting = 0;
|
||||
pe->pe_pid = 0; /* mark as dead */
|
||||
pe->pe_status = status;
|
||||
if (pe->pe_clone){
|
||||
/* Delete it */
|
||||
DELQ(pe, _proc_entry_list, process_entry_t *);
|
||||
clixon_process_delete_only(pe);
|
||||
}
|
||||
break; /* pid is unique */
|
||||
}
|
||||
else
|
||||
clicon_debug(1, "%s waitpid(%d) nomatch:%d", __FUNCTION__, pe->pe_pid, wpid);
|
||||
}
|
||||
pe = NEXTQ(process_entry_t *, pe);
|
||||
} while (pe != _proc_entry_list);
|
||||
retval = 0;
|
||||
// done:
|
||||
clicon_debug(1, "%s retval:%d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,9 +67,9 @@
|
|||
/* clicon */
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_sig.h"
|
||||
|
|
|
|||
|
|
@ -73,10 +73,10 @@
|
|||
#include "clixon_queue.h"
|
||||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_string.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_event.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_io.h"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
# - on enable change, make the state as configured
|
||||
# - No restconf config means enable: false (extra rule)
|
||||
# See test_restconf_netns for network namespaces
|
||||
# XXX Lots of sleeps to remove race conditions. I am sure there are others way to fix this
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
|
@ -62,6 +63,7 @@ function testrpc()
|
|||
operation=$1
|
||||
expectret=$2
|
||||
|
||||
sleep $DEMSLEEP
|
||||
new "send rpc $operation"
|
||||
ret=$($clixon_netconf -qf $cfg<<EOF
|
||||
$DEFAULTHELLO
|
||||
|
|
@ -106,7 +108,7 @@ EOF
|
|||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep $DEMSLEEP
|
||||
echo "$pid" # cant use return that only uses 0-255
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +167,7 @@ wait_restconf
|
|||
new "try restconf rpc status"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{"clixon-lib:input":{"name":"restconf","operation":"status"}}')" 0 "HTTP/1.1 200 OK" '{"clixon-lib:output":{"pid":'
|
||||
|
||||
new "1.1. Get status"
|
||||
new "2. Get status"
|
||||
pid1=$(testrpc status 1)
|
||||
if [ $? -ne 0 ]; then echo "$pid1";exit -1; fi
|
||||
|
||||
|
|
@ -177,7 +179,7 @@ fi
|
|||
new "try restconf rpc restart"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/operations/clixon-lib:process-control -d '{"clixon-lib:input":{"name":"restconf","operation":"restart"}}')" 0 "HTTP/1.1 200 OK" '{"clixon-lib:output":{"pid":'
|
||||
|
||||
new "1.1. Get status"
|
||||
new "3. Get status"
|
||||
pid1=$(testrpc status 1)
|
||||
if [ $? -ne 0 ]; then echo "$pid1";exit -1; fi
|
||||
|
||||
|
|
@ -186,19 +188,19 @@ if [ "$pid0" -eq "$pid1" ]; then
|
|||
err "not $pid0"
|
||||
fi
|
||||
|
||||
new "2. stop restconf RPC"
|
||||
new "4. stop restconf RPC"
|
||||
testrpc stop 0
|
||||
if [ $? -ne 0 ]; then exit -1; fi
|
||||
|
||||
new "3. Get rpc status stopped"
|
||||
new "5. Get rpc status stopped"
|
||||
pid=$(testrpc status 0)
|
||||
if [ $? -ne 0 ]; then echo "$pid";exit -1; fi
|
||||
|
||||
new "4. Start rpc again"
|
||||
new "6. Start rpc again"
|
||||
testrpc start 0
|
||||
if [ $? -ne 0 ]; then exit -1; fi
|
||||
|
||||
new "4.1. Get rpc status"
|
||||
new "7. Get rpc status"
|
||||
pid3=$(testrpc status 1)
|
||||
if [ $? -ne 0 ]; then echo "$pid3";exit -1; fi
|
||||
|
||||
|
|
@ -215,19 +217,19 @@ fi
|
|||
new "kill restconf"
|
||||
stop_restconf_pre
|
||||
|
||||
new "5. start restconf RPC"
|
||||
new "8. start restconf RPC"
|
||||
testrpc start 0
|
||||
if [ $? -ne 0 ]; then exit -1; fi
|
||||
|
||||
new "6. check status RPC on"
|
||||
new "9. check status RPC on"
|
||||
pid5=$(testrpc status 1) # Save pid5
|
||||
if [ $? -ne 0 ]; then echo "$pid5";exit -1; fi
|
||||
|
||||
new "7. restart restconf RPC"
|
||||
new "10. restart restconf RPC"
|
||||
testrpc restart 0
|
||||
if [ $? -ne 0 ]; then exit -1; fi
|
||||
|
||||
new "8. Get restconf status rpc"
|
||||
new "11. Get restconf status rpc"
|
||||
pid7=$(testrpc status 1) # Save pid7
|
||||
if [ $? -ne 0 ]; then echo "$pid7";exit -1; fi
|
||||
|
||||
|
|
@ -264,7 +266,7 @@ if [ $BE -ne 0 ]; then
|
|||
wait_backend
|
||||
fi
|
||||
|
||||
new "9. Get restconf (running) after restart"
|
||||
new "12. Get restconf (running) after restart"
|
||||
pid=$(testrpc status 1)
|
||||
if [ $? -ne 0 ]; then echo "$pid"; exit -1; fi
|
||||
|
||||
|
|
@ -309,15 +311,15 @@ if [ $BE -ne 0 ]; then
|
|||
wait_backend
|
||||
fi
|
||||
|
||||
new "10. check status RPC off"
|
||||
new "13. check status RPC off"
|
||||
pid=$(testrpc status 0)
|
||||
if [ $? -ne 0 ]; then echo "$pid";exit -1; fi
|
||||
|
||||
new "11. start restconf RPC"
|
||||
new "14. start restconf RPC"
|
||||
testrpc start 0
|
||||
if [ $? -ne 0 ]; then exit -1; fi
|
||||
|
||||
new "12. check status RPC off"
|
||||
new "15. check status RPC off"
|
||||
pid=$(testrpc status 0)
|
||||
if [ $? -ne 0 ]; then echo "$pid";exit -1; fi
|
||||
|
||||
|
|
@ -327,7 +329,9 @@ expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-confi
|
|||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "13. check status RPC on"
|
||||
sleep $DEMSLEEP
|
||||
|
||||
new "16. check status RPC on"
|
||||
pid=$(testrpc status 1)
|
||||
if [ $? -ne 0 ]; then echo "$pid";exit -1; fi
|
||||
|
||||
|
|
@ -343,9 +347,9 @@ if [ $pid -eq $pid1 ]; then
|
|||
err "A different pid" "Same pid: $pid"
|
||||
fi
|
||||
|
||||
new "Edit a non-restconf field via restconf"
|
||||
echo "curl $CURLOPTS -X POST -H \"Content-Type: application/yang-data+json\" $RCPROTO://localhost/restconf/data -d '{\"example:val\":\"xyz\"}'"
|
||||
sleep $DEMSLEEP
|
||||
|
||||
new "Edit a non-restconf field via restconf"
|
||||
expectpart "$(curl $CURLOPTS -X POST -H "Content-Type: application/yang-data+json" $RCPROTO://localhost/restconf/data -d '{"example:val":"xyz"}' )" 0 "HTTP/1.1 201 Created"
|
||||
|
||||
new "check status RPC same pid"
|
||||
|
|
@ -361,7 +365,7 @@ expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><edit-confi
|
|||
new "netconf commit"
|
||||
expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO<rpc $DEFAULTNS><commit/></rpc>]]>]]>" "^<rpc-reply $DEFAULTNS><ok/></rpc-reply>]]>]]>$"
|
||||
|
||||
new "14. check status RPC off"
|
||||
new "17. check status RPC off"
|
||||
pid=$(testrpc status 0)
|
||||
if [ $? -ne 0 ]; then echo "$pid";exit -1; fi
|
||||
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ main(int argc,
|
|||
}
|
||||
if (clixon_event_reg_fd(ss, ssl_input_cb, sd, "ssl socket") < 0)
|
||||
goto done;
|
||||
if (clixon_event_loop() < 0)
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -539,7 +539,7 @@ main(int argc,
|
|||
}
|
||||
if (clixon_event_reg_fd(ss, ssl_input_cb, sd, "ssl socket") < 0)
|
||||
goto done;
|
||||
if (clixon_event_loop() < 0)
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue