* 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.


SVN revision: 19430
This commit is contained in:
David Walter Seikel 2005-12-30 19:17:21 +00:00
parent e37b4166d8
commit 8bb13800f8
4 changed files with 106 additions and 18 deletions

View File

@ -210,6 +210,7 @@ extern "C" {
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);

View File

@ -71,6 +71,10 @@ int _ecore_exe_check_errno(int result, char *file, int line)
* 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 @@ int _ecore_exe_check_errno(int result, char *file, int line)
* // Something failed, cleanup.
* }
*/
switch (result)
switch (saved_errno)
{
case EACCES :
case EAGAIN :
@ -118,6 +122,7 @@ int _ecore_exe_check_errno(int result, char *file, int line)
case EFAULT :
case EBADF :
case EINVAL :
case EROFS :
case EISDIR :
case EDEADLK :
case EPERM :
@ -137,9 +142,9 @@ int _ecore_exe_check_errno(int result, char *file, int line)
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_exe_run(const char *exe_cmd, const void *data)
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 @@ ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void *data)
{ /* 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;
@ -425,6 +433,25 @@ ecore_exe_pipe_write(Ecore_Exe *exe, void *data, int size)
return 1;
}
/**
* 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
*
@ -782,6 +809,7 @@ _ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler)
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 @@ _ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler)
}
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 @@ _ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler)
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;
}

View File

@ -191,11 +191,7 @@ struct _Ecore_Exe
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

View File

@ -33,6 +33,8 @@ static void _ecore_signal_callback_sigpwr(int sig, siginfo_t *si, void *foo);
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 @@ _ecore_signal_call(void)
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 @@ _ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo __UNUSED__)
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