typedef enum { ECORE_EXE_WIN32_SIGINT, ECORE_EXE_WIN32_SIGQUIT, ECORE_EXE_WIN32_SIGTERM, ECORE_EXE_WIN32_SIGKILL } Ecore_Exe_Win32_Signal; /* FIXME: Getting respawn to work * * There is no way that we can do anything about the internal state info of * an external exe. The same can be said about the state of user code. User * code in this context means the code that is using ecore_exe to manage exe's * for it. * * Document that the exe must be respawnable, in other words, there is no * state that it cannot regenerate by just killing it and starting it again. * This includes state that the user code knows about, as the respawn is * transparent to that code. On the other hand, maybe a respawn event might * be useful, or maybe resend the currently non existent add event. For * consistancy with ecore_con, an add event is good anyway. * * The Ecore_exe structure is reused for respawning, so that the (opaque) * pointer held by the user remains valid. This means that the Ecore_Exe * init and del functions may need to be split into two parts each to avoid * duplicating code - common code part, and the rest. This implies that * the unchanging members mentioned next should NEVER change. * * These structure members don't need to change - * __list_data - we stay on the list * data - passed in originally * cmd - passed in originally * flags - passed in originally * * These structure members need to change - * tag - state that must be regenerated, zap it * pid - it will be different * child_fd_write - it will be different * child_fd_read - it will be different * child_fd_error - it will be different * write_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. * read_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. * error_fd_handler - we cannot change the fd used by a handler, this changes coz the fd changes. * * Hmm, the read, write, and error buffers could be tricky. * They are not atomic, and could be in a semi complete state. * They fall into the "state must be regenerated" mentioned above. * A respawn/add event should take care of it. * * These structure members need to change - * write_data_buf - state that must be regenerated, zap it * write_data_size - state that must be regenerated, zap it * write_data_offset - state that must be regenerated, zap it * read_data_buf - state that must be regenerated, zap it * read_data_size - state that must be regenerated, zap it * error_data_buf - state that must be regenerated, zap it * error_data_size - state that must be regenerated, zap it * close_write - state that must be regenerated, zap it * * There is the problem that an exe that fell over and needs respawning * might keep falling over, keep needing to be respawned, and tie up system * resources with the constant respawning. An exponentially increasing * timeout (with maximum timeout) between respawns should take care of that. * Although this is not a "contention for a resource" problem, the exe falling * over may be, so a random element added to the timeout may help, and won't * hurt. The user code may need to be informed that a timeout is in progress. */ struct _Ecore_Exe_Data { void *data; char *tag, *cmd; Eo *loop; #ifdef _WIN32 HANDLE process; HANDLE process_thread; DWORD thread_id; Ecore_Win32_Handler *h_close; Ecore_Exe_Win32_Signal sig; Ecore_Thread *th; struct { HANDLE child_pipe; void *data_buf; int data_size; } pipe_read; struct { HANDLE child_pipe; void *data_buf; int data_size; } pipe_error; struct { HANDLE child_pipe; HANDLE child_pipe_x; } pipe_write; Eina_Bool close_threads : 1; Eina_Bool is_suspended : 1; #else 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 */ Ecore_Fd_Handler *error_fd_handler; /* the fd_handler to handle errors 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 */ void *error_data_buf; /* errors read from the child awating delivery to an event */ int error_data_size; /* errors 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 */ int child_fd_error; /* fd to read FROM when child has sent us (the parent) errors */ int child_fd_write_x; /* fd to write TO to send data to the child */ int child_fd_read_x; /* fd to read FROM when child has sent us (the parent) data */ int child_fd_error_x; /* fd to read FROM when child has sent us (the parent) errors */ int start_bytes, end_bytes, start_lines, end_lines; /* Number of bytes/lines to auto pipe at start/end of stdout/stderr. */ Ecore_Timer *doomsday_clock; /* The Timer of Death. Muahahahaha. */ #endif Ecore_Exe_Cb pre_free_cb; pid_t pid; Ecore_Exe_Flags flags; Eina_Bool close_stdin : 1; }; typedef struct _Ecore_Exe_Data Ecore_Exe_Data; EAPI extern int ECORE_EXE_EVENT_ADD; EAPI extern int ECORE_EXE_EVENT_DEL; EAPI extern int ECORE_EXE_EVENT_DATA; EAPI extern int ECORE_EXE_EVENT_ERROR; Ecore_Exe *_ecore_exe_find(pid_t pid); void *_ecore_exe_event_del_new(void); void _ecore_exe_event_del_free(void *data EINA_UNUSED, void *ev); void _ecore_exe_event_exe_data_free(void *data EINA_UNUSED, void *ev); Ecore_Exe_Event_Add * _ecore_exe_event_add_new(void); void _ecore_exe_event_add_free(void *data EINA_UNUSED, void *ev); void _impl_ecore_exe_run_priority_set(int pri); int _impl_ecore_exe_run_priority_get(void); void _impl_ecore_exe_auto_limits_set(Ecore_Exe *obj, Ecore_Exe_Data *exe, int start_bytes, int end_bytes, int start_lines, int end_lines); Eo *_impl_ecore_exe_efl_object_finalize(Eo *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_efl_control_suspend_set(Eo *obj EINA_UNUSED, Ecore_Exe_Data *exe, Eina_Bool suspend); Eina_Bool _impl_ecore_exe_send(Ecore_Exe *obj, Ecore_Exe_Data *exe, const void *data, int size); Ecore_Exe_Event_Data *_impl_ecore_exe_event_data_get(Ecore_Exe *obj, Ecore_Exe_Data *exe, Ecore_Exe_Flags flags); void _impl_ecore_exe_efl_object_destructor(Eo *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_pause(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_continue(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_interrupt(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_quit(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_terminate(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_kill(Ecore_Exe *obj, Ecore_Exe_Data *exe); void _impl_ecore_exe_signal(Ecore_Exe *obj, Ecore_Exe_Data *exe, int num); void _impl_ecore_exe_hup(Ecore_Exe *obj EINA_UNUSED, Ecore_Exe_Data *exe);