diff options
-rw-r--r-- | doc/jim_tcl.txt | 5 | ||||
-rw-r--r-- | jim-exec.c | 20 | ||||
-rw-r--r-- | jim-posix.c | 88 |
3 files changed, 103 insertions, 10 deletions
diff --git a/doc/jim_tcl.txt b/doc/jim_tcl.txt index d733d50..9733705 100644 --- a/doc/jim_tcl.txt +++ b/doc/jim_tcl.txt @@ -37,7 +37,7 @@ The major differences are: 7. file mkdir, file rename (Tcl 7.x) 8. env command to access environment variables 9. List: lmap, lset, lreverse (Tcl 8.x) -10. os.fork +10. os.fork, os.wait 11. rand 12. string map (Tcl 7.x) 13. subst (Tcl 7.x) @@ -1351,7 +1351,8 @@ in the pipeline will go to the application's standard output unless redirected in the command, and error output from all the commands in the pipeline will go to the application's -standard error file. +standard error file. The return value of exec in this case +is a list of process ids (pids) in the pipeline. Each *arg* becomes one word for a command, except for '|', '<', '<<', '>', and '&' arguments, and the @@ -88,11 +88,20 @@ Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) * the command, detach it, and return. */ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { + Jim_Obj *listObj; + int i; + argc--; numPids = Jim_CreatePipeline(interp, argc-1, argv+1, &pidPtr, NULL, NULL, NULL); if (numPids < 0) { return JIM_ERR; } + /* The return value is a list of the pids */ + listObj = Jim_NewListObj(interp, NULL, 0); + for (i = 0; i < numPids; i++) { + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pidPtr[i])); + } + Jim_SetResult(interp, listObj); JimDetachPids(interp, numPids, pidPtr); Jim_Free(pidPtr); return JIM_OK; @@ -915,17 +924,16 @@ Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId) /* * Read the standard error file. If there's anything there, - * then return an error and add the file's contents to the result + * then add the file's contents to the result * string. */ if (errorId >= 0) { - if (errorId >= 0) { - result = Jim_AppendStreamToString(interp, errorId, Jim_GetResult(interp)); - if (result < 0) { - Jim_SetResultErrno(interp, "error reading from stderr output file"); - } + if (Jim_AppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) { + Jim_SetResultErrno(interp, "error reading from stderr output file"); + result = JIM_ERR; } + close(errorId); } /* diff --git a/jim-posix.c b/jim-posix.c index e8cb6e6..e199848 100644 --- a/jim-posix.c +++ b/jim-posix.c @@ -19,6 +19,7 @@ #include <sys/types.h> #include <sys/time.h> +#include <sys/wait.h> #include <unistd.h> #include <string.h> #include <signal.h> @@ -47,7 +48,7 @@ static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, return JIM_ERR; } if ((pid = fork()) == -1) { - Jim_SetResultString(interp, strerror(errno), -1); + Jim_PosixSetError(interp); return JIM_ERR; } Jim_SetResult(interp, Jim_NewIntObj(interp, (jim_wide)pid)); @@ -55,6 +56,89 @@ static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, #endif } +/* + * os.wait ?-nohang? pid + * + * An interface to waitpid(2) + * + * Returns a 3 element list. + * + * If -nohang is specified, and the process is still alive, returns + * + * {0 none 0} + * + * If the process does not exist or has already been waited for, returns: + * + * {-1 error <error-description>} + * + * If the process exited normally, returns: + * + * {<pid> exit <exit-status>} + * + * If the process terminated on a signal, returns: + * + * {<pid> signal <signal-number>} + * + * Otherwise (core dump, stopped, continued, ...), returns: + * + * {<pid> other 0} + */ +static int Jim_PosixWaitCommand(Jim_Interp *interp, int argc, + Jim_Obj *const *argv) +{ + int nohang = 0; + long pid; + int status; + Jim_Obj *listObj; + const char *type; + int value; + + if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) { + nohang = 1; + } + if (argc != nohang + 2) { + Jim_WrongNumArgs(interp, 1, argv, "?-nohang? pid"); + return JIM_ERR; + } + if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) { + return JIM_ERR; + } + + pid = waitpid(pid, &status, nohang ? WNOHANG : 0); + listObj = Jim_NewListObj(interp, NULL, 0); + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pid)); + if (pid < 0) { + type = "error"; + value = errno; + } + else if (pid == 0) { + type = "none"; + value = 0; + } + else if (WIFEXITED(status)) { + type = "exit"; + value = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) { + type = "signal"; + value = WTERMSIG(status); + } + else { + type = "other"; + value = 0; + } + + Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, type, -1)); + if (pid < 0) { + Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, strerror(value), -1)); + } + else { + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); + } + Jim_SetResult(interp, listObj); + return JIM_OK; +} + static int Jim_PosixGetidsCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -104,12 +188,12 @@ static int Jim_PosixPidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -// end added int Jim_posixInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "posix", "1.0", JIM_ERRMSG) != JIM_OK) return JIM_ERR; Jim_CreateCommand(interp, "os.fork", Jim_PosixForkCommand, NULL, NULL); + Jim_CreateCommand(interp, "os.wait", Jim_PosixWaitCommand, NULL, NULL); Jim_CreateCommand(interp, "os.getids", Jim_PosixGetidsCommand, NULL, NULL); Jim_CreateCommand(interp, "os.gethostname", Jim_PosixGethostnameCommand, NULL, NULL); Jim_CreateCommand(interp, "pid", Jim_PosixPidCommand, NULL, NULL); |