refactor: atInit changed to afterIocRunning
This commit is contained in:
committed by
Andrew Johnson
parent
2fc955bf8a
commit
70d5df05c7
@@ -1,8 +1,8 @@
|
||||
### New `atInit` IOC Shell Command Added
|
||||
### New `afterIocRunning` IOC Shell Command Added
|
||||
|
||||
This release incorporates [PR #558](https://github.com/epics-base/epics-base/pull/558) which added a new IOC shell command `atInit`. This command allows startup scripts to schedule arbitrary commands to be executed automatically after the IOC initialization phase (`iocInit`).
|
||||
This release incorporates [PR #558](https://github.com/epics-base/epics-base/pull/558) which added a new IOC shell command `afterIocRunning`. This command allows startup scripts to schedule arbitrary commands to be executed automatically after the IOC initialization phase (`iocInit`).
|
||||
|
||||
`atInit` allows you to write better-structured IOC shell files to include in your startup scripts without tracking where `iocInit` is located (and how IOC is deployed) e.g.:
|
||||
`afterIocRunning` allows you to write better-structured IOC shell files to include in your startup scripts without tracking where `iocInit` is located (and how IOC is deployed) e.g.:
|
||||
- to achieve the best maintainability (e.g. encapsulation of the context into one file),
|
||||
- to improve writing boot sequences,
|
||||
- to improve IOC startup flexibility and scripting capabilities,
|
||||
@@ -17,7 +17,7 @@ This release incorporates [PR #558](https://github.com/epics-base/epics-base/pul
|
||||
- Executes following `iocInit` and `autosave` initialization (important for proper PV configuration).
|
||||
- Supports any valid IOC shell command as an argument.
|
||||
- Example usages:
|
||||
- `atInit "dbpf <PV> <VAL>"`
|
||||
- `atInit "date"`
|
||||
- `atInit "dbpf $(P)EvtClkSource-Sel 'Upstream (fanout)'"`
|
||||
- `atInit "dbpf $(P)Enable-Sel Enabled"`
|
||||
- `afterIocRunning "dbpf <PV> <VAL>"`
|
||||
- `afterIocRunning "date"`
|
||||
- `afterIocRunning "dbpf $(P)EvtClkSource-Sel 'Upstream (fanout)'"`
|
||||
- `afterIocRunning "dbpf $(P)Enable-Sel Enabled"`
|
||||
|
||||
@@ -16,7 +16,7 @@ Com_SRCS += iocsh.cpp
|
||||
Com_SRCS += initHooks.c
|
||||
Com_SRCS += registry.c
|
||||
Com_SRCS += libComRegister.c
|
||||
Com_SRCS += atInit.c
|
||||
Com_SRCS += afterIocRunning.c
|
||||
|
||||
iocsh_CXXFLAGS += -DEPICS_COMMANDLINE_LIBRARY=EPICS_COMMANDLINE_LIBRARY_$(COMMANDLINE_LIBRARY)
|
||||
iocsh_INCLUDES += $(INCLUDES_$(COMMANDLINE_LIBRARY))
|
||||
|
||||
@@ -13,18 +13,20 @@
|
||||
#include <iocsh.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atInit.h"
|
||||
#include "afterIocRunning.h"
|
||||
|
||||
static const iocshArg atInitArg0 = {"command (before iocInit)", iocshArgString};
|
||||
static const iocshArg *const atInitArgs[] = {&atInitArg0};
|
||||
static const iocshFuncDef atInitDef = {
|
||||
"atInit",
|
||||
static const iocshArg afterIocRunningArg0 = {"command (before iocInit)", iocshArgString};
|
||||
static const iocshArg *const afterIocRunningArgs[] = {&afterIocRunningArg0};
|
||||
static const iocshFuncDef afterIocRunningDef = {
|
||||
"afterIocRunning",
|
||||
1,
|
||||
atInitArgs,
|
||||
afterIocRunningArgs,
|
||||
"Allows you to define commands to be run after the iocInit\n"
|
||||
"Example commands:\n"
|
||||
" atInit \"dbpf <PV> <VAL>\"\n"
|
||||
" atInit \"date\"\n"};
|
||||
" afterIocRunning \"dbpf <PV> <VAL>\"\n"
|
||||
" afterIocRunning \"date\"\n"
|
||||
" afterIocRunning \"dbpf $(P)EvtClkSource-Sel 'Upstream (fanout)'\"\n"
|
||||
" afterIocRunning \"dbpf $(P)Enable-Sel Enabled\"\n"};
|
||||
|
||||
struct cmditem {
|
||||
ELLNODE node;
|
||||
@@ -34,7 +36,7 @@ struct cmditem {
|
||||
static ELLLIST cmdList = ELLLIST_INIT;
|
||||
static int initEndFlag = 0; // Defines the end of the initialization
|
||||
|
||||
static void atInitHook(const initHookState state)
|
||||
static void afterIocRunningHook(const initHookState state)
|
||||
{
|
||||
struct cmditem *item = NULL;
|
||||
|
||||
@@ -42,10 +44,10 @@ static void atInitHook(const initHookState state)
|
||||
return;
|
||||
|
||||
while ((item = (struct cmditem *)ellGet(&cmdList))) {
|
||||
printf(ANSI_GREEN("atInit:") " %s\n", item->cmd);
|
||||
printf(ANSI_GREEN("afterIocRunning:") " %s\n", item->cmd);
|
||||
|
||||
if (iocshCmd(item->cmd))
|
||||
printf(ERL_ERROR " atInit: "
|
||||
printf(ERL_ERROR " afterIocRunning: "
|
||||
"command '%s' failed to run\n",
|
||||
item->cmd);
|
||||
|
||||
@@ -58,7 +60,7 @@ static void atInitHook(const initHookState state)
|
||||
static struct cmditem *newItem(const char *cmd)
|
||||
{
|
||||
const size_t cmd_len = strlen(cmd) + 1;
|
||||
struct cmditem *const item = mallocMustSucceed(sizeof(struct cmditem) + cmd_len, "atInit");
|
||||
struct cmditem *const item = mallocMustSucceed(sizeof(struct cmditem) + cmd_len, "afterIocRunning");
|
||||
item->cmd = (char *)(item + 1);
|
||||
memcpy(item->cmd, cmd, cmd_len);
|
||||
|
||||
@@ -67,18 +69,18 @@ static struct cmditem *newItem(const char *cmd)
|
||||
return item;
|
||||
}
|
||||
|
||||
static void atInitFunc(const iocshArgBuf *args)
|
||||
static void afterIocRunningFunc(const iocshArgBuf *args)
|
||||
{
|
||||
const char *const cmd = args[0].sval;
|
||||
|
||||
if (initEndFlag) {
|
||||
printf(ERL_WARNING " atInit: "
|
||||
printf(ERL_WARNING " afterIocRunning: "
|
||||
"can only be used before 'iocInit'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cmd || !cmd[0]) {
|
||||
printf(ERL_ERROR " atInit: "
|
||||
printf(ERL_ERROR " afterIocRunning: "
|
||||
"received an empty 'command' argument\n");
|
||||
return;
|
||||
}
|
||||
@@ -86,12 +88,12 @@ static void atInitFunc(const iocshArgBuf *args)
|
||||
newItem(cmd);
|
||||
}
|
||||
|
||||
void atInitRegister(void)
|
||||
void afterIocRunningRegister(void)
|
||||
{
|
||||
static int first_time = 1;
|
||||
if (first_time) {
|
||||
first_time = 0;
|
||||
iocshRegister(&atInitDef, atInitFunc);
|
||||
initHookRegister(atInitHook);
|
||||
iocshRegister(&afterIocRunningDef, afterIocRunningFunc);
|
||||
initHookRegister(afterIocRunningHook);
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#ifndef INC_atInit_H
|
||||
#define INC_atInit_H
|
||||
#ifndef INC_afterIocRunning_H
|
||||
#define INC_afterIocRunning_H
|
||||
|
||||
void atInitRegister(void);
|
||||
void afterIocRunningRegister(void);
|
||||
|
||||
#endif /* INC_atInit_H */
|
||||
#endif /* INC_afterIocRunning_H */
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "epicsGeneralTime.h"
|
||||
#include "freeList.h"
|
||||
#include "libComRegister.h"
|
||||
#include "atInit.h"
|
||||
#include "afterIocRunning.h"
|
||||
|
||||
/* Register the PWD environment variable when the cd IOC shell function is
|
||||
* registered. This variable contains the current directory path.
|
||||
@@ -513,7 +513,7 @@ void epicsStdCall libComRegister(void)
|
||||
iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc);
|
||||
iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc);
|
||||
|
||||
atInitRegister();
|
||||
afterIocRunningRegister();
|
||||
|
||||
comDefs[0].pval = &asCheckClientIP;
|
||||
comDefs[1].pval = &freeListBypass;
|
||||
|
||||
@@ -256,10 +256,10 @@ osiSockTest_SRCS += osiSockTest.c
|
||||
testHarness_SRCS += osiSockTest.c
|
||||
TESTS += osiSockTest
|
||||
|
||||
TESTPROD_HOST += atInitTest
|
||||
atInitTest_SRCS += atInitTest.cpp
|
||||
TESTS += atInitTest
|
||||
testHarness_SRCS += atInitTest.cpp
|
||||
TESTPROD_HOST += afterIocRunningTest
|
||||
afterIocRunningTest_SRCS += afterIocRunningTest.cpp
|
||||
TESTS += afterIocRunningTest
|
||||
testHarness_SRCS += afterIocRunningTest.cpp
|
||||
|
||||
TESTPROD_HOST += testexecname
|
||||
testexecname_SRCS += testexecname.c
|
||||
|
||||
80
modules/libcom/test/afterIocRunningTest.cpp
Normal file
80
modules/libcom/test/afterIocRunningTest.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*************************************************************************\
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <epicsUnitTest.h>
|
||||
#include <initHooks.h>
|
||||
#include <iocsh.h>
|
||||
#include <libComRegister.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <testMain.h>
|
||||
|
||||
static void testOkEnv(const char *varName, const char *varValue)
|
||||
{
|
||||
const char *val = getenv(varName);
|
||||
testOk(val && strcmp(val, varValue) == 0,
|
||||
"%s=%s", varName, val ? val : "(null)");
|
||||
}
|
||||
|
||||
static void iocshCmdDebug(const char *cmd)
|
||||
{
|
||||
printf("%s\n", cmd);
|
||||
iocshCmd(cmd);
|
||||
}
|
||||
|
||||
MAIN(afterIocRunningTest)
|
||||
{
|
||||
testPlan(12);
|
||||
|
||||
libComRegister();
|
||||
|
||||
// Reset environment variables
|
||||
iocshCmdDebug("epicsEnvSet \"TEST_VAR\" \"BeforeIocInit\"");
|
||||
iocshCmdDebug("epicsEnvSet \"TEST_VAR_ONE\" \"Before(Ioc)Init\"");
|
||||
iocshCmdDebug("epicsEnvSet 'TEST_VAR_SPACES' 'Before Ioc Init'");
|
||||
|
||||
printf("Test whether the variables are initialized correctly.\n");
|
||||
testOkEnv("TEST_VAR", "BeforeIocInit");
|
||||
testOkEnv("TEST_VAR_ONE", "Before(Ioc)Init");
|
||||
testOkEnv("TEST_VAR_SPACES", "Before Ioc Init");
|
||||
printf("===================\n");
|
||||
epicsThreadSleep(1.0);
|
||||
// Basic test
|
||||
iocshCmdDebug("afterIocRunning \"epicsEnvSet TEST_VAR AfterIocInit\"");
|
||||
iocshCmdDebug("afterIocRunning \"epicsEnvSet TEST_VAR_ONE 'After(Ioc)Init'\"");
|
||||
iocshCmdDebug("afterIocRunning \"epicsEnvSet TEST_VAR_SPACES 'After Ioc Init'\"");
|
||||
iocshCmdDebug("afterIocRunning \"date\"");
|
||||
// Verify error handling and robustness
|
||||
iocshCmdDebug("afterIocRunning \"nonexistentCommand arg1 arg2\"");
|
||||
iocshCmdDebug("afterIocRunning \"\""); // empty string
|
||||
iocshCmdDebug("afterIocRunning \" \""); // only spaces
|
||||
printf("===================\n");
|
||||
|
||||
epicsThreadSleep(1.0);
|
||||
printf("Test whether the variables remain unchanged after 'afterIocRunning' and before 'iocInit'.\n");
|
||||
testOkEnv("TEST_VAR", "BeforeIocInit");
|
||||
testOkEnv("TEST_VAR_ONE", "Before(Ioc)Init");
|
||||
testOkEnv("TEST_VAR_SPACES", "Before Ioc Init");
|
||||
|
||||
// Simulate iocInit
|
||||
printf("===================\n"
|
||||
"iocInit: Simulation\n"
|
||||
"===================\n");
|
||||
initHookAnnounce(initHookAfterIocRunning);
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
// Verify the results
|
||||
printf("Test whether the variables are correctly initialized after 'iocInit'.\n");
|
||||
testOkEnv("TEST_VAR", "AfterIocInit");
|
||||
testOkEnv("TEST_VAR_ONE", "After(Ioc)Init");
|
||||
testOkEnv("TEST_VAR_SPACES", "After Ioc Init");
|
||||
testPass("Command 'date' executed");
|
||||
testPass("Invalid command did not crash IOC");
|
||||
testPass("Empty afterIocRunning commands do not cause failure");
|
||||
|
||||
return testDone();
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* SPDX-License-Identifier: EPICS
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
#include <epicsThread.h>
|
||||
#include <epicsUnitTest.h>
|
||||
#include <initHooks.h>
|
||||
#include <iocsh.h>
|
||||
#include <libComRegister.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <testMain.h>
|
||||
|
||||
void testOkEnv(const char *varName, const char *varValue)
|
||||
{
|
||||
const char *val = getenv(varName);
|
||||
testOk(val && strcmp(val, varValue) == 0,
|
||||
"%s=%s", varName, val ? val : "(null)");
|
||||
}
|
||||
|
||||
MAIN(atInitTest)
|
||||
{
|
||||
testPlan(12);
|
||||
|
||||
libComRegister();
|
||||
|
||||
// Reset environment variables
|
||||
iocshCmd("epicsEnvSet \"ATINIT_TEST_VAR\" \"BeforeIocInit\"");
|
||||
iocshCmd("epicsEnvSet \"ATINIT_TEST_VAR_ONE\" \"BeforeIocInit\"");
|
||||
iocshCmd("epicsEnvSet 'ATINIT_TEST_VAR_SPACES' 'Before Ioc Init'");
|
||||
|
||||
printf("Test whether the variables are initialized correctly.\n");
|
||||
testOkEnv("ATINIT_TEST_VAR", "BeforeIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_ONE", "BeforeIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_SPACES", "Before Ioc Init");
|
||||
|
||||
// Basic test
|
||||
iocshCmd("atInit \"epicsEnvSet ATINIT_TEST_VAR AfterIocInit\"");
|
||||
iocshCmd("atInit \"epicsEnvSet ATINIT_TEST_VAR_ONE AfterIocInit\"");
|
||||
iocshCmd("atInit \"epicsEnvSet ATINIT_TEST_VAR_SPACES 'After Ioc Init'\"");
|
||||
iocshCmd("atInit \"date\"");
|
||||
|
||||
epicsThreadSleep(1.0);
|
||||
// Verify error handling and robustness
|
||||
iocshCmd("atInit \"nonexistentCommand arg1 arg2\"");
|
||||
iocshCmd("atInit \"\""); // empty string
|
||||
iocshCmd("atInit \" \""); // only spaces
|
||||
|
||||
printf("Test whether the variables remain unchanged after 'atInit' and before 'iocInit'.\n");
|
||||
testOkEnv("ATINIT_TEST_VAR", "BeforeIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_ONE", "BeforeIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_SPACES", "Before Ioc Init");
|
||||
|
||||
// Simulate iocInit
|
||||
initHookAnnounce(initHookAfterIocRunning);
|
||||
printf("=== iocInit Simulation ===\n");
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
// Verify the results
|
||||
printf("Test whether the variables are correctly initialized after 'iocInit'.\n");
|
||||
testOkEnv("ATINIT_TEST_VAR", "AfterIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_ONE", "AfterIocInit");
|
||||
testOkEnv("ATINIT_TEST_VAR_SPACES", "After Ioc Init");
|
||||
testPass("Command 'date' executed");
|
||||
|
||||
testPass("Invalid command did not crash IOC");
|
||||
testPass("Empty atInit commands do not cause failure");
|
||||
|
||||
return testDone();
|
||||
}
|
||||
Reference in New Issue
Block a user