aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/jim_tcl.txt5
-rw-r--r--jim-exec.c20
-rw-r--r--jim-posix.c88
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
diff --git a/jim-exec.c b/jim-exec.c
index 42056fa..40abe34 100644
--- a/jim-exec.c
+++ b/jim-exec.c
@@ -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);