EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0
From: mdavidsaver via Core-talk <[email protected]>
To: [email protected],Bruce Hill <[email protected]>
Date: Fri, 03 May 2019 03:50:36 -0000
mdavidsaver has proposed merging ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0.

Requested reviews:
  Bruce Hill (bhill)

For more details, see:
https://code.launchpad.net/~epics-core/epics-base/+git/Com/+merge/366876

Add basic (literally?) error handling to iocsh.

1. Add the iocsh command "on error ..." with options to "continue" (the default), "break" (return w/ error code), "halt", and "wait ###".
2. Catch c++ exceptions and treat as an error.
3. Add iocshSetError() for use in C code.

Opening a iocsh script with "on error halt" will act similarly to:

https://code.launchpad.net/~bhill/epics-base/+git/epics-base/+merge/366606

The main difference is that:

1. More options in how errors are treated.
2. Errors on unknown iocsh commands.
3. Modifies *CallFunc() wrappers, not functions.

-- 
Your team EPICS Core Developers is subscribed to branch epics-base:7.0.
diff --git a/modules/database/src/ioc/as/asIocRegister.c b/modules/database/src/ioc/as/asIocRegister.c
index 16cba90..d5926a5 100644
--- a/modules/database/src/ioc/as/asIocRegister.c
+++ b/modules/database/src/ioc/as/asIocRegister.c
@@ -39,7 +39,7 @@ static void asSetSubstitutionsCallFunc(const iocshArgBuf *args)
 static const iocshFuncDef asInitFuncDef = {"asInit",0};
 static void asInitCallFunc(const iocshArgBuf *args)
 {
-    asInit();
+    iocshSetError(asInit());
 }
 
 /* asdbdump */
diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c
index c40af92..afb3115 100644
--- a/modules/database/src/ioc/db/dbIocRegister.c
+++ b/modules/database/src/ioc/db/dbIocRegister.c
@@ -39,7 +39,7 @@ static const iocshFuncDef dbLoadDatabaseFuncDef =
     {"dbLoadDatabase",3,dbLoadDatabaseArgs};
 static void dbLoadDatabaseCallFunc(const iocshArgBuf *args)
 {
-    dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval);
+    iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval));
 }
 
 /* dbLoadRecords */
@@ -49,7 +49,7 @@ static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoad
 static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs};
 static void dbLoadRecordsCallFunc(const iocshArgBuf *args)
 {
-    dbLoadRecords(args[0].sval,args[1].sval);
+    iocshSetError(dbLoadRecords(args[0].sval,args[1].sval));
 }
 
 /* dbb */
diff --git a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c
index 201a323..879f67e 100644
--- a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c
+++ b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c
@@ -22,7 +22,7 @@ static const iocshFuncDef dbLoadTemplateFuncDef =
     {"dbLoadTemplate", 2, dbLoadTemplateArgs};
 static void dbLoadTemplateCallFunc(const iocshArgBuf *args)
 {
-    dbLoadTemplate(args[0].sval, args[1].sval);
+    iocshSetError(dbLoadTemplate(args[0].sval, args[1].sval));
 }
 
 
diff --git a/modules/database/src/ioc/misc/miscIocRegister.c b/modules/database/src/ioc/misc/miscIocRegister.c
index 6c08ef0..4dffdfc 100644
--- a/modules/database/src/ioc/misc/miscIocRegister.c
+++ b/modules/database/src/ioc/misc/miscIocRegister.c
@@ -22,28 +22,28 @@
 static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL};
 static void iocInitCallFunc(const iocshArgBuf *args)
 {
-    iocInit();
+    iocshSetError(iocInit());
 }
 
 /* iocBuild */
 static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL};
 static void iocBuildCallFunc(const iocshArgBuf *args)
 {
-    iocBuild();
+    iocshSetError(iocBuild());
 }
 
 /* iocRun */
 static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL};
 static void iocRunCallFunc(const iocshArgBuf *args)
 {
-    iocRun();
+    iocshSetError(iocRun());
 }
 
 /* iocPause */
 static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL};
 static void iocPauseCallFunc(const iocshArgBuf *args)
 {
-    iocPause();
+    iocshSetError(iocPause());
 }
 
 /* coreRelease */
@@ -77,7 +77,7 @@ static const iocshArg * const systemArgs[] = {&systemArg0};
 static const iocshFuncDef systemFuncDef = {"system",1,systemArgs};
 static void systemCallFunc(const iocshArgBuf *args)
 {
-    system(args[0].sval);
+    iocshSetError(system(args[0].sval));
 }
 #endif
 
diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl
index 02bb9b7..10147db 100644
--- a/modules/database/src/tools/registerRecordDeviceDriver.pl
+++ b/modules/database/src/tools/registerRecordDeviceDriver.pl
@@ -277,7 +277,7 @@ static const iocshFuncDef rrddFuncDef =
     {"$subname", 1, rrddArgs};
 static void rrddCallFunc(const iocshArgBuf *)
 {
-    $subname(*iocshPpdbbase);
+    iocshSetError($subname(*iocshPpdbbase));
 }
 
 } // extern "C"
diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp
index 0de90c8..2e64e8b 100644
--- a/modules/libcom/src/iocsh/iocsh.cpp
+++ b/modules/libcom/src/iocsh/iocsh.cpp
@@ -11,6 +11,8 @@
 /* Heavily modified by Eric Norum   Date: 03MAY2000 */
 /* Adapted to C++ by Eric Norum   Date: 18DEC2000 */
 
+#include <exception>
+
 #include <stddef.h>
 #include <string.h>
 #include <stdio.h>
@@ -56,7 +58,7 @@ static char iocshVarID[] = "iocshVar";
 extern "C" { static void varCallFunc(const iocshArgBuf *); }
 static epicsMutexId iocshTableMutex;
 static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT;
-static epicsThreadPrivateId iocshMacroHandleId;
+static epicsThreadPrivateId iocshScopeId;
 
 /*
  * I/O redirection
@@ -76,7 +78,7 @@ struct iocshRedirect {
 static void iocshOnce (void *)
 {
     iocshTableMutex = epicsMutexMustCreate ();
-    iocshMacroHandleId = epicsThreadPrivateCreate();
+    iocshScopeId = epicsThreadPrivateCreate();
 }
 
 static void iocshInit (void)
@@ -496,6 +498,30 @@ static void helpCallFunc(const iocshArgBuf *args)
     }
 }
 
+typedef enum {
+    Continue,
+    Break,
+    Halt
+} OnError;
+
+typedef struct {
+    MAC_HANDLE *handle;
+    OnError onerr;
+    double timeout;
+    bool errored;
+} Scope;
+
+int iocshSetError(int err)
+{
+    Scope *scope;
+    if (err && iocshScopeId) {
+        scope = (Scope *) epicsThreadPrivateGet(iocshScopeId);
+
+        if(scope) scope->errored = 1;
+    }
+    return err;
+}
+
 /*
  * The body of the command interpreter
  */
@@ -524,8 +550,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
     void *readlineContext = NULL;
     int wasOkToBlock;
     static const char * pairs[] = {"", "environ", NULL, NULL};
+    Scope *scope;
     MAC_HANDLE *handle;
     char ** defines = NULL;
+    int ret = 0;
     
     iocshInit();
 
@@ -586,17 +614,20 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
     /*
      * Check for existing macro context or construct a new one.
      */
-    handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId);
+    scope = (Scope *) epicsThreadPrivateGet(iocshScopeId);
     
-    if (handle == NULL) {
-        if (macCreateHandle(&handle, pairs)) {
+    if (!scope) {
+        scope = (Scope*)calloc(1, sizeof(*scope));
+        if (!scope || macCreateHandle(&scope->handle, pairs)) {
             errlogMessage("iocsh: macCreateHandle failed.");
             free(redirects);
+            free(scope);
             return -1;
         }
         
-        epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle);
+        epicsThreadPrivateSet(iocshScopeId, (void *) scope);
     }
+    handle = scope->handle;
     
     macPushScope(handle);
     macInstallMacros(handle, defines);
@@ -834,7 +865,17 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
                 for (int iarg = 0 ; ; ) {
                     if (iarg == piocshFuncDef->nargs) {
                         startRedirect(filename, lineno, redirects);
-                        (*found->def.func)(argBuf);
+                        /* execute */
+                        scope->errored = false;
+                        try {
+                            (*found->def.func)(argBuf);
+                        } catch(std::exception& e){
+                            fprintf(epicsGetStderr(), "c++ error: %s\n", e.what());
+                            scope->errored = true;
+                        } catch(...) {
+                            fprintf(epicsGetStderr(), "c++ error unknown\n");
+                            scope->errored = true;
+                        }
                         break;
                     }
                     if (iarg >= argBufCapacity) {
@@ -868,15 +909,33 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
             }
             else {
                 showError(filename, lineno, "Command %s not found.", argv[0]);
+                scope->errored = true;
             }
         }
         stopRedirect(filename, lineno, redirects);
+        if(!commandLine && !scope->errored) {
+            if(scope->onerr==Continue) {
+            } else if(scope->onerr==Break) {
+                ret = -1;
+                break;
+            } else if(scope->onerr==Halt) {
+                ret = -1;
+                if(scope->timeout<=0.0) {
+                    epicsThreadSuspendSelf();
+                } else {
+                    fprintf(epicsGetStderr(), "Wait %f sec\n", scope->timeout);
+                    epicsThreadSleep(scope->timeout);
+                }
+                break;
+            }
+        }
     }
     macPopScope(handle);
     
     if (handle->level == 0) {
         macDeleteHandle(handle);
-        epicsThreadPrivateSet(iocshMacroHandleId, NULL);
+        free(scope);
+        epicsThreadPrivateSet(iocshScopeId, NULL);
     }
     if (fp && (fp != stdin))
         fclose (fp);
