From: <enl...@li...> - 2005-10-24 14:47:37
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Fleshed out the fork'n'pipe IPC a little more. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -3 -r1.14 -r1.15 --- ecore_exe.c 24 Oct 2005 09:02:46 -0000 1.14 +++ ecore_exe.c 24 Oct 2005 14:47:25 -0000 1.15 @@ -1,6 +1,9 @@ #include "ecore_private.h" #include "Ecore.h" +#include <errno.h> +#include <sys/wait.h> + #ifndef WIN32 static Ecore_Exe *exes = NULL; @@ -52,6 +55,9 @@ return NULL; } + +static char *shell = 0; + /** * Spawns a child process with its stdin/out available for communication. * @@ -73,7 +79,12 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { Ecore_Exe *exe; - pid_t pid; + pid_t pid = 0; + int dataPipe[2] = { -1, -1 }; + int statusPipe[2] = { -1, -1 }; + int n; + volatile int vfork_exec_errno = 0; + char **args; /* FIXME: * if flags does not have read or write in them - just execute using @@ -99,15 +110,99 @@ * chars are left, then take trailing data (if any) and put in read buf * waiting for more data. * + * Just for the sake of example, this currently closes the parent to child pipe, + * and leaves the other one open. */ if (!exe_cmd) return NULL; - pid = fork(); + + if (shell == 0) + { + shell = getenv("SHELL"); + if (shell == 0) + shell = "/bin/sh"; + } + + args = (char **) calloc(4, sizeof(char *)); + n = 0; + args[n++] = shell; + args[n++] = "-c"; + args[n++] = exe_cmd; + args[n++] = 0; + + if (pipe(dataPipe) < 0 || pipe(statusPipe) < 0) + printf("Failed to create pipe\n"); + signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ + pid = fork(); + + if (pid == 0) + { /* child */ + setsid(); + close(STDIN_FILENO); + dup2(dataPipe[1], STDOUT_FILENO); + dup2(dataPipe[1], STDERR_FILENO); + close(dataPipe[0]); + close(statusPipe[0]); + fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ + + errno = 0; + execvp(shell, (char **) args); + + vfork_exec_errno = errno; + close(statusPipe[1]); + _exit(-1); + } + else if (pid > 0) + { /* parent */ + close(dataPipe[1]); + close(statusPipe[1]); + + while (1) + { + char buf; + + n = read(statusPipe[0], &buf, 1); + + if (n == 0 && vfork_exec_errno != 0) + { + errno = vfork_exec_errno; + printf("Could not exec process\n"); + } + break; + } + close(statusPipe[0]); + + } + else + { + printf("Failed to fork process\n"); + pid = 0; + } + + n = 0; + if (pid) + { + close(dataPipe[0]); + + if (WIFEXITED(n)) + { + n = WEXITSTATUS(n); + printf("Process %s returned %i\n", exe_cmd, n); + pid = 0; + } + else + n = -1; + } + + free(args); + errno = n; + if (pid) { exe = calloc(1, sizeof(Ecore_Exe)); if (!exe) { kill(pid, SIGKILL); + printf("No memory for Ecore_Exe %s\n", exe_cmd); return NULL; } ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); @@ -116,9 +211,7 @@ exes = _ecore_list2_append(exes, exe); return exe; } - setsid(); - execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL); - exit(127); + return NULL; } |
From: <enl...@li...> - 2005-10-25 07:21:58
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h Log Message: Need to store the flags for later. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.21 retrieving revision 1.22 diff -u -3 -r1.21 -r1.22 --- ecore_private.h 24 Oct 2005 09:02:21 -0000 1.21 +++ ecore_private.h 25 Oct 2005 07:21:52 -0000 1.22 @@ -145,6 +145,7 @@ pid_t pid; void *data; char *tag; + Ecore_Exe_Flags flags; Ecore_Fd_Handler *fd_handler; /* FIXME: the fd_handler to handle read/write to child - if this was used, or NULL if not */ void *write_data_buf; /* FIXME: a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ int write_data_size; /* FIXME: the size in bytes of the data buffer */ |
From: <enl...@li...> - 2005-10-25 07:30:36
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: The pipes, the pipes are calling. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.15 retrieving revision 1.16 diff -u -3 -r1.15 -r1.16 --- ecore_exe.c 24 Oct 2005 14:47:25 -0000 1.15 +++ ecore_exe.c 25 Oct 2005 07:30:29 -0000 1.16 @@ -78,7 +78,7 @@ Ecore_Exe * ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { - Ecore_Exe *exe; + Ecore_Exe *exe = NULL; pid_t pid = 0; int dataPipe[2] = { -1, -1 }; int statusPipe[2] = { -1, -1 }; @@ -87,13 +87,6 @@ char **args; /* FIXME: - * if flags does not have read or write in them - just execute using - * ecore_exe_run() as normal. - * pipe() to creeate pipes (as necessary accoring to flags) - * in child close() parent side of pipes - * in child dup2() stdin, stdout (according to flags as necessary) - * in parent (here) close() child side of pipes - * set up fd's in ecore_exe struct FIXME - add to struct * set up fd handler in ecore_exe struct * see ecore_con for code and examples on this (fd's there are to a socket * but otherwise work the same as here). the ECORE_EVENT_EXE_EXIT event @@ -109,12 +102,12 @@ * generate data event for that. repeat for each other \n found until no \n * chars are left, then take trailing data (if any) and put in read buf * waiting for more data. - * - * Just for the sake of example, this currently closes the parent to child pipe, - * and leaves the other one open. */ + if (!exe_cmd) return NULL; + if ((flags & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE)) == 0) return ecore_exe_run(exe_cmd, data); + if (shell == 0) { shell = getenv("SHELL"); @@ -131,16 +124,34 @@ if (pipe(dataPipe) < 0 || pipe(statusPipe) < 0) printf("Failed to create pipe\n"); + /* FIXME: I should check this. */ signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ pid = fork(); if (pid == 0) { /* child */ setsid(); - close(STDIN_FILENO); - dup2(dataPipe[1], STDOUT_FILENO); - dup2(dataPipe[1], STDERR_FILENO); - close(dataPipe[0]); + + if (flags & ECORE_EXE_PIPE_READ) + { + dup2(dataPipe[1], STDOUT_FILENO); + dup2(dataPipe[1], STDERR_FILENO); + } + else + { + close(dataPipe[1]); + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + if (flags & ECORE_EXE_PIPE_WRITE) + { + dup2(dataPipe[0], STDIN_FILENO); + } + else + { + close(dataPipe[0]); + close(STDIN_FILENO); + } close(statusPipe[0]); fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ @@ -153,7 +164,10 @@ } else if (pid > 0) { /* parent */ - close(dataPipe[1]); + if (! (flags & ECORE_EXE_PIPE_READ)) + close(dataPipe[0]); + if (! (flags & ECORE_EXE_PIPE_WRITE)) + close(dataPipe[1]); close(statusPipe[1]); while (1) @@ -181,38 +195,48 @@ n = 0; if (pid) { - close(dataPipe[0]); - if (WIFEXITED(n)) { + if (flags & ECORE_EXE_PIPE_READ) + close(dataPipe[0]); + if (flags & ECORE_EXE_PIPE_WRITE) + close(dataPipe[1]); + n = WEXITSTATUS(n); printf("Process %s returned %i\n", exe_cmd, n); pid = 0; } else - n = -1; + { + n = -1; + + exe = calloc(1, sizeof(Ecore_Exe)); + if (!exe) + { + if (flags & ECORE_EXE_PIPE_READ) + close(dataPipe[0]); + if (flags & ECORE_EXE_PIPE_WRITE) + close(dataPipe[1]); + kill(pid, SIGKILL); + printf("No memory for Ecore_Exe %s\n", exe_cmd); + return NULL; + } + ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); + exe->pid = pid; + exe->flags = flags; + exe->data = (void *)data; + if (flags & ECORE_EXE_PIPE_READ) + exe->child_fd_read = dataPipe[0]; + if (flags & ECORE_EXE_PIPE_WRITE) + exe->child_fd_write = dataPipe[1]; + exes = _ecore_list2_append(exes, exe); + } } free(args); errno = n; - if (pid) - { - exe = calloc(1, sizeof(Ecore_Exe)); - if (!exe) - { - kill(pid, SIGKILL); - printf("No memory for Ecore_Exe %s\n", exe_cmd); - return NULL; - } - ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); - exe->pid = pid; - exe->data = (void *)data; - exes = _ecore_list2_append(exes, exe); - return exe; - } - - return NULL; + return exe; } /** |
From: <enl...@li...> - 2005-11-09 13:57:51
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h Ecore.h Log Message: Getting ready for fork'n'pipe. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.22 retrieving revision 1.23 diff -u -3 -r1.22 -r1.23 --- ecore_private.h 25 Oct 2005 07:21:52 -0000 1.22 +++ ecore_private.h 9 Nov 2005 13:57:45 -0000 1.23 @@ -119,8 +119,9 @@ enum _Ecore_Exe_Flags { ECORE_EXE_PIPE_READ = 1, - ECORE_EXE_PIPE_WRITE = 2, - ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4 + ECORE_EXE_PIPE_WRITE = 2, + ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4, + ECORE_EXE_RESPAWN = 8 }; typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; @@ -145,14 +146,16 @@ pid_t pid; void *data; char *tag; + char *cmd; Ecore_Exe_Flags flags; + char *args[4]; /* Arguments for child */ Ecore_Fd_Handler *fd_handler; /* FIXME: the fd_handler to handle read/write to child - if this was used, or NULL if not */ - void *write_data_buf; /* FIXME: a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ - int write_data_size; /* FIXME: the size in bytes of the data buffer */ - void *read_data_buf; /* FIXME: data read from the child awating delivery to an event */ - int read_data_size; /* FIXME: data read from child in bytes */ - int child_fd_write; /* FIXME: fd to write TO to send data to the child */ - int child_fd_read; /* FIXME: fd to read FROM whne child has send us (parent) data */ + void *write_data_buf; /* FIXME: a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ + int write_data_size; /* FIXME: the size in bytes of the data buffer */ + void *read_data_buf; /* FIXME: data read from the child awating delivery to an event */ + int read_data_size; /* FIXME: data read from child in bytes */ + int child_fd_write; /* fd to write TO to send data to the child */ + int child_fd_read; /* fd to read FROM whne child has send us (parent) data */ }; #endif =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/Ecore.h,v retrieving revision 1.27 retrieving revision 1.28 diff -u -3 -r1.27 -r1.28 --- Ecore.h 24 Oct 2005 08:53:50 -0000 1.27 +++ Ecore.h 9 Nov 2005 13:57:45 -0000 1.28 @@ -78,7 +78,8 @@ { ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */ ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */ - ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4 /**< Reads are buffered until a newline and delivered 1 event per line */ + ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4, /**< Reads are buffered until a newline and delivered 1 event per line */ + ECORE_EXE_RESPAWN = 8 /**< Exe is restarted if it dies */ }; typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; @@ -205,6 +206,7 @@ EAPI void ecore_exe_pause(Ecore_Exe *exe); EAPI void ecore_exe_continue(Ecore_Exe *exe); EAPI void ecore_exe_terminate(Ecore_Exe *exe); + EAPI void ecore_exe_kill_maybe(Ecore_Exe *exe); EAPI void ecore_exe_kill(Ecore_Exe *exe); EAPI void ecore_exe_signal(Ecore_Exe *exe, int num); EAPI void ecore_exe_hup(Ecore_Exe *exe); |
From: <enl...@li...> - 2005-11-09 13:59:24
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_signal.c Log Message: Getting ready for fork'n'pipe. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_signal.c,v retrieving revision 1.17 retrieving revision 1.18 diff -u -3 -r1.17 -r1.18 --- ecore_signal.c 24 Oct 2005 08:53:50 -0000 1.17 +++ ecore_signal.c 9 Nov 2005 13:59:03 -0000 1.18 @@ -166,6 +166,9 @@ * errors - THEN report and exe - so store this exe value in the * ecore_exe struct waiting for the read fd to die then report * final read data, THEN this exit event + * + * If this process is set respawn, respawn with a suitable backoff + * for those that need too much respawning. */ e = _ecore_event_exe_exit_new(); if (e) |
From: <enl...@li...> - 2005-11-09 14:09:35
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Beginnings of fork'n'pipe. Don't use ecore_exe_pipe_run() yet, it is not finished. You can use ecore_exe_pipe_write(), but it will do nothing. I committed this because someone wanted to play with it in it's current state. ecore_exe_pipe_run() will startup your exe, and open the pipes that you request, and everything should get cleaned up when the exe closes. The pipes are in the Ecore_Exe struct, you can use them. The next thing I will add will be proper use of the pipes. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -3 -r1.16 -r1.17 --- ecore_exe.c 25 Oct 2005 07:30:29 -0000 1.16 +++ ecore_exe.c 9 Nov 2005 14:09:28 -0000 1.17 @@ -82,9 +82,8 @@ pid_t pid = 0; int dataPipe[2] = { -1, -1 }; int statusPipe[2] = { -1, -1 }; - int n; + int n = 0; volatile int vfork_exec_errno = 0; - char **args; /* FIXME: * set up fd handler in ecore_exe struct @@ -94,6 +93,8 @@ * connection is closed. once this event has been handled the child * ecore_exe struct is freed automatically and is no longer valid. * + * _ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler) + * * when fd handlers report data - if line buffering is nto enabled instantly * copy data to a exe data event struct and add the event like ecore_con. if * line buffering is enabled, parse new data block for a \n. if there is @@ -111,129 +112,116 @@ if (shell == 0) { shell = getenv("SHELL"); - if (shell == 0) - shell = "/bin/sh"; + if (shell == 0) + shell = "/bin/sh"; } - args = (char **) calloc(4, sizeof(char *)); - n = 0; - args[n++] = shell; - args[n++] = "-c"; - args[n++] = exe_cmd; - args[n++] = 0; - - if (pipe(dataPipe) < 0 || pipe(statusPipe) < 0) - printf("Failed to create pipe\n"); - /* FIXME: I should check this. */ - signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ + exe = calloc(1, sizeof(Ecore_Exe)); + if (exe == NULL) return NULL; + + exe->args[n++] = shell; + exe->args[n++] = "-c"; + exe->args[n++] = exe_cmd; + exe->args[n++] = NULL; + + if ((pipe(dataPipe) == -1) || pipe(statusPipe) == -1) + printf("Failed to create pipes\n"); + /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ + /* signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ pid = fork(); - if (pid == 0) - { /* child */ - setsid(); + if (pid == -1) + { + printf("Failed to fork process\n"); + pid = 0; + } + else if (pid == 0) /* child */ + { + setsid(); /* FIXME: Check for -1 then errno. */ + close(STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ + close(STDERR_FILENO); /* FIXME: Check for -1 then errno. */ + close(STDIN_FILENO); /* FIXME: Check for -1 then errno. */ if (flags & ECORE_EXE_PIPE_READ) { - dup2(dataPipe[1], STDOUT_FILENO); - dup2(dataPipe[1], STDERR_FILENO); + dup2(dataPipe[1], STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ + dup2(dataPipe[1], STDERR_FILENO); /* FIXME: Check for -1 then errno. */ } else { - close(dataPipe[1]); - close(STDOUT_FILENO); - close(STDERR_FILENO); + close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ } if (flags & ECORE_EXE_PIPE_WRITE) { - dup2(dataPipe[0], STDIN_FILENO); + dup2(dataPipe[0], STDIN_FILENO); /* FIXME: Check for -1 then errno. */ } else { - close(dataPipe[0]); - close(STDIN_FILENO); + close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ } - close(statusPipe[0]); - fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ + close(statusPipe[0]); /* FIXME: Check for -1 then errno. */ + fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ /* FIXME: Check for -1 then errno. */ errno = 0; - execvp(shell, (char **) args); + execvp(shell, (char **) exe->args); + /* Something went 'orribly wrong. */ vfork_exec_errno = errno; - close(statusPipe[1]); +// if (! (flags & ECORE_EXE_PIPE_READ)) +// close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ +// if (! (flags & ECORE_EXE_PIPE_WRITE)) +// close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ +// close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ _exit(-1); } - else if (pid > 0) - { /* parent */ + else /* parent */ + { if (! (flags & ECORE_EXE_PIPE_READ)) - close(dataPipe[0]); + close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ if (! (flags & ECORE_EXE_PIPE_WRITE)) - close(dataPipe[1]); - close(statusPipe[1]); + close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ + close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ - while (1) + /* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */ + + while (1) /* Wait for it to start executing. */ { char buf; n = read(statusPipe[0], &buf, 1); - if (n == 0 && vfork_exec_errno != 0) + if ((n == -1) && ((errno == EAGAIN) || (errno == EINTR))) + continue; /* try it again */ + if (n == 0) { - errno = vfork_exec_errno; - printf("Could not exec process\n"); - } - break; + if (vfork_exec_errno != 0) + { + n = vfork_exec_errno; + printf("Could not exec process\n"); /* FIXME: maybe set the pid to 0? */ + } + break; + } } close(statusPipe[0]); } - else - { - printf("Failed to fork process\n"); - pid = 0; - } - n = 0; if (pid) { - if (WIFEXITED(n)) - { - if (flags & ECORE_EXE_PIPE_READ) - close(dataPipe[0]); - if (flags & ECORE_EXE_PIPE_WRITE) - close(dataPipe[1]); - - n = WEXITSTATUS(n); - printf("Process %s returned %i\n", exe_cmd, n); - pid = 0; - } - else - { - n = -1; - - exe = calloc(1, sizeof(Ecore_Exe)); - if (!exe) - { - if (flags & ECORE_EXE_PIPE_READ) - close(dataPipe[0]); - if (flags & ECORE_EXE_PIPE_WRITE) - close(dataPipe[1]); - kill(pid, SIGKILL); - printf("No memory for Ecore_Exe %s\n", exe_cmd); - return NULL; - } - ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); - exe->pid = pid; - exe->flags = flags; - exe->data = (void *)data; - if (flags & ECORE_EXE_PIPE_READ) - exe->child_fd_read = dataPipe[0]; - if (flags & ECORE_EXE_PIPE_WRITE) - exe->child_fd_write = dataPipe[1]; - exes = _ecore_list2_append(exes, exe); - } + ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); + exe->pid = pid; + exe->flags = flags; + exe->data = (void *)data; + exe->cmd = exe_cmd; /* FIXME: should calloc and cpy. */ + if (flags & ECORE_EXE_PIPE_READ) + exe->child_fd_read = dataPipe[0]; + if (flags & ECORE_EXE_PIPE_WRITE) + exe->child_fd_write = dataPipe[1]; + exes = _ecore_list2_append(exes, exe); + n = 0; + printf("Ecore_Exe %s success!\n", exe_cmd); } - free(args); errno = n; return exe; @@ -374,6 +362,25 @@ */ /** + * Makes sure the process is dead, one way or another. + * @param exe Process handle to the given process. + * @ingroup Ecore_Exe_Signal_Group + */ +void +ecore_exe_kill_maybe(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + /* Since Ecore_Exe's can be freed without the users knowledge, we need a way to kill them without bitchin'. */ + /* FIXME: On the other hand, handling the exe exit event may be the way to go. */ + return; + } + kill(exe->pid, SIGTERM); +/* FIXME: should pause for a bit. */ + kill(exe->pid, SIGKILL); +} + +/** * Pauses the given process by sending it a @c SIGSTOP signal. * @param exe Process handle to the given process. * @ingroup Ecore_Exe_Signal_Group @@ -506,8 +513,15 @@ { void *data; - /* FIXME: close fdhanlders and free buffers if they exist */ +printf("FREEING Ecore_Exe %s\n", exe->cmd); data = exe->data; + + /* FIXME: close fdhanlders and free buffers if they exist */ + if (exe->flags & ECORE_EXE_PIPE_READ) + close(exe->child_fd_read); /* FIXME: Check for -1 then errno. */ + if (exe->flags & ECORE_EXE_PIPE_WRITE) + close(exe->child_fd_write); /* FIXME: Check for -1 then errno. */ + exes = _ecore_list2_remove(exes, exe); ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); if (exe->tag) free(exe->tag); |
From: <enl...@li...> - 2005-11-09 20:01:37
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Brain dead, quick'n'dirty pipe writer, Strictly for testing purposes. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.17 retrieving revision 1.18 diff -u -3 -r1.17 -r1.18 --- ecore_exe.c 9 Nov 2005 14:09:28 -0000 1.17 +++ ecore_exe.c 9 Nov 2005 20:01:32 -0000 1.18 @@ -249,8 +249,17 @@ * its own write buffer in process space - giving us potentially huge * buffers, so synchronisation needs to be done at a higher level here as * buffers could just get huge + * + * But for now, a quick and dirty test implementation - */ - return 0; + ssize_t outsize = write(exe->child_fd_write, data, size); + if (outsize == -1) + { + /* FIXME: should check errno to see what went wrong. */ + return 0; + } + else + return 1; } /** |
From: <enl...@li...> - 2005-11-29 22:22:27
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Remove the kill_maybe that slipped in a while ago. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -3 -r1.19 -r1.20 --- ecore_exe.c 29 Nov 2005 12:39:09 -0000 1.19 +++ ecore_exe.c 29 Nov 2005 22:22:21 -0000 1.20 @@ -225,11 +225,11 @@ /* Something went 'orribly wrong. */ vfork_exec_errno = errno; -// if (! (flags & ECORE_EXE_PIPE_READ)) -// close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ -// if (! (flags & ECORE_EXE_PIPE_WRITE)) -// close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ -// close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ + if (! (flags & ECORE_EXE_PIPE_READ)) + close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ + if (! (flags & ECORE_EXE_PIPE_WRITE)) + close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ + close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ _exit(-1); } else /* parent */ @@ -429,25 +429,6 @@ */ /** - * Makes sure the process is dead, one way or another. - * @param exe Process handle to the given process. - * @ingroup Ecore_Exe_Signal_Group - */ -void -ecore_exe_kill_maybe(Ecore_Exe *exe) -{ - if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) - { - /* Since Ecore_Exe's can be freed without the users knowledge, we need a way to kill them without bitchin'. */ - /* FIXME: On the other hand, handling the exe exit event may be the way to go. */ - return; - } - kill(exe->pid, SIGTERM); -/* FIXME: should pause for a bit. */ - kill(exe->pid, SIGKILL); -} - -/** * Pauses the given process by sending it a @c SIGSTOP signal. * @param exe Process handle to the given process. * @ingroup Ecore_Exe_Signal_Group @@ -580,7 +561,6 @@ { void *data; -printf("FREEING Ecore_Exe %s\n", exe->cmd); data = exe->data; /* FIXME: close fdhanlders and free buffers if they exist */ |
From: <enl...@li...> - 2005-12-10 22:39:26
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h Log Message: Fork'n'pipe now actually pipes. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.23 retrieving revision 1.24 diff -u -3 -r1.23 -r1.24 --- ecore_private.h 9 Nov 2005 13:57:45 -0000 1.23 +++ ecore_private.h 10 Dec 2005 22:39:19 -0000 1.24 @@ -47,6 +47,8 @@ #define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) #endif +#define READBUFSIZ 65536 + #define ECORE_MAGIC_NONE 0x1234fedc #define ECORE_MAGIC_EXE 0xf7e812f5 #define ECORE_MAGIC_TIMER 0xf7d713f4 @@ -148,14 +150,15 @@ char *tag; char *cmd; Ecore_Exe_Flags flags; - char *args[4]; /* Arguments for child */ - Ecore_Fd_Handler *fd_handler; /* FIXME: the fd_handler to handle read/write to child - if this was used, or NULL if not */ + Ecore_Fd_Handler *write_fd_handler; /* FIXME: the fd_handler to handle write to child - if this was used, or NULL if not */ + Ecore_Fd_Handler *read_fd_handler; /* FIXME: the fd_handler to handle read from child - if this was used, or NULL if not */ void *write_data_buf; /* FIXME: a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ int write_data_size; /* FIXME: the size in bytes of the data buffer */ + int write_data_offset; /* FIXME: the offset in bytes in the data buffer */ void *read_data_buf; /* FIXME: data read from the child awating delivery to an event */ int read_data_size; /* FIXME: data read from child in bytes */ int child_fd_write; /* fd to write TO to send data to the child */ - int child_fd_read; /* fd to read FROM whne child has send us (parent) data */ + int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */ }; #endif |
From: <enl...@li...> - 2005-12-10 22:39:58
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Fork'n'pipe now actually pipes. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -3 -r1.20 -r1.21 --- ecore_exe.c 29 Nov 2005 22:22:21 -0000 1.20 +++ ecore_exe.c 10 Dec 2005 22:39:51 -0000 1.21 @@ -5,7 +5,15 @@ #include <sys/wait.h> #ifndef WIN32 + +static void _ecore_exe_exec_it(const char *exe_cmd); +static int _ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler); +static int _ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler); +static void _ecore_exe_flush(Ecore_Exe *exe); +static void _ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev); + static Ecore_Exe *exes = NULL; +static char *shell = NULL; /** * @defgroup Ecore_Exe_Basic_Group Process Spawning Functions @@ -49,6 +57,7 @@ exes = _ecore_list2_append(exes, exe); return exe; } +/* FIXME: replace this lot with _ecore_exe_exec_it(exe_cmd); once it gets a bit of testing. */ { char use_sh = 1; char* buf = NULL; @@ -113,9 +122,6 @@ return NULL; } - -static char *shell = 0; - /** * Spawns a child process with its stdin/out available for communication. * @@ -123,7 +129,7 @@ * standard in and/or out from the child process available for reading or * writing. To write use ecore_exe_pipe_write(). To read listen to * ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read data - * until a newline character if asked to wit the @p flags. All data will be + * until a newline character if asked for with the @p flags. All data will be * included in the events (newlines will not be stripped). This will only * happen if the process is run with ECORE_EXE_PIPE_READ enabled in the flags. * @@ -138,51 +144,20 @@ { Ecore_Exe *exe = NULL; pid_t pid = 0; - int dataPipe[2] = { -1, -1 }; + int readPipe[2] = { -1, -1 }; + int writePipe[2] = { -1, -1 }; int statusPipe[2] = { -1, -1 }; int n = 0; volatile int vfork_exec_errno = 0; - /* FIXME: - * set up fd handler in ecore_exe struct - * see ecore_con for code and examples on this (fd's there are to a socket - * but otherwise work the same as here). the ECORE_EVENT_EXE_EXIT event - * aces like the client del event from ecore_con - signalling that the - * connection is closed. once this event has been handled the child - * ecore_exe struct is freed automatically and is no longer valid. - * - * _ecore_con_svr_cl_handler(void *data, Ecore_Fd_Handler *fd_handler) - * - * when fd handlers report data - if line buffering is nto enabled instantly - * copy data to a exe data event struct and add the event like ecore_con. if - * line buffering is enabled, parse new data block for a \n. if there is - * none, then simply append to read buf. if there are 1 or more, append - * until, and including the first \n, to the existing read ubf (if any) then - * generate data event for that. repeat for each other \n found until no \n - * chars are left, then take trailing data (if any) and put in read buf - * waiting for more data. - */ - if (!exe_cmd) return NULL; if ((flags & (ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE)) == 0) return ecore_exe_run(exe_cmd, data); - if (shell == 0) - { - shell = getenv("SHELL"); - if (shell == 0) - shell = "/bin/sh"; - } - exe = calloc(1, sizeof(Ecore_Exe)); if (exe == NULL) return NULL; - exe->args[n++] = shell; - exe->args[n++] = "-c"; - exe->args[n++] = exe_cmd; - exe->args[n++] = NULL; - - if ((pipe(dataPipe) == -1) || pipe(statusPipe) == -1) + if ((pipe(readPipe) == -1) || (pipe(writePipe) == -1) || (pipe(statusPipe) == -1)) printf("Failed to create pipes\n"); /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ /* signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ @@ -195,52 +170,49 @@ } else if (pid == 0) /* child */ { - setsid(); /* FIXME: Check for -1 then errno. */ - close(STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ close(STDERR_FILENO); /* FIXME: Check for -1 then errno. */ close(STDIN_FILENO); /* FIXME: Check for -1 then errno. */ if (flags & ECORE_EXE_PIPE_READ) { - dup2(dataPipe[1], STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ - dup2(dataPipe[1], STDERR_FILENO); /* FIXME: Check for -1 then errno. */ + dup2(readPipe[1], STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ +// dup2(dataPipe[1], STDERR_FILENO); /* FIXME: Check for -1 then errno. */ } else { - close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ + close(readPipe[1]); /* FIXME: Check for -1 then errno. */ } if (flags & ECORE_EXE_PIPE_WRITE) { - dup2(dataPipe[0], STDIN_FILENO); /* FIXME: Check for -1 then errno. */ + dup2(writePipe[0], STDIN_FILENO); /* FIXME: Check for -1 then errno. */ } else { - close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ + close(writePipe[0]); /* FIXME: Check for -1 then errno. */ } close(statusPipe[0]); /* FIXME: Check for -1 then errno. */ fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ /* FIXME: Check for -1 then errno. */ - errno = 0; - execvp(shell, (char **) exe->args); + _ecore_exe_exec_it(exe_cmd); /* Something went 'orribly wrong. */ vfork_exec_errno = errno; - if (! (flags & ECORE_EXE_PIPE_READ)) - close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ - if (! (flags & ECORE_EXE_PIPE_WRITE)) - close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ + if (flags & ECORE_EXE_PIPE_READ) + close(readPipe[1]); /* FIXME: Check for -1 then errno. */ + if (flags & ECORE_EXE_PIPE_WRITE) + close(writePipe[0]); /* FIXME: Check for -1 then errno. */ close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ _exit(-1); } else /* parent */ { if (! (flags & ECORE_EXE_PIPE_READ)) - close(dataPipe[0]); /* FIXME: Check for -1 then errno. */ + close(readPipe[0]); /* FIXME: Check for -1 then errno. */ if (! (flags & ECORE_EXE_PIPE_WRITE)) - close(dataPipe[1]); /* FIXME: Check for -1 then errno. */ + close(writePipe[1]); /* FIXME: Check for -1 then errno. */ close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ - /* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */ +/* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */ while (1) /* Wait for it to start executing. */ { @@ -272,9 +244,21 @@ exe->data = (void *)data; exe->cmd = exe_cmd; /* FIXME: should calloc and cpy. */ if (flags & ECORE_EXE_PIPE_READ) - exe->child_fd_read = dataPipe[0]; + { + exe->child_fd_read = readPipe[0]; + fcntl(exe->child_fd_read, F_SETFL, O_NONBLOCK); /* FIXME: Check for -1 then errno. */ + exe->read_fd_handler = ecore_main_fd_handler_add(exe->child_fd_read, + ECORE_FD_READ, _ecore_exe_data_read_handler, exe, + NULL, NULL); + } if (flags & ECORE_EXE_PIPE_WRITE) - exe->child_fd_write = dataPipe[1]; + { + exe->child_fd_write = writePipe[1]; + exe->write_fd_handler = ecore_main_fd_handler_add(exe->child_fd_write, + ECORE_FD_WRITE, _ecore_exe_data_write_handler, exe, + NULL, NULL); + } + exes = _ecore_list2_append(exes, exe); n = 0; printf("Ecore_Exe %s success!\n", exe_cmd); @@ -301,23 +285,16 @@ int ecore_exe_pipe_write(Ecore_Exe *exe, void *data, int size) { - /* FIXME: add data to buffer and flag fd handlers to wake up when write - * to child fd is available, and when it is, flush as much data as possible - * at that time (much like ecore_con). this means the parent is mallocing - * its own write buffer in process space - giving us potentially huge - * buffers, so synchronisation needs to be done at a higher level here as - * buffers could just get huge - * - * But for now, a quick and dirty test implementation - - */ - ssize_t outsize = write(exe->child_fd_write, data, size); - if (outsize == -1) - { - /* FIXME: should check errno to see what went wrong. */ - return 0; - } - else - return 1; + void *buf; + + buf = realloc(exe->write_data_buf, exe->write_data_size + size); + if (buf == NULL) return 0; + + exe->write_data_buf = buf; + memcpy(exe->write_data_buf + exe->write_data_size, data, size); + exe->write_data_size += size; + + return 1; } /** @@ -535,6 +512,7 @@ kill(exe->pid, SIGHUP); } + void _ecore_exe_shutdown(void) { @@ -556,6 +534,94 @@ return NULL; } +static void +_ecore_exe_exec_it(const char *exe_cmd) +{ + char use_sh = 1; + char* buf = NULL; + char** args = NULL; + int save_errno = 0; + + if (! strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#")) + { + char* token; + char pre_command = 1; + int num_tokens = 0; + + if (! (buf = strdup(exe_cmd))) + return; + + token = strtok(buf, " \t\n\v"); + while(token) + { + if (token[0] == '~') + break; + if (pre_command) + { + if (token[0] == '[') + break; + if (strchr(token, '=')) + break; + else + pre_command = 0; + } + num_tokens ++; + token = strtok(NULL, " \t\n\v"); + } + free(buf); + buf = NULL; + if (! token && num_tokens) + { + int i = 0; + char* token; + + if (! (buf = strdup(exe_cmd))) + return; + + token = strtok(buf, " \t\n\v"); + use_sh = 0; + if (! (args = (char**) calloc(num_tokens + 1, sizeof(char*)))) + { + free (buf); + return; + } + for (i = 0; i < num_tokens; i ++) + { + if (token) + args[i] = token; + token = strtok(NULL, " \t\n\v"); + } + args[num_tokens] = NULL; + } + } + + setsid(); + if (use_sh) + { + if (shell == NULL) + { + shell = getenv("SHELL"); + if (shell == 0) + shell = "/bin/sh"; + } + errno = 0; + execl(shell, shell, "-c", exe_cmd, (char *)NULL); + } + else + { + errno = 0; + execvp(args[0], args); + } + + save_errno = errno; + if (buf) + free(buf); + if(args) + free(args); + errno = save_errno; + return; +} + void * _ecore_exe_free(Ecore_Exe *exe) { @@ -563,11 +629,12 @@ data = exe->data; - /* FIXME: close fdhanlders and free buffers if they exist */ - if (exe->flags & ECORE_EXE_PIPE_READ) - close(exe->child_fd_read); /* FIXME: Check for -1 then errno. */ - if (exe->flags & ECORE_EXE_PIPE_WRITE) - close(exe->child_fd_write); /* FIXME: Check for -1 then errno. */ + if (exe->write_fd_handler) ecore_main_fd_handler_del(exe->write_fd_handler); + if (exe->read_fd_handler) ecore_main_fd_handler_del(exe->read_fd_handler); + if (exe->write_data_buf) free(exe->write_data_buf); + if (exe->read_data_buf) free(exe->read_data_buf); + if (exe->flags & ECORE_EXE_PIPE_READ) close(exe->child_fd_read); /* FIXME: Check for -1 then errno. */ + if (exe->flags & ECORE_EXE_PIPE_WRITE) close(exe->child_fd_write); /* FIXME: Check for -1 then errno. */ exes = _ecore_list2_remove(exes, exe); ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); @@ -575,4 +642,138 @@ free(exe); return data; } + + +static int +_ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + Ecore_Exe *exe; + + exe = data; + if ((exe->read_fd_handler) && (ecore_main_fd_handler_active_get(exe->read_fd_handler, ECORE_FD_READ))) + { + unsigned char *inbuf = NULL; + int inbuf_num = 0; + + for (;;) + { + int num, lost_server; + char buf[READBUFSIZ]; + + lost_server = 0; + errno = 0; + if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1) + { + lost_server = ((errno == EIO) || + (errno == EBADF) || + (errno == EPIPE) || + (errno == EINVAL) || + (errno == ENOSPC) || + (num == 0)); + /* is num == 0 is right - when the server closes us + * off we will get this (as this is called when select + * tells us there is data to read!) + */ + if ((errno != EAGAIN) && (errno != EINTR)) + perror("_ecore_exe_data_handler() read problem "); + } + if (num < 1) + { + if (inbuf) + { + Ecore_Event_Exe_Data *e; + + e = calloc(1, sizeof(Ecore_Event_Exe_Data)); + if (e) + { + e->exe = exe; + e->data = inbuf; + e->size = inbuf_num; + ecore_event_add(ECORE_EVENT_EXE_DATA, e, + _ecore_exe_event_exe_data_free, NULL); + } + } + if (lost_server) + { + /* we lost our server! */ + ecore_exe_terminate(exe); + return 1; + } + break; + } + else + { + inbuf = realloc(inbuf, inbuf_num + num); + memcpy(inbuf + inbuf_num, buf, num); + inbuf_num += num; + /* FIXME: + * when fd handlers report data - if line buffering is not enabled instantly + * copy data to a exe data event struct and add the event like ecore_con. if + * line buffering is enabled, parse new data block for a \n. if there is + * none, then simply append to read buf. if there are 1 or more, append + * until, and including the first \n, to the existing read buf (if any) then + * generate data event for that. repeat for each other \n found until no \n + * chars are left, then take trailing data (if any) and put in read buf + * waiting for more data. + */ + } + } + } + + return 1; +} + +static int +_ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + Ecore_Exe *exe; + + exe = data; + if ((exe->write_fd_handler) && (ecore_main_fd_handler_active_get(exe->write_fd_handler, ECORE_FD_WRITE))) + _ecore_exe_flush(exe); + + return 1; +} + +static void +_ecore_exe_flush(Ecore_Exe *exe) +{ + int count; + + /* check whether we need to write anything at all. */ + if ((!exe->child_fd_write) && (!exe->write_data_buf)) return; + if (exe->write_data_size == exe->write_data_offset) return; + + count = write(exe->child_fd_write, + exe->write_data_buf + exe->write_data_offset, + exe->write_data_size - exe->write_data_offset); + if (count < 1) + { + if (errno == EIO || errno == EBADF || + errno == EPIPE || errno == EINVAL || + errno == ENOSPC) /* we lost our server! */ + ecore_exe_terminate(exe); + } + else + { + exe->write_data_offset += count; + if (exe->write_data_offset >= exe->write_data_size) + { + exe->write_data_size = 0; + exe->write_data_offset = 0; + free(exe->write_data_buf); + exe->write_data_buf = NULL; + } + } +} + +static void +_ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev) +{ + Ecore_Event_Exe_Data *e; + + e = ev; + if (e->data) free(e->data); + free(e); +} #endif |
From: <enl...@li...> - 2005-12-10 22:40:41
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore Modified Files: AUTHORS Log Message: Time I added myself. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/AUTHORS,v retrieving revision 1.18 retrieving revision 1.19 diff -u -3 -r1.18 -r1.19 --- AUTHORS 15 Sep 2005 04:19:45 -0000 1.18 +++ AUTHORS 10 Dec 2005 22:40:34 -0000 1.19 @@ -16,3 +16,4 @@ Jorge Luis Zapata Muga <jor...@gm...> dan sinclair <ze...@ev...> Michael 'Mickey' Lauer <mi...@tm...> +David 'onefang' Seikel <on...@gm...> |
From: <enl...@li...> - 2005-12-11 00:11:18
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Turn off the write handler when not needed. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -3 -r1.21 -r1.22 --- ecore_exe.c 10 Dec 2005 22:39:51 -0000 1.21 +++ ecore_exe.c 11 Dec 2005 00:11:12 -0000 1.22 @@ -257,11 +257,12 @@ exe->write_fd_handler = ecore_main_fd_handler_add(exe->child_fd_write, ECORE_FD_WRITE, _ecore_exe_data_write_handler, exe, NULL, NULL); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); } exes = _ecore_list2_append(exes, exe); n = 0; - printf("Ecore_Exe %s success!\n", exe_cmd); } errno = n; @@ -293,6 +294,9 @@ exe->write_data_buf = buf; memcpy(exe->write_data_buf + exe->write_data_size, data, size); exe->write_data_size += size; + + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE); return 1; } @@ -752,7 +756,11 @@ if (errno == EIO || errno == EBADF || errno == EPIPE || errno == EINVAL || errno == ENOSPC) /* we lost our server! */ - ecore_exe_terminate(exe); + { + ecore_exe_terminate(exe); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); + } } else { @@ -763,6 +771,8 @@ exe->write_data_offset = 0; free(exe->write_data_buf); exe->write_data_buf = NULL; + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); } } } |
From: <enl...@li...> - 2005-12-12 16:49:49
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/examples Modified Files: .cvsignore Log Message: I'm on a .cvsignore cleanup spree. Guess I can take care of this one myself. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/examples/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -u -3 -r1.2 -r1.3 --- .cvsignore 23 Oct 2004 14:27:09 -0000 1.2 +++ .cvsignore 12 Dec 2005 16:49:43 -0000 1.3 @@ -7,6 +7,7 @@ con_server_example config_basic_example event_handler_example +exe_example list_destroy_example list_example timer_example |
From: <enl...@li...> - 2005-12-16 01:10:08
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h Log Message: The FIXME's have been. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.24 retrieving revision 1.25 diff -u -3 -r1.24 -r1.25 --- ecore_private.h 10 Dec 2005 22:39:19 -0000 1.24 +++ ecore_private.h 16 Dec 2005 01:09:52 -0000 1.25 @@ -150,13 +150,13 @@ char *tag; char *cmd; Ecore_Exe_Flags flags; - Ecore_Fd_Handler *write_fd_handler; /* FIXME: the fd_handler to handle write to child - if this was used, or NULL if not */ - Ecore_Fd_Handler *read_fd_handler; /* FIXME: the fd_handler to handle read from child - if this was used, or NULL if not */ - void *write_data_buf; /* FIXME: a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ - int write_data_size; /* FIXME: the size in bytes of the data buffer */ - int write_data_offset; /* FIXME: the offset in bytes in the data buffer */ - void *read_data_buf; /* FIXME: data read from the child awating delivery to an event */ - int read_data_size; /* FIXME: data read from child in bytes */ + Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to child - if this was used, or NULL if not */ + Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from child - if this was used, or NULL if not */ + void *write_data_buf; /* a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ + int write_data_size; /* the size in bytes of the data buffer */ + int write_data_offset; /* the offset in bytes in the data buffer */ + void *read_data_buf; /* data read from the child awating delivery to an event */ + int read_data_size; /* data read from child in bytes */ int child_fd_write; /* fd to write TO to send data to the child */ int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */ }; |
From: <enl...@li...> - 2005-12-16 01:11:36
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: Ecore.h Log Message: Preperation for line buffering, coming soon. Just gotta spend the rest of the day testing it. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/Ecore.h,v retrieving revision 1.28 retrieving revision 1.29 diff -u -3 -r1.28 -r1.29 --- Ecore.h 9 Nov 2005 13:57:45 -0000 1.28 +++ Ecore.h 16 Dec 2005 01:11:24 -0000 1.29 @@ -102,6 +102,7 @@ typedef struct _Ecore_Event_Signal_Exit Ecore_Event_Signal_Exit; /**< Exit signal event */ typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */ typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */ + typedef struct _Ecore_Event_Exe_Data_Line Ecore_Event_Exe_Data_Line; /**< Lines from a child process */ typedef struct _Ecore_Event_Exe_Data Ecore_Event_Exe_Data; /**< Data from a child process */ #ifndef WIN32 @@ -168,11 +169,18 @@ }; #ifndef WIN32 + struct _Ecore_Event_Exe_Data_Line /**< Lines from a child process */ + { + char *line; + int size; + }; + struct _Ecore_Event_Exe_Data /** Data from a child process event */ { Ecore_Exe *exe; /**< The handle to the process */ void *data; /**< the raw binary data from the child process that was recieved */ int size; /**< the size of this data in bytes */ + Ecore_Event_Exe_Data_Line *lines; /**< an array of line data if line buffered */ }; #endif |
From: <enl...@li...> - 2005-12-16 03:34:04
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: Ecore.h Log Message: Document that the lines array is NULL terminated. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/Ecore.h,v retrieving revision 1.29 retrieving revision 1.30 diff -u -3 -r1.29 -r1.30 --- Ecore.h 16 Dec 2005 01:11:24 -0000 1.29 +++ Ecore.h 16 Dec 2005 03:33:52 -0000 1.30 @@ -180,7 +180,7 @@ Ecore_Exe *exe; /**< The handle to the process */ void *data; /**< the raw binary data from the child process that was recieved */ int size; /**< the size of this data in bytes */ - Ecore_Event_Exe_Data_Line *lines; /**< an array of line data if line buffered */ + Ecore_Event_Exe_Data_Line *lines; /**< a NULL terminated array of line data if line buffered */ }; #endif |
From: <enl...@li...> - 2005-12-16 03:36:22
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: The fork'n'pipe knows line dancing! Er, I mean line buffering. It's slightly different from what raster wanted. I'll update the example next. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -3 -r1.23 -r1.24 --- ecore_exe.c 11 Dec 2005 06:52:07 -0000 1.23 +++ ecore_exe.c 16 Dec 2005 03:36:16 -0000 1.24 @@ -127,12 +127,15 @@ * * This function does the same thing as ecore_exe_run(), but also makes the * standard in and/or out from the child process available for reading or - * writing. To write use ecore_exe_pipe_write(). To read listen to - * ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read data - * until a newline character if asked for with the @p flags. All data will be - * included in the events (newlines will not be stripped). This will only - * happen if the process is run with ECORE_EXE_PIPE_READ enabled in the flags. - * + * writing. To write use ecore_exe_pipe_write(). To read listen to + * ECORE_EVENT_EXE_DATA events (set up a handler). Ecore may buffer read + * data until a newline character if asked for with the @p flags. All + * data will be included in the events (newlines will be replaced with + * NULLS if line buffered). ECORE_EVENT_EXE_DATA events will only happen + * if the process is run with ECORE_EXE_PIPE_READ enabled in the flags. + * Writing will only be allowed with ECORE_EXE_PIPE_WRITE enabled in the + * flags. + * * @param exe_cmd The command to run with @c /bin/sh. * @param flags The flag parameters for how to deal with inter-process I/O * @param data Data to attach to the returned process handle. @@ -142,6 +145,7 @@ Ecore_Exe * ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { +/* FIXME: MAybe we should allow STDERR reading as well. */ Ecore_Exe *exe = NULL; pid_t pid = 0; int readPipe[2] = { -1, -1 }; @@ -658,73 +662,120 @@ exe = data; if ((exe->read_fd_handler) && (ecore_main_fd_handler_active_get(exe->read_fd_handler, ECORE_FD_READ))) { - unsigned char *inbuf = NULL; - int inbuf_num = 0; + unsigned char *inbuf; + int inbuf_num; + + inbuf = exe->read_data_buf; + inbuf_num = exe->read_data_size; + exe->read_data_buf = NULL; + exe->read_data_size = 0; for (;;) { - int num, lost_server; + int num, lost_exe; char buf[READBUFSIZ]; - lost_server = 0; + lost_exe = 0; errno = 0; - if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1) + if ((num = read(exe->child_fd_read, buf, READBUFSIZ)) < 1) /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE (currently 64k) to inbuf, use that instead of buf, and save ourselves a memcpy(). */ { - lost_server = ((errno == EIO) || - (errno == EBADF) || - (errno == EPIPE) || - (errno == EINVAL) || - (errno == ENOSPC) || - (num == 0)); - /* is num == 0 is right - when the server closes us - * off we will get this (as this is called when select - * tells us there is data to read!) - */ + lost_exe = ((errno == EIO) || + (errno == EBADF) || + (errno == EPIPE) || + (errno == EINVAL) || + (errno == ENOSPC)); if ((errno != EAGAIN) && (errno != EINTR)) perror("_ecore_exe_data_handler() read problem "); } - if (num < 1) - { - if (inbuf) - { - Ecore_Event_Exe_Data *e; + if (num > 0) + { + inbuf = realloc(inbuf, inbuf_num + num); + memcpy(inbuf + inbuf_num, buf, num); + inbuf_num += num; + } + else + { + if (inbuf) + { + Ecore_Event_Exe_Data *e; - e = calloc(1, sizeof(Ecore_Event_Exe_Data)); - if (e) - { - e->exe = exe; - e->data = inbuf; - e->size = inbuf_num; - ecore_event_add(ECORE_EVENT_EXE_DATA, e, + e = calloc(1, sizeof(Ecore_Event_Exe_Data)); + if (e) + { + e->exe = exe; + e->data = inbuf; + e->size = inbuf_num; + + if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED) + { + int max = 0; + int count = 0; + int i; + int last = 0; + char *c; + + c = inbuf; + for (i = 0; i < inbuf_num; i++) /* Find the lines. */ + { + if (inbuf[i] == '\n') + { + if (count >= max) + { + max += 10; /* FIXME: Maybe keep track of the largest number of lines ever sent, and add half that many instead of 10. */ + e->lines = realloc(e->lines, sizeof(Ecore_Event_Exe_Data_Line) * (max + 1)); /* Allow room for the NULL termination. */ + } + /* raster said to leave the line endings as line endings, however - + * This is line buffered mode, we are not dealing with binary here, but lines. + * If we are not dealing with binary, we must be dealing with ASCII, unicode, or some other text format. + * Thus the user is most likely gonna deal with this text as strings. + * Thus the user is most likely gonna pass this data to str functions. + * rasters way - the endings are always gonna be '\n'; onefangs way - they will always be '\0' + * We are handing them the string length as a convenience. + * Thus if they really want it in raw format, they can e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough. + * In the default case, we can do this conversion quicker than the user can, as we already have the index and pointer. + * Let's make it easy on them to use these as standard C strings. + * + * onefang is proud to announce that he has just set a new personal record for the + * most over documentation of a simple assignment statement. B-) + */ + inbuf[i] = '\0'; + e->lines[count].line = c; + e->lines[count].size = i - last; + last = i + 1; + c = &inbuf[last]; + count++; + } + } + if (count == 0) /* No lines to send, cancel the event. */ + { + _ecore_exe_event_exe_data_free(NULL, e); + e = NULL; + } + else /* NULL terminate the array, so that people know where the end is. */ + { + e->lines[count].line = NULL; + e->lines[count].size = 0; + } + if (i > last) /* Partial line left over, save it for next time. */ + { + e->size = last; + exe->read_data_size = i - last; + exe->read_data_buf = malloc(exe->read_data_size); + memcpy(exe->read_data_buf, c, exe->read_data_size); + } + } + + if (e) + ecore_event_add(ECORE_EVENT_EXE_DATA, e, _ecore_exe_event_exe_data_free, NULL); - } - } - if (lost_server) - { - /* we lost our server! */ + } + } + if (lost_exe) ecore_exe_terminate(exe); - return 1; - } - break; - } - else - { - inbuf = realloc(inbuf, inbuf_num + num); - memcpy(inbuf + inbuf_num, buf, num); - inbuf_num += num; - /* FIXME: - * when fd handlers report data - if line buffering is not enabled instantly - * copy data to a exe data event struct and add the event like ecore_con. if - * line buffering is enabled, parse new data block for a \n. if there is - * none, then simply append to read buf. if there are 1 or more, append - * until, and including the first \n, to the existing read buf (if any) then - * generate data event for that. repeat for each other \n found until no \n - * chars are left, then take trailing data (if any) and put in read buf - * waiting for more data. - */ - } - } - } + break; + } + } + } return 1; } @@ -785,7 +836,9 @@ Ecore_Event_Exe_Data *e; e = ev; - if (e->data) free(e->data); + + if (e->lines) free(e->lines); + if (e->data) free(e->data); free(e); } #endif |
From: <enl...@li...> - 2005-12-16 04:03:20
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/examples Modified Files: exe_example.c Log Message: The line dancing craze spreads it's evil tenticles. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/examples/exe_example.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -3 -r1.1 -r1.2 --- exe_example.c 11 Dec 2005 06:52:07 -0000 1.1 +++ exe_example.c 16 Dec 2005 04:03:04 -0000 1.2 @@ -19,8 +19,21 @@ ev = event; printf(" [*] DATA RET EXE %p - %p [%i bytes]\n", ev->exe, ev->data, ev->size); - for (i = 0; i < ev->size; i++) - putchar(((unsigned char *)ev->data)[i]); + + if (ev->lines) + { + int i; + + for (i = 0; ev->lines[i].line != NULL; i++) + { + printf("%d %s\n", ev->lines[i].size, ev->lines[i].line); + } + } + else + { + for (i = 0; i < ev->size; i++) + putchar(((unsigned char *)ev->data)[i]); + } printf("\n"); return 1; } @@ -46,7 +59,7 @@ NULL); ecore_exe_pipe_write(exe1, "ls\n", 3); exe2 = ecore_exe_pipe_run("/usr/bin/find / -print", - ECORE_EXE_PIPE_READ, + ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); exe3 = ecore_exe_pipe_run("/bin/cat", ECORE_EXE_PIPE_WRITE, |
From: <enl...@li...> - 2005-12-19 01:37:09
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_main.c Log Message: More documentation for fd_handler return values as per the mailing list discussion. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_main.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -3 -r1.20 -r1.21 --- ecore_main.c 20 Sep 2005 19:15:49 -0000 1.20 +++ ecore_main.c 19 Dec 2005 01:36:55 -0000 1.21 @@ -103,9 +103,19 @@ * * @p func will be called during the execution of @ref ecore_main_loop_begin * when the file descriptor is available for reading, or writing, or both. + * + * Normally the return value from the @p func is "zero means this handler is + * finished and can be deleted" as is usual for handler callbacks. However, + * if the @p buf_func is supplied, then the return value from the @p func is "non + * zero means the handler should be called again in a tight loop". + * * @p buf_func is called during event loop handling to check if data that has * been read from the file descriptor is in a buffer and is available to - * read. + * read. Some systems (notably xlib) handle their own buffering, and would + * otherwise not work with select(). These systems should use a @p buf_func. + * This is a most annoying hack, only ecore_x uses it, so refer to that for + * an example. NOTE - @p func should probably return "one" always if @p buf_func + * is used, to avoid confusion with the other return walue semantics. * * @param fd The file descriptor to watch. * @param flags To watch it for read (@c ECORE_FD_READ) and/or |
From: <enl...@li...> - 2005-12-19 05:08:17
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h ecore_signal.c ecore_exe.c Log Message: Make sure that the Last Words of a dead exe are preserved for future generations. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.25 retrieving revision 1.26 diff -u -3 -r1.25 -r1.26 --- ecore_private.h 16 Dec 2005 01:09:52 -0000 1.25 +++ ecore_private.h 19 Dec 2005 05:07:58 -0000 1.26 @@ -152,13 +152,20 @@ Ecore_Exe_Flags flags; Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to child - if this was used, or NULL if not */ Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from child - if this was used, or NULL if not */ - void *write_data_buf; /* a data buffer for data to write to the child - realloced as needed for more data and flushed when the fd handler says writes are possible */ + void *write_data_buf; /* a data buffer for data to write to the child - + * realloced as needed for more data and flushed when the fd handler says writes are possible + */ int write_data_size; /* the size in bytes of the data buffer */ int write_data_offset; /* the offset in bytes in the data buffer */ void *read_data_buf; /* data read from the child awating delivery to an event */ int read_data_size; /* data read from child in bytes */ int child_fd_write; /* fd to write TO to send data to the child */ int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */ + /* I thought a bit about wether or not their could be multiple exit events, then realised that since we + * delete the exe on the first exit event, the answer is no. On the other hand, STOPing an exe may trigger + * this, even though it has not truly exited. Probably should investigate this further. + */ + struct _Ecore_Event_Exe_Exit *exit_event; /* Process exit event */ }; #endif =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_signal.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -3 -r1.18 -r1.19 --- ecore_signal.c 9 Nov 2005 13:59:03 -0000 1.18 +++ ecore_signal.c 19 Dec 2005 05:07:58 -0000 1.19 @@ -161,14 +161,8 @@ { Ecore_Event_Exe_Exit *e; - /* FIXME: If this process is set to read from the child, DELAY - * the exe event until the pipe from the child dies and reports - * errors - THEN report and exe - so store this exe value in the - * ecore_exe struct waiting for the read fd to die then report - * final read data, THEN this exit event - * - * If this process is set respawn, respawn with a suitable backoff - * for those that need too much respawning. + /* FIXME: If this process is set respawn, respawn with a suitable backoff + * period for those that need too much respawning. */ e = _ecore_event_exe_exit_new(); if (e) @@ -187,9 +181,12 @@ e->exe = _ecore_exe_find(pid); if (sigchld_info.si_signo) - e->data = sigchld_info; + e->data = sigchld_info; /* FIXME: I'm not sure, but maybe we should clone this. I don't know if anybody uses it. */ - _ecore_event_add(ECORE_EVENT_EXE_EXIT, e, + if ((e->exe) && (e->exe->flags & ECORE_EXE_PIPE_READ)) + e->exe->exit_event = e; /* We want to report the Last Words of the exe, so delay this event. */ + else + _ecore_event_add(ECORE_EVENT_EXE_EXIT, e, _ecore_event_exe_exit_free, NULL); } } =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -3 -r1.24 -r1.25 --- ecore_exe.c 16 Dec 2005 03:36:16 -0000 1.24 +++ ecore_exe.c 19 Dec 2005 05:07:58 -0000 1.25 @@ -771,7 +771,16 @@ } } if (lost_exe) - ecore_exe_terminate(exe); + { + if (exe->exit_event) + { + _ecore_event_add(ECORE_EVENT_EXE_EXIT, exe->exit_event, + _ecore_event_exe_exit_free, NULL); + exe->exit_event = NULL; /* Just being paranoid. */ + } + else + ecore_exe_terminate(exe); /* FIXME: give this some deep thought later. */ + } break; } } |
From: <enl...@li...> - 2005-12-24 12:11:47
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_private.h Log Message: Clone another e.h macro. Maybe these should be combined to a common place? =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.26 retrieving revision 1.27 diff -u -3 -r1.26 -r1.27 --- ecore_private.h 19 Dec 2005 05:07:58 -0000 1.26 +++ ecore_private.h 24 Dec 2005 12:11:39 -0000 1.27 @@ -74,6 +74,9 @@ #undef IF_FREE #define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL; +#undef IF_FN_DEL +#define IF_FN_DEL(_fn, ptr) if (ptr) { _fn(ptr); ptr = NULL; } + inline void ecore_print_warning(const char *function, const char *sparam); /* convenience macros for checking pointer parameters for non-NULL */ |
From: <enl...@li...> - 2005-12-24 12:13:18
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: ecore_exe.c Log Message: Generic errno checking. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -3 -r1.25 -r1.26 --- ecore_exe.c 19 Dec 2005 05:07:58 -0000 1.25 +++ ecore_exe.c 24 Dec 2005 12:13:12 -0000 1.26 @@ -15,6 +15,145 @@ static Ecore_Exe *exes = NULL; static char *shell = NULL; + +/* FIXME: This errno checking stuff should be put elsewhere for everybody to use. + * For now it lives here though, just to make testing easier. + */ +int _ecore_exe_check_errno(int result, char *file, int line); +#define E_IF_NO_ERRNO(result, foo, ok) \ + while (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, __LINE__)) == -1) sleep(1); \ + if (ok) + +#define E_NO_ERRNO(result, foo, ok) \ + while (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, __LINE__)) == -1) sleep(1) + +#define E_IF_NO_ERRNO_NOLOOP(result, foo, ok) \ + if (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, __LINE__))) + +int _ecore_exe_check_errno(int result, char *file, int line) +{ + int saved_errno = errno; + + if (result == -1) + { + perror("*** errno reports "); +/* What is currently supported - + * + * pipe + * EFAULT Argument is not valid. + * EMFILE Too many file descriptors used by process. + * ENFILE Too many open files by system. + * read + * EAGAIN No data now, try again. + * EBADF This is not an fd that can be read. + * EFAULT This is not a valid buffer. + * EINTR Interupted by signal, try again. + * EINVAL This is not an fd that can be read. + * EIO I/O error. + * EISDIR This is a directory, and cannot be read. + * others Depending on what sort of thing we are reading from. + * close + * EBADF This is not an fd that can be closed. + * EINTR Interupted by signal, try again. + * EIO I/O error. + * dup2 + * EBADF This is not an fd that can be dup2'ed. + * EBUSY Race condition between open() and dup() + * EINTR Interupted by signal, try again. + * EMFILE Too many file descriptors used by process. + * fcntl + * EACCES, EAGAIN Locked or mapped by something else, try again later. + * EBADF This is not an fd that can be fcntl'ed. + * EDEADLK This will cause a deadlock. + * EFAULT This is not a valid lock. + * EINTR Interupted by signal, try again. + * EINVAL This is not a valid arg. + * EMFILE Too many file descriptors used by process. + * ENOLCK Problem getting a lock. + * EPERM Not allowed to do that. + * + * How to use it - + * int ok = 0; + * int result; + * + * E_IF_NO_ERRNO(result, foo(bar), ok) + * { + * E_IF_NO_ERRNO_NOLOOP(result, foo(bar), ok) + * { + * } + * } + * + * if (!ok) + * { + * // Something failed, cleanup. + * } + */ + switch (result) + { + case EACCES : + case EAGAIN : + case EINTR : + { /* Not now, try later. */ + fprintf(stderr, "*** Must try again in %s @%u.\n", file, line); + result = -1; + break; + } + + case EMFILE : + case ENFILE : + case ENOLCK : + { /* Low on resources. */ + fprintf(stderr, "*** Low on resources in %s @%u.\n", file, line); + result = 0; + break; + } + + case EIO : + { /* I/O error. */ + fprintf(stderr, "*** I/O error in %s @%u.\n", file, line); + result = 0; + break; + } + + case EFAULT : + case EBADF : + case EINVAL : + case EISDIR : + case EDEADLK : + case EPERM : + case EBUSY : + { /* Programmer fucked up. */ + fprintf(stderr, + "*** NAUGHTY PROGRAMMER!!!\n" + "*** SPANK SPANK SPANK!!!\n" + "*** Now go fix your code in %s @%u. Tut tut tut!\n" + "\n", file, line); + result = 0; + break; + } + + default : + { /* Unsupported errno code, please add this one. */ + fprintf(stderr, + "*** NAUGHTY PROGRAMMER!!!\n" + "*** SPANK SPANK SPANK!!!\n" + "*** Unsupported errno code, please add this one.\n" + "*** Now go fix your code in %s @%u. Tut tut tut!\n" + "\n", __FILE__, __LINE__); + result = 0; + break; + } + } + } + else /* Everything is fine. */ + result = 1; + + errno = saved_errno; + return result; +} + + + /** * @defgroup Ecore_Exe_Basic_Group Process Spawning Functions * @@ -57,67 +196,7 @@ exes = _ecore_list2_append(exes, exe); return exe; } -/* FIXME: replace this lot with _ecore_exe_exec_it(exe_cmd); once it gets a bit of testing. */ - { - char use_sh = 1; - char* buf = NULL; - char** args = NULL; - if (! strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#")) - { - if (! (buf = strdup(exe_cmd))) - return NULL; - char* token = strtok(buf, " \t\n\v"); - char pre_command = 1; - int num_tokens = 0; - while(token) - { - if (token[0] == '~') - break; - if (pre_command) - { - if (token[0] == '[') - break; - if (strchr(token, '=')) - break; - else - pre_command = 0; - } - num_tokens ++; - token = strtok(NULL, " \t\n\v"); - } - free(buf); - buf = NULL; - if (! token && num_tokens) - { - int i = 0; - char* token; - if (! (buf = strdup(exe_cmd))) - return NULL; - token = strtok(buf, " \t\n\v"); - use_sh = 0; - if (! (args = (char**) calloc(num_tokens + 1, sizeof(char*)))) { - free (buf); - return NULL; - } - for (i = 0; i < num_tokens; i ++) - { - if (token) - args[i] = token; - token = strtok(NULL, " \t\n\v"); - } - args[num_tokens] = NULL; - } - } - setsid(); - if (use_sh) - execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL); - else - execvp(args[0], args); - if (buf) - free(buf); - if(args) - free(args); - } + _ecore_exe_exec_it(exe_cmd); exit(127); return NULL; } @@ -145,14 +224,12 @@ Ecore_Exe * ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data) { -/* FIXME: MAybe we should allow STDERR reading as well. */ +/* FIXME: Maybe we should allow STDERR reading as well. */ Ecore_Exe *exe = NULL; - pid_t pid = 0; int readPipe[2] = { -1, -1 }; - int writePipe[2] = { -1, -1 }; - int statusPipe[2] = { -1, -1 }; int n = 0; - volatile int vfork_exec_errno = 0; + int ok = 0; + int result; if (!exe_cmd) return NULL; @@ -161,117 +238,159 @@ exe = calloc(1, sizeof(Ecore_Exe)); if (exe == NULL) return NULL; - if ((pipe(readPipe) == -1) || (pipe(writePipe) == -1) || (pipe(statusPipe) == -1)) - printf("Failed to create pipes\n"); - /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ - /* signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ - pid = fork(); - - if (pid == -1) + /* Create some pipes. */ + E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok) { - printf("Failed to fork process\n"); - pid = 0; - } - else if (pid == 0) /* child */ - { - close(STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ - close(STDERR_FILENO); /* FIXME: Check for -1 then errno. */ - close(STDIN_FILENO); /* FIXME: Check for -1 then errno. */ - if (flags & ECORE_EXE_PIPE_READ) - { - dup2(readPipe[1], STDOUT_FILENO); /* FIXME: Check for -1 then errno. */ -// dup2(dataPipe[1], STDERR_FILENO); /* FIXME: Check for -1 then errno. */ - } - else - { - close(readPipe[1]); /* FIXME: Check for -1 then errno. */ - } - if (flags & ECORE_EXE_PIPE_WRITE) - { - dup2(writePipe[0], STDIN_FILENO); /* FIXME: Check for -1 then errno. */ - } - else - { - close(writePipe[0]); /* FIXME: Check for -1 then errno. */ - } - close(statusPipe[0]); /* FIXME: Check for -1 then errno. */ - fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC); /* close on exec shows sucess */ /* FIXME: Check for -1 then errno. */ + int writePipe[2] = { -1, -1 }; - _ecore_exe_exec_it(exe_cmd); + E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok) + { + int statusPipe[2] = { -1, -1 }; - /* Something went 'orribly wrong. */ - vfork_exec_errno = errno; - if (flags & ECORE_EXE_PIPE_READ) - close(readPipe[1]); /* FIXME: Check for -1 then errno. */ - if (flags & ECORE_EXE_PIPE_WRITE) - close(writePipe[0]); /* FIXME: Check for -1 then errno. */ - close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ - _exit(-1); - } - else /* parent */ - { - if (! (flags & ECORE_EXE_PIPE_READ)) - close(readPipe[0]); /* FIXME: Check for -1 then errno. */ - if (! (flags & ECORE_EXE_PIPE_WRITE)) - close(writePipe[1]); /* FIXME: Check for -1 then errno. */ - close(statusPipe[1]); /* FIXME: Check for -1 then errno. */ + E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok) + { + pid_t pid = 0; + volatile int vfork_exec_errno = 0; + + /* FIXME: I should double check this. After a quick look around, this is already done, but via a more modern method. */ + /* signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ + pid = fork(); + + if (pid == -1) + { + fprintf(stderr, "Failed to fork process\n"); + pid = 0; + } + else if (pid == 0) /* child */ + { + /* Close and/or dup STDIN and STDOUT. */ + E_IF_NO_ERRNO(result, close(STDIN_FILENO), ok); + { + if (flags & ECORE_EXE_PIPE_WRITE) + E_NO_ERRNO(result, dup2(writePipe[0], STDIN_FILENO), ok); + else + E_NO_ERRNO(result, close(writePipe[0]), ok); + + if (ok) + { + E_IF_NO_ERRNO(result, close(STDOUT_FILENO), ok) + { + if (flags & ECORE_EXE_PIPE_READ) + E_NO_ERRNO(result, dup2(readPipe[1], STDOUT_FILENO), ok); + else + E_NO_ERRNO(result, close(readPipe[1]), ok); + } + + if (ok) + { + /* Setup the status pipe. */ + E_NO_ERRNO(result, close(statusPipe[0]), ok); + E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, FD_CLOEXEC), ok) /* close on exec shows sucess */ + { + /* Close STDERR. */ + E_NO_ERRNO(result, close(STDERR_FILENO), ok); + /* Run the actual command. */ + _ecore_exe_exec_it(exe_cmd); /* Should not return from this. */ + } + } + } + } + + /* Something went 'orribly wrong. */ + vfork_exec_errno = errno; + + /* Close the pipes. */ + if (flags & ECORE_EXE_PIPE_READ) E_NO_ERRNO(result, close(readPipe[1]), ok); + if (flags & ECORE_EXE_PIPE_WRITE) E_NO_ERRNO(result, close(writePipe[0]), ok); + E_NO_ERRNO(result, close(statusPipe[1]), ok); + + _exit(-1); + } + else /* parent */ + { + /* Close the unused pipes. */ + if (! (flags & ECORE_EXE_PIPE_READ)) E_NO_ERRNO(result, close(readPipe[0]), ok); + if (! (flags & ECORE_EXE_PIPE_WRITE)) E_NO_ERRNO(result, close(writePipe[1]), ok); + E_NO_ERRNO(result, close(statusPipe[1]), ok); /* FIXME: after having a good look at the current e fd handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */ - while (1) /* Wait for it to start executing. */ - { - char buf; + /* Wait for it to start executing. */ + while (1) + { + char buf; + + E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok); + if (result == 0) + { + if (vfork_exec_errno != 0) + { + n = vfork_exec_errno; + fprintf(stderr, "Could not start \"%s\"\n", exe_cmd); + pid = 0; + } + break; + } + } - n = read(statusPipe[0], &buf, 1); + /* Close the status pipe. */ + E_NO_ERRNO(result, close(statusPipe[0]), ok); + } - if ((n == -1) && ((errno == EAGAIN) || (errno == EINTR))) - continue; /* try it again */ - if (n == 0) - { - if (vfork_exec_errno != 0) - { - n = vfork_exec_errno; - printf("Could not exec process\n"); /* FIXME: maybe set the pid to 0? */ - } - break; - } - } - close(statusPipe[0]); + if (pid) + { + /* Setup the exe structure. */ + ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); + exe->pid = pid; + exe->flags = flags; + exe->data = (void *)data; + if ((exe->cmd = strdup(exe_cmd))) + { + if (flags & ECORE_EXE_PIPE_READ) + { /* Setup the read stuff. */ + exe->child_fd_read = readPipe[0]; + E_IF_NO_ERRNO(result, fcntl(exe->child_fd_read, F_SETFL, O_NONBLOCK), ok) + { + exe->read_fd_handler = ecore_main_fd_handler_add(exe->child_fd_read, + ECORE_FD_READ, _ecore_exe_data_read_handler, exe, + NULL, NULL); + if (exe->read_fd_handler == NULL) + ok = 0; + } + } + if (ok && (flags & ECORE_EXE_PIPE_WRITE)) + { /* Setup the write stuff. */ + exe->child_fd_write = writePipe[1]; + E_IF_NO_ERRNO(result, fcntl(exe->child_fd_write, F_SETFL, O_NONBLOCK), ok) + { + exe->write_fd_handler = ecore_main_fd_handler_add(exe->child_fd_write, + ECORE_FD_WRITE, _ecore_exe_data_write_handler, exe, + NULL, NULL); + if (exe->write_fd_handler) + ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); /* Nothing to write to start with. */ + else + ok = 0; + } + } + exes = _ecore_list2_append(exes, exe); + n = 0; + } + else + ok = 0; + } + else + ok = 0; + } + } } - if (pid) - { - ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); - exe->pid = pid; - exe->flags = flags; - exe->data = (void *)data; - exe->cmd = strdup(exe_cmd); - if (flags & ECORE_EXE_PIPE_READ) - { - exe->child_fd_read = readPipe[0]; - fcntl(exe->child_fd_read, F_SETFL, O_NONBLOCK); /* FIXME: Check for -1 then errno. */ - exe->read_fd_handler = ecore_main_fd_handler_add(exe->child_fd_read, - ECORE_FD_READ, _ecore_exe_data_read_handler, exe, - NULL, NULL); - } - if (flags & ECORE_EXE_PIPE_WRITE) - { - exe->child_fd_write = writePipe[1]; - fcntl(exe->child_fd_write, F_SETFL, O_NONBLOCK); /* FIXME: Check for -1 then errno. */ - exe->write_fd_handler = ecore_main_fd_handler_add(exe->child_fd_write, - ECORE_FD_WRITE, _ecore_exe_data_write_handler, exe, - NULL, NULL); - if (exe->write_fd_handler) - ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); - } - - exes = _ecore_list2_append(exes, exe); - n = 0; + if (!ok) + { /* Something went wrong, so pull down everything. */ + IF_FN_DEL(_ecore_exe_free, exe); } errno = n; - return exe; } @@ -322,9 +441,8 @@ "ecore_exe_tag_set"); return; } - if (exe->tag) free(exe->tag); - exe->tag = NULL; - if (tag) exe->tag = strdup(tag); + IF_FREE(exe->tag); + if (tag) exe->tag = strdup(tag); } /** @@ -577,8 +695,7 @@ num_tokens ++; token = strtok(NULL, " \t\n\v"); } - free(buf); - buf = NULL; + IF_FREE(buf); if (! token && num_tokens) { int i = 0; @@ -591,7 +708,7 @@ use_sh = 0; if (! (args = (char**) calloc(num_tokens + 1, sizeof(char*)))) { - free (buf); + IF_FREE(buf); return; } for (i = 0; i < num_tokens; i ++) @@ -606,9 +723,9 @@ setsid(); if (use_sh) - { + { /* We have to use a shell to run this. */ if (shell == NULL) - { + { /* Find users preferred shell. */ shell = getenv("SHELL"); if (shell == 0) shell = "/bin/sh"; @@ -617,16 +734,14 @@ execl(shell, shell, "-c", exe_cmd, (char *)NULL); } else - { + { /* We can run this directly. */ errno = 0; execvp(args[0], args); } save_errno = errno; - if (buf) - free(buf); - if(args) - free(args); + IF_FREE(buf); + IF_FREE(args); errno = save_errno; return; } @@ -635,20 +750,22 @@ _ecore_exe_free(Ecore_Exe *exe) { void *data; + int ok = 0; + int result; data = exe->data; - if (exe->write_fd_handler) ecore_main_fd_handler_del(exe->write_fd_handler); - if (exe->read_fd_handler) ecore_main_fd_handler_del(exe->read_fd_handler); - if (exe->write_data_buf) free(exe->write_data_buf); - if (exe->read_data_buf) free(exe->read_data_buf); - if (exe->flags & ECORE_EXE_PIPE_READ) close(exe->child_fd_read); /* FIXME: Check for -1 then errno. */ - if (exe->flags & ECORE_EXE_PIPE_WRITE) close(exe->child_fd_write); /* FIXME: Check for -1 then errno. */ - if (exe->cmd) free(exe->cmd); + IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler); + IF_FN_DEL(ecore_main_fd_handler_del, exe->read_fd_handler); + if (exe->flags & ECORE_EXE_PIPE_READ) E_NO_ERRNO(result, close(exe->child_fd_read), ok); + if (exe->flags & ECORE_EXE_PIPE_WRITE) E_NO_ERRNO(result, close(exe->child_fd_write), ok); + IF_FREE(exe->write_data_buf); + IF_FREE(exe->read_data_buf); + IF_FREE(exe->cmd); exes = _ecore_list2_remove(exes, exe); ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE); - if (exe->tag) free(exe->tag); + IF_FREE(exe->tag); free(exe); return data; } @@ -665,6 +782,7 @@ unsigned char *inbuf; int inbuf_num; + /* Get any left over data from last time. */ inbuf = exe->read_data_buf; inbuf_num = exe->read_data_size; exe->read_data_buf = NULL; @@ -688,13 +806,13 @@ perror("_ecore_exe_data_handler() read problem "); } if (num > 0) - { + { /* Data got read. */ inbuf = realloc(inbuf, inbuf_num + num); memcpy(inbuf + inbuf_num, buf, num); inbuf_num += num; } else - { + { /* No more data to read. */ if (inbuf) { Ecore_Event_Exe_Data *e; @@ -765,7 +883,7 @@ } } - if (e) + if (e) /* Send the event. */ ecore_event_add(ECORE_EVENT_EXE_DATA, e, _ecore_exe_event_exe_data_free, NULL); } @@ -773,7 +891,7 @@ if (lost_exe) { if (exe->exit_event) - { + { /* There is a pending exit event to send, so send it. */ _ecore_event_add(ECORE_EVENT_EXE_EXIT, exe->exit_event, _ecore_event_exe_exit_free, NULL); exe->exit_event = NULL; /* Just being paranoid. */ @@ -817,7 +935,7 @@ { if (errno == EIO || errno == EBADF || errno == EPIPE || errno == EINVAL || - errno == ENOSPC) /* we lost our server! */ + errno == ENOSPC) /* we lost our exe! */ { ecore_exe_terminate(exe); if (exe->write_fd_handler) @@ -828,11 +946,10 @@ { exe->write_data_offset += count; if (exe->write_data_offset >= exe->write_data_size) - { + { /* Nothing left to write, clean up. */ exe->write_data_size = 0; exe->write_data_offset = 0; - free(exe->write_data_buf); - exe->write_data_buf = NULL; + IF_FREE(exe->write_data_buf); if (exe->write_fd_handler) ecore_main_fd_handler_active_set(exe->write_fd_handler, 0); } @@ -846,8 +963,8 @@ e = ev; - if (e->lines) free(e->lines); - if (e->data) free(e->data); + IF_FREE(e->lines); + IF_FREE(e->data); free(e); } #endif |
From: <enl...@li...> - 2005-12-24 12:22:53
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: Ecore.h Log Message: Fixup the FIXME's. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/Ecore.h,v retrieving revision 1.30 retrieving revision 1.31 diff -u -3 -r1.30 -r1.31 --- Ecore.h 16 Dec 2005 03:33:52 -0000 1.30 +++ Ecore.h 24 Dec 2005 12:22:47 -0000 1.31 @@ -74,12 +74,12 @@ }; typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags; - enum _Ecore_Exe_Flags /* FIXME: flags for executing a child with its stdin and/or stdout piped back */ + enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or stdout piped back */ { ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */ ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */ ECORE_EXE_PIPE_READ_LINE_BUFFERED = 4, /**< Reads are buffered until a newline and delivered 1 event per line */ - ECORE_EXE_RESPAWN = 8 /**< Exe is restarted if it dies */ + ECORE_EXE_RESPAWN = 8 /* FIXME: Exe is restarted if it dies */ }; typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags; |
From: <enl...@li...> - 2005-12-30 19:17:32
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/src/lib/ecore Modified Files: Ecore.h ecore_exe.c ecore_private.h ecore_signal.c Log Message: * exe exit event delay method changed. * Added method to close an exe's stdin in a (probably) vain attempt to convince exe to exit. * Other debugging shit. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/Ecore.h,v retrieving revision 1.32 retrieving revision 1.33 diff -u -3 -r1.32 -r1.33 --- Ecore.h 27 Dec 2005 17:17:30 -0000 1.32 +++ Ecore.h 30 Dec 2005 19:17:21 -0000 1.33 @@ -210,6 +210,7 @@ EAPI Ecore_Exe *ecore_exe_run(const char *exe_cmd, const void *data); EAPI Ecore_Exe *ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data); EAPI int ecore_exe_pipe_write(Ecore_Exe *exe, void *data, int size); + EAPI void ecore_exe_pipe_write_close(Ecore_Exe *exe); EAPI void *ecore_exe_free(Ecore_Exe *exe); EAPI pid_t ecore_exe_pid_get(Ecore_Exe *exe); EAPI void ecore_exe_tag_set(Ecore_Exe *exe, const char *tag); =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_exe.c,v retrieving revision 1.26 retrieving revision 1.27 diff -u -3 -r1.26 -r1.27 --- ecore_exe.c 24 Dec 2005 12:13:12 -0000 1.26 +++ ecore_exe.c 30 Dec 2005 19:17:21 -0000 1.27 @@ -71,6 +71,10 @@ * EMFILE Too many file descriptors used by process. * ENOLCK Problem getting a lock. * EPERM Not allowed to do that. + * fsync + * EBADF This is not an fd that is open for writing. + * EINVAL, EROFS This is not an fd that can be fsynced. + * EIO I/O error. * * How to use it - * int ok = 0; @@ -88,7 +92,7 @@ * // Something failed, cleanup. * } */ - switch (result) + switch (saved_errno) { case EACCES : case EAGAIN : @@ -118,6 +122,7 @@ case EFAULT : case EBADF : case EINVAL : + case EROFS : case EISDIR : case EDEADLK : case EPERM : @@ -137,9 +142,9 @@ fprintf(stderr, "*** NAUGHTY PROGRAMMER!!!\n" "*** SPANK SPANK SPANK!!!\n" - "*** Unsupported errno code, please add this one.\n" - "*** Now go fix your code in %s @%u. Tut tut tut!\n" - "\n", __FILE__, __LINE__); + "*** Unsupported errno code %d, please add this one.\n" + "*** Now go fix your code in %s @%u, from %s @%u. Tut tut tut!\n" + "\n", saved_errno, __FILE__, __LINE__, file, line); result = 0; break; } @@ -193,6 +198,7 @@ ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE); exe->pid = pid; exe->data = (void *)data; + exe->cmd = strdup(exe_cmd); exes = _ecore_list2_append(exes, exe); return exe; } @@ -389,6 +395,8 @@ { /* Something went wrong, so pull down everything. */ IF_FN_DEL(_ecore_exe_free, exe); } +else +printf("Running as %d for %s.\n", exe->pid, exe->cmd); errno = n; return exe; @@ -426,6 +434,25 @@ } /** + * The stdin pipe of the given child process will close when the write buffer is empty. + * + * @param exe The child process to write to + * @ingroup Ecore_Exe_Basic_Group + */ +void +ecore_exe_pipe_write_close(Ecore_Exe *exe) +{ + if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE)) + { + ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, + "ecore_exe_pipe_write_close"); + return; + } + exe->close_write = 1; +} + + +/** * Sets the string tag for the given process handle * * @param exe The given process handle. @@ -782,6 +809,7 @@ unsigned char *inbuf; int inbuf_num; +//printf("Reading data for %s\n", exe->cmd); /* Get any left over data from last time. */ inbuf = exe->read_data_buf; inbuf_num = exe->read_data_size; @@ -890,14 +918,17 @@ } if (lost_exe) { - if (exe->exit_event) - { /* There is a pending exit event to send, so send it. */ - _ecore_event_add(ECORE_EVENT_EXE_EXIT, exe->exit_event, - _ecore_event_exe_exit_free, NULL); - exe->exit_event = NULL; /* Just being paranoid. */ - } - else - ecore_exe_terminate(exe); /* FIXME: give this some deep thought later. */ +if (exe->read_data_size) + printf("Theer are %d bytes left unsent from the dead exe %s.\n", exe->read_data_size, exe->cmd); +// if (exe->exit_event) +// { /* There is a pending exit event to send, so send it. */ +//printf("Sending delayed exit event for %s.\n", exe->cmd); +// _ecore_event_add(ECORE_EVENT_EXE_EXIT, exe->exit_event, +// _ecore_event_exe_exit_free, NULL); +// exe->exit_event = NULL; /* Just being paranoid. */ +// } +// else +// ecore_exe_terminate(exe); /* FIXME: give this some deep thought later. */ } break; } @@ -916,6 +947,22 @@ if ((exe->write_fd_handler) && (ecore_main_fd_handler_active_get(exe->write_fd_handler, ECORE_FD_WRITE))) _ecore_exe_flush(exe); + /* If we have sent all there is to send, and we need to close the pipe, then close it. */ + if ((exe->close_write == 1) && /*(!exe->write_data_buf) &&*/ (exe->write_data_size == exe->write_data_offset)) + { + int ok = 0; + int result; + +printf("Closing stdin for %s\n", exe->cmd); +// if (exe->child_fd_write) E_NO_ERRNO(result, fsync(exe->child_fd_write), ok); + IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler); + if (exe->child_fd_write) E_NO_ERRNO(result, close(exe->child_fd_write), ok); + exe->child_fd_write = 0; + IF_FREE(exe->write_data_buf); + exe->flags &= ~ECORE_EXE_PIPE_WRITE; + exe->close_write = 0; + } + return 1; } =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_private.h,v retrieving revision 1.28 retrieving revision 1.29 diff -u -3 -r1.28 -r1.29 --- ecore_private.h 27 Dec 2005 17:17:30 -0000 1.28 +++ ecore_private.h 30 Dec 2005 19:17:21 -0000 1.29 @@ -191,11 +191,7 @@ int read_data_size; /* data read from child in bytes */ int child_fd_write; /* fd to write TO to send data to the child */ int child_fd_read; /* fd to read FROM when child has sent us (the parent) data */ - /* I thought a bit about wether or not their could be multiple exit events, then realised that since we - * delete the exe on the first exit event, the answer is no. On the other hand, STOPing an exe may trigger - * this, even though it has not truly exited. Probably should investigate this further. - */ - struct _Ecore_Event_Exe_Exit *exit_event; /* Process exit event */ + int close_write; }; #endif =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/src/lib/ecore/ecore_signal.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -3 -r1.19 -r1.20 --- ecore_signal.c 19 Dec 2005 05:07:58 -0000 1.19 +++ ecore_signal.c 30 Dec 2005 19:17:21 -0000 1.20 @@ -33,6 +33,8 @@ static void _ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo); #endif +static int _ecore_signal_exe_exit_delay(void *data); + static volatile sig_atomic_t sig_count = 0; static volatile sig_atomic_t sigchld_count = 0; static volatile sig_atomic_t sigusr1_count = 0; @@ -184,10 +186,37 @@ e->data = sigchld_info; /* FIXME: I'm not sure, but maybe we should clone this. I don't know if anybody uses it. */ if ((e->exe) && (e->exe->flags & ECORE_EXE_PIPE_READ)) - e->exe->exit_event = e; /* We want to report the Last Words of the exe, so delay this event. */ + { + /* We want to report the Last Words of the exe, so delay this event. + * There are three possibilities here - + * 1 There are no Last Words. + * 2 There are Last Words, they are not ready to be read. + * 3 There are Last Words, they are ready to be read. + * + * For 1 we don't want to delay, for 3 we want to delay. + * 2 is the problem. If we check for data now and there + * is none, then there is no way to differentiate 1 and 2. + * If we don't delay, we may loose data, but if we do delay, + * there may not be data and the exit event never gets sent. + * + * Any way you look at it, there has to be some time passed + * before the exit event gets sent. So the startegy here is + * to setup a timer event that will send the exit event after + * an arbitrary, but brief, time. + * + * This is probably paranoid, for the less paraniod, we could + * check to see for Last Words, and only delay if there are any. + * This has it's own set of problems. + */ +printf("Delaying exit event for %s.\n", e->exe->cmd); + ecore_timer_add(0.1, _ecore_signal_exe_exit_delay, e); + } else +{ +printf("Sending exit event for %s.\n", e->exe->cmd); _ecore_event_add(ECORE_EVENT_EXE_EXIT, e, _ecore_event_exe_exit_free, NULL); +} } } sigchld_count--; @@ -458,4 +487,19 @@ sig_count++; } #endif + +static int +_ecore_signal_exe_exit_delay(void *data) +{ + Ecore_Event_Exe_Exit *e; + + e = data; + if (e) + { +printf("Sending delayed exit event for %s.\n", e->exe->cmd); + _ecore_event_add(ECORE_EVENT_EXE_EXIT, e, + _ecore_event_exe_exit_free, NULL); + } + return 0; +} #endif |
From: <enl...@li...> - 2005-12-30 19:20:06
|
Enlightenment CVS committal Author : onefang Project : e17 Module : libs/ecore Dir : e17/libs/ecore/examples Modified Files: exe_example.c Log Message: * Should now shut down properly when all exe's finish. * All exe's should now finish. B-) * If called with a file as an argument, it will use the contents of that file as a R/W performance test. =================================================================== RCS file: /cvsroot/enlightenment/e17/libs/ecore/examples/exe_example.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -3 -r1.2 -r1.3 --- exe_example.c 16 Dec 2005 04:03:04 -0000 1.2 +++ exe_example.c 30 Dec 2005 19:19:59 -0000 1.3 @@ -3,14 +3,24 @@ #include <Ecore.h> +#include <string.h> #include <stdlib.h> #include <stdio.h> - +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +int size = 0; +int exe_count = 0; +int data_count = 0; +int line_count = 0; +int one_percent = 0; Ecore_Exe *exe0 = NULL; Ecore_Exe *exe1 = NULL; Ecore_Exe *exe2 = NULL; Ecore_Exe *exe3 = NULL; - + static int exe_data(void *data, int type, void *event) { @@ -39,37 +49,148 @@ } static int +exe_data_count(void *data, int type, void *event) +{ + Ecore_Event_Exe_Data *ev; + int i; + + ev = event; + + if (ev->lines) + { + int i; + + for (i = 0; ev->lines[i].line != NULL; i++) + line_count++; + printf("%d ", i); + } + + for (i = 0; i < ev->size; i++) + { + data_count++; + if ((data_count % one_percent) == 0) + { + putchar('.'); + fflush(stdout); + } + } + + if (data_count >= size) + { + printf("\n"); + /* Since there does not seem to be anyway to convince /bin/cat to finish... */ + ecore_exe_terminate(exe0); + } + + return 1; +} + +static int exe_exit(void *data, int type, void *event) { Ecore_Event_Exe_Exit *ev; ev = event; printf(" [*] EXE EXIT: %p\n", ev->exe); + exe_count--; + if (exe_count <= 0) + ecore_main_loop_quit(); return 1; } -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ + double then = 0.0, now = 0.0; + ecore_init(); - ecore_event_handler_add(ECORE_EVENT_EXE_DATA, exe_data, NULL); ecore_event_handler_add(ECORE_EVENT_EXE_EXIT, exe_exit, NULL); - exe0 = ecore_exe_run("/bin/uname -a", NULL); - - exe1 = ecore_exe_pipe_run("/bin/sh", + + if (argc == 1) + { + ecore_event_handler_add(ECORE_EVENT_EXE_DATA, exe_data, NULL); + exe0 = ecore_exe_run("/bin/uname -a", NULL); + if (exe0) exe_count++; + + exe1 = ecore_exe_pipe_run("/bin/sh", ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE, NULL); - ecore_exe_pipe_write(exe1, "ls\n", 3); - exe2 = ecore_exe_pipe_run("/usr/bin/find / -print", + if (exe1) + { + exe_count++; + ecore_exe_pipe_write(exe1, "ls\n", 3); + ecore_exe_pipe_write(exe1, "exit\n", 5); + } + + exe2 = ecore_exe_pipe_run("/usr/bin/find . -print", ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED, NULL); - exe3 = ecore_exe_pipe_run("/bin/cat", + if (exe2) exe_count++; + + exe3 = ecore_exe_pipe_run("/bin/cat", ECORE_EXE_PIPE_WRITE, NULL); - ecore_exe_pipe_write(exe3, "ls\n", 3); - printf(" [*] exe0 = %p (/bin/uname -a)\n", exe0); - printf(" [*] exe1 = %p (echo \"ls\" | /bin/sh)\n", exe1); - printf(" [*] exe2 = %p (/usr/bin/find / -print)\n", exe2); - printf(" [*] exe3 = %p (echo \"ls\" | /bin/cat)\n", exe3); - ecore_main_loop_begin(); + if (exe3) + { + exe_count++; + ecore_exe_pipe_write(exe3, "ls\n", 3); + } + + printf(" [*] exe0 = %p (/bin/uname -a)\n", exe0); + printf(" [*] exe1 = %p (echo \"ls\" | /bin/sh)\n", exe1); + printf(" [*] exe2 = %p (/usr/bin/find / -print)\n", exe2); + printf(" [*] exe3 = %p (echo \"ls\" | /bin/cat)\n", exe3); + } + else + { + int i = 1; + + ecore_event_handler_add(ECORE_EVENT_EXE_DATA, exe_data_count, NULL); + printf("FILE : %s\n", argv[i]); + exe0 = ecore_exe_pipe_run("/bin/cat", + ECORE_EXE_PIPE_WRITE | ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED, + NULL); + if (exe0) + { + struct stat s; + + exe_count++; + if (stat(argv[i], &s) == 0) + { + int fd; + + size = s.st_size; + one_percent = s.st_size / 100; + if (one_percent == 0) + one_percent = 1; + if ((fd = open(argv[i], O_RDONLY)) != -1) + { + char buf[1024]; + int length; + while ((length = read(fd, buf, 1024)) > 0) + ecore_exe_pipe_write(exe0, buf, length); + close(fd); + } + } + /* FIXME: Fuckit, neither of these will actually cause /bin/cat to shut down. What the fuck does it take? */ + ecore_exe_pipe_write(exe0, "\004", 1); /* Send an EOF. */ + ecore_exe_pipe_write_close(exe0); /* /bin/cat should stop when it's stdin closes. */ + } + } + + if (one_percent) + then = ecore_time_get() + 0.1; /* Factor in the exe exit delay at least. */ + + if (exe_count > 0) + ecore_main_loop_begin(); + + if (one_percent) + { + now = ecore_time_get(); + printf("Approximate data rate (overhead not accounted for) - %f bytes/second ( %d lines and %d bytes in %f seconds).\n", ((double) data_count) / (now - then), line_count, data_count, now - then); + if (data_count != size) + printf("Size discrepency of %d bytes.\n", size - data_count); + } + ecore_shutdown(); return 0; } |