@@ -891,7 +950,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
     if (readlineContext)
         epicsReadlineEnd(readlineContext);
     epicsThreadSetOkToBlock(wasOkToBlock);
-    return 0;
+    return ret;
 }
 
 /*
@@ -943,13 +1002,13 @@ iocshRun(const char *cmd, const char *macros)
 void epicsShareAPI
 iocshEnvClear(const char *name)
 {
-    MAC_HANDLE *handle;
+    Scope *scope;
     
-    if (iocshMacroHandleId) {
-        handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId);
+    if (iocshScopeId) {
+        scope = (Scope *) epicsThreadPrivateGet(iocshScopeId);
     
-        if (handle != NULL) {
-            macPutValue(handle, name, NULL);
+        if (scope != NULL) {
+            macPutValue(scope->handle, name, NULL);
         }
     }
 }
@@ -1054,6 +1113,41 @@ static void iocshRunCallFunc(const iocshArgBuf *args)
     iocshRun(args[0].sval, args[1].sval);
 }
 
+/* on */
+static const iocshArg onArg0 = { "...", iocshArgArgv };
+static const iocshArg *onArgs[1] = {&onArg0};
+static const iocshFuncDef onFuncDef = {"on", 1, onArgs};
+static void onCallFunc(const iocshArgBuf *args)
+{
+    Scope *scope = (Scope *) epicsThreadPrivateGet(iocshScopeId);
+
+    if(!scope || args->aval.ac<=2) {
+    } else if(strcmp(args->aval.av[1], "error")==0) {
+        if(args->aval.ac==2) {
+        } else if(strcmp(args->aval.av[2], "continue")==0) {
+            scope->onerr = Continue;
+            return;
+
+        } else if(strcmp(args->aval.av[2], "break")==0) {
+            scope->onerr = Break;
+            return;
+
+        } else if(strcmp(args->aval.av[2], "halt")==0) {
+            scope->onerr = Halt;
+            scope->timeout = 0.0;
+            return;
+
+        } else if(strcmp(args->aval.av[2], "wait")==0) {
+            scope->onerr = Halt;
+            if(args->aval.ac==3 || !epicsParseDouble(args->aval.av[3], &scope->timeout, NULL)) {
+                scope->timeout = 5.0;
+            }
+            return;
+        }
+    }
+    fprintf(epicsGetStderr(), "Invalid 'on'\n");
+}
+
 /*
  * Dummy internal commands -- register and install in command table
  * so they show up in the help display
@@ -1083,6 +1177,7 @@ static void localRegister (void)
     iocshRegister(&iocshCmdFuncDef,iocshCmdCallFunc);
     iocshRegister(&iocshLoadFuncDef,iocshLoadCallFunc);
     iocshRegister(&iocshRunFuncDef,iocshRunCallFunc);
+    iocshRegister(&onFuncDef, onCallFunc);
 }
 
 } /* extern "C" */
diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h
index 84b38f2..2e8dc22 100644
--- a/modules/libcom/src/iocsh/iocsh.h
+++ b/modules/libcom/src/iocsh/iocsh.h
@@ -89,6 +89,8 @@ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd);
 epicsShareFunc int epicsShareAPI iocshLoad(const char *pathname, const char* macros);
 epicsShareFunc int epicsShareAPI iocshRun(const char *cmd, const char* macros);
 
+epicsShareFunc int iocshSetError(int err);
+
 /* Makes macros that shadow environment variables work correctly with epicsEnvSet */
 epicsShareFunc void epicsShareAPI iocshEnvClear(const char *name);
 
diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c
index b105ea1..11396e9 100644
--- a/modules/libcom/src/iocsh/libComRegister.c
+++ b/modules/libcom/src/iocsh/libComRegister.c
@@ -76,7 +76,7 @@ static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs};
 static void chdirCallFunc(const iocshArgBuf *args)
 {
     if (args[0].sval == NULL ||
-        chdir(args[0].sval)) {
+        iocshSetError(chdir(args[0].sval))) {
         fprintf(stderr, "Invalid directory path, ignored\n");
     }
 }

Replies:
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Ben Franksen via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Keenan Lang via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Keenan Lang via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Keenan Lang via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Bruce Hill via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Bruce Hill via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Keenan Lang via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Keenan Lang via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
[Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 Andrew Johnson via Core-talk
[Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 noreply--- via Core-talk

Navigate by Date:
Prev: [Bug 1827225] Re: AppVeyor mingw builds broken (claiming missing epicsTempFile.obj) Ralph Lange via Core-talk
Next: Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Build completed: EPICS Base base-3.15-390 AppVeyor via Core-talk
Next: Re: [Merge] ~epics-core/epics-base/+git/Com:iocsherr into epics-base:7.0 mdavidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  <20192020  2021  2022  2023  2024 
ANJ, 19 Oct 2019 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·