forked from enlightenment/efl
ecore: Add thread safety support to ecore pipe
Fixes hang in edje_codegen with thread safe ecore enabled. ecore_shutdown takes lock, then calls _ecore_pipe_read, which makes callbacks without unlocking ecore. Signed-off-by: Mike McCormack <mikem@atratus.org> SVN revision: 78937
This commit is contained in:
parent
3b16fb0fe3
commit
5faaa68c99
|
@ -181,7 +181,7 @@ ecore_init(void)
|
||||||
eina_condition_new(&_thread_cond, &_thread_mutex);
|
eina_condition_new(&_thread_cond, &_thread_mutex);
|
||||||
eina_lock_new(&_thread_feedback_mutex);
|
eina_lock_new(&_thread_feedback_mutex);
|
||||||
eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
|
eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
|
||||||
_thread_call = ecore_pipe_add(_thread_callback, NULL);
|
_thread_call = _ecore_pipe_add(_thread_callback, NULL);
|
||||||
eina_lock_new(&_thread_safety);
|
eina_lock_new(&_thread_safety);
|
||||||
|
|
||||||
eina_lock_new(&_thread_id_lock);
|
eina_lock_new(&_thread_id_lock);
|
||||||
|
@ -268,8 +268,8 @@ ecore_shutdown(void)
|
||||||
*/
|
*/
|
||||||
p = _thread_call;
|
p = _thread_call;
|
||||||
_thread_call = NULL;
|
_thread_call = NULL;
|
||||||
ecore_pipe_wait(p, 1, 0.1);
|
_ecore_pipe_wait(p, 1, 0.1);
|
||||||
ecore_pipe_del(p);
|
_ecore_pipe_del(p);
|
||||||
eina_lock_free(&_thread_safety);
|
eina_lock_free(&_thread_safety);
|
||||||
eina_condition_free(&_thread_cond);
|
eina_condition_free(&_thread_cond);
|
||||||
eina_lock_free(&_thread_mutex);
|
eina_lock_free(&_thread_mutex);
|
||||||
|
|
|
@ -996,23 +996,20 @@ ecore_main_loop_select_func_get(void)
|
||||||
return main_loop_select;
|
return main_loop_select;
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPI Ecore_Fd_Handler *
|
Ecore_Fd_Handler *
|
||||||
ecore_main_fd_handler_add(int fd,
|
_ecore_main_fd_handler_add(int fd,
|
||||||
Ecore_Fd_Handler_Flags flags,
|
Ecore_Fd_Handler_Flags flags,
|
||||||
Ecore_Fd_Cb func,
|
Ecore_Fd_Cb func,
|
||||||
const void *data,
|
const void *data,
|
||||||
Ecore_Fd_Cb buf_func,
|
Ecore_Fd_Cb buf_func,
|
||||||
const void *buf_data)
|
const void *buf_data)
|
||||||
{
|
{
|
||||||
Ecore_Fd_Handler *fdh = NULL;
|
Ecore_Fd_Handler *fdh = NULL;
|
||||||
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
if ((fd < 0) || (flags == 0) || (!func)) return NULL;
|
||||||
_ecore_lock();
|
|
||||||
|
|
||||||
if ((fd < 0) || (flags == 0) || (!func)) goto unlock;
|
|
||||||
|
|
||||||
fdh = ecore_fd_handler_calloc(1);
|
fdh = ecore_fd_handler_calloc(1);
|
||||||
if (!fdh) goto unlock;
|
if (!fdh) return NULL;
|
||||||
ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER);
|
ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER);
|
||||||
fdh->next_ready = NULL;
|
fdh->next_ready = NULL;
|
||||||
fdh->fd = fd;
|
fdh->fd = fd;
|
||||||
|
@ -1022,8 +1019,7 @@ ecore_main_fd_handler_add(int fd,
|
||||||
int err = errno;
|
int err = errno;
|
||||||
ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err));
|
ERR("Failed to add poll on fd %d (errno = %d: %s)!", fd, err, strerror(err));
|
||||||
ecore_fd_handler_mp_free(fdh);
|
ecore_fd_handler_mp_free(fdh);
|
||||||
fdh = NULL;
|
return NULL;
|
||||||
goto unlock;
|
|
||||||
}
|
}
|
||||||
fdh->read_active = EINA_FALSE;
|
fdh->read_active = EINA_FALSE;
|
||||||
fdh->write_active = EINA_FALSE;
|
fdh->write_active = EINA_FALSE;
|
||||||
|
@ -1038,12 +1034,26 @@ ecore_main_fd_handler_add(int fd,
|
||||||
fd_handlers = (Ecore_Fd_Handler *)
|
fd_handlers = (Ecore_Fd_Handler *)
|
||||||
eina_inlist_append(EINA_INLIST_GET(fd_handlers),
|
eina_inlist_append(EINA_INLIST_GET(fd_handlers),
|
||||||
EINA_INLIST_GET(fdh));
|
EINA_INLIST_GET(fdh));
|
||||||
unlock:
|
|
||||||
_ecore_unlock();
|
|
||||||
|
|
||||||
return fdh;
|
return fdh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EAPI Ecore_Fd_Handler *
|
||||||
|
ecore_main_fd_handler_add(int fd,
|
||||||
|
Ecore_Fd_Handler_Flags flags,
|
||||||
|
Ecore_Fd_Cb func,
|
||||||
|
const void *data,
|
||||||
|
Ecore_Fd_Cb buf_func,
|
||||||
|
const void *buf_data)
|
||||||
|
{
|
||||||
|
Ecore_Fd_Handler *fdh = NULL;
|
||||||
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
||||||
|
_ecore_lock();
|
||||||
|
fdh = _ecore_main_fd_handler_add(fd, flags, func, data, buf_func, buf_data);
|
||||||
|
_ecore_unlock();
|
||||||
|
return fdh;
|
||||||
|
}
|
||||||
|
|
||||||
EAPI Ecore_Fd_Handler *
|
EAPI Ecore_Fd_Handler *
|
||||||
ecore_main_fd_handler_file_add(int fd,
|
ecore_main_fd_handler_file_add(int fd,
|
||||||
Ecore_Fd_Handler_Flags flags,
|
Ecore_Fd_Handler_Flags flags,
|
||||||
|
|
|
@ -123,6 +123,277 @@ ecore_pipe_add(Ecore_Pipe_Cb handler,
|
||||||
const void *data)
|
const void *data)
|
||||||
{
|
{
|
||||||
Ecore_Pipe *p;
|
Ecore_Pipe *p;
|
||||||
|
|
||||||
|
_ecore_lock();
|
||||||
|
p = _ecore_pipe_add(handler, data);
|
||||||
|
_ecore_unlock();
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free an Ecore_Pipe object created with ecore_pipe_add().
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object to be freed.
|
||||||
|
* @return The pointer to the private data
|
||||||
|
*/
|
||||||
|
EAPI void *
|
||||||
|
ecore_pipe_del(Ecore_Pipe *p)
|
||||||
|
{
|
||||||
|
void *r;
|
||||||
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
||||||
|
_ecore_lock();
|
||||||
|
r = _ecore_pipe_del(p);
|
||||||
|
_ecore_unlock();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the read end of an Ecore_Pipe object created with ecore_pipe_add().
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object.
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_pipe_read_close(Ecore_Pipe *p)
|
||||||
|
{
|
||||||
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
||||||
|
_ecore_lock();
|
||||||
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
|
{
|
||||||
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (p->fd_handler)
|
||||||
|
{
|
||||||
|
_ecore_main_fd_handler_del(p->fd_handler);
|
||||||
|
p->fd_handler = NULL;
|
||||||
|
}
|
||||||
|
if (p->fd_read != PIPE_FD_INVALID)
|
||||||
|
{
|
||||||
|
pipe_close(p->fd_read);
|
||||||
|
p->fd_read = PIPE_FD_INVALID;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
_ecore_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop monitoring if necessary the pipe for reading. See ecore_pipe_thaw()
|
||||||
|
* for monitoring it again.
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object.
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_pipe_freeze(Ecore_Pipe *p)
|
||||||
|
{
|
||||||
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
||||||
|
_ecore_lock();
|
||||||
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
|
{
|
||||||
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_freeze");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (p->fd_handler)
|
||||||
|
{
|
||||||
|
_ecore_main_fd_handler_del(p->fd_handler);
|
||||||
|
p->fd_handler = NULL;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
_ecore_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start monitoring again the pipe for reading. See ecore_pipe_freeze() for
|
||||||
|
* stopping the monitoring activity. This will not work if
|
||||||
|
* ecore_pipe_read_close() was previously called on the same pipe.
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object.
|
||||||
|
* @since 1.1
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_pipe_thaw(Ecore_Pipe *p)
|
||||||
|
{
|
||||||
|
EINA_MAIN_LOOP_CHECK_RETURN;
|
||||||
|
_ecore_lock();
|
||||||
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
|
{
|
||||||
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_thaw");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!p->fd_handler && p->fd_read != PIPE_FD_INVALID)
|
||||||
|
{
|
||||||
|
p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
|
||||||
|
ECORE_FD_READ,
|
||||||
|
_ecore_pipe_read,
|
||||||
|
p,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
_ecore_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait from another thread on the read side of a pipe.
|
||||||
|
*
|
||||||
|
* @param p The pipe to watch on.
|
||||||
|
* @param message_count The minimal number of message to wait before exiting.
|
||||||
|
* @param wait The amount of time in second to wait before exiting.
|
||||||
|
* @return the number of message catched during that wait call.
|
||||||
|
* @since 1.1
|
||||||
|
*
|
||||||
|
* Negative value for @p wait means infite wait.
|
||||||
|
*/
|
||||||
|
EAPI int
|
||||||
|
ecore_pipe_wait(Ecore_Pipe *p,
|
||||||
|
int message_count,
|
||||||
|
double wait)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
_ecore_lock();
|
||||||
|
r = _ecore_pipe_wait(p, message_count, wait);
|
||||||
|
_ecore_unlock();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the write end of an Ecore_Pipe object created with ecore_pipe_add().
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object.
|
||||||
|
*/
|
||||||
|
EAPI void
|
||||||
|
ecore_pipe_write_close(Ecore_Pipe *p)
|
||||||
|
{
|
||||||
|
_ecore_lock();
|
||||||
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
|
{
|
||||||
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (p->fd_write != PIPE_FD_INVALID)
|
||||||
|
{
|
||||||
|
pipe_close(p->fd_write);
|
||||||
|
p->fd_write = PIPE_FD_INVALID;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
_ecore_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write on the file descriptor the data passed as parameter.
|
||||||
|
*
|
||||||
|
* @param p The Ecore_Pipe object.
|
||||||
|
* @param buffer The data to write into the pipe.
|
||||||
|
* @param nbytes The size of the @p buffer in bytes
|
||||||
|
* @return @c EINA_TRUE on a successful write, @c EINA_FALSE on error.
|
||||||
|
*/
|
||||||
|
EAPI Eina_Bool
|
||||||
|
ecore_pipe_write(Ecore_Pipe *p,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned int nbytes)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
size_t already_written = 0;
|
||||||
|
int retry = ECORE_PIPE_WRITE_RETRY;
|
||||||
|
Eina_Bool ok = EINA_FALSE;
|
||||||
|
|
||||||
|
_ecore_lock();
|
||||||
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
|
{
|
||||||
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->delete_me) goto out;
|
||||||
|
|
||||||
|
if (p->fd_write == PIPE_FD_INVALID) goto out;
|
||||||
|
|
||||||
|
/* First write the len into the pipe */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes));
|
||||||
|
if (ret == sizeof(nbytes))
|
||||||
|
{
|
||||||
|
retry = ECORE_PIPE_WRITE_RETRY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (ret > 0)
|
||||||
|
{
|
||||||
|
/* XXX What should we do here? */
|
||||||
|
ERR("The length of the data was not written complete"
|
||||||
|
" to the pipe");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (ret == PIPE_FD_ERROR && errno == EPIPE)
|
||||||
|
{
|
||||||
|
pipe_close(p->fd_write);
|
||||||
|
p->fd_write = PIPE_FD_INVALID;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (ret == PIPE_FD_ERROR && errno == EINTR)
|
||||||
|
/* try it again */
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("An unhandled error (ret: %zd errno: %d)"
|
||||||
|
"occurred while writing to the pipe the length",
|
||||||
|
ret, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (retry--);
|
||||||
|
|
||||||
|
if (retry != ECORE_PIPE_WRITE_RETRY) goto out;
|
||||||
|
|
||||||
|
/* and now pass the data to the pipe */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = pipe_write(p->fd_write,
|
||||||
|
((unsigned char *)buffer) + already_written,
|
||||||
|
nbytes - already_written);
|
||||||
|
|
||||||
|
if (ret == (ssize_t)(nbytes - already_written))
|
||||||
|
{
|
||||||
|
ok = EINA_TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (ret >= 0)
|
||||||
|
{
|
||||||
|
already_written -= ret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (ret == PIPE_FD_ERROR && errno == EPIPE)
|
||||||
|
{
|
||||||
|
pipe_close(p->fd_write);
|
||||||
|
p->fd_write = PIPE_FD_INVALID;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (ret == PIPE_FD_ERROR && errno == EINTR)
|
||||||
|
/* try it again */
|
||||||
|
;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERR("An unhandled error (ret: %zd errno: %d)"
|
||||||
|
"occurred while writing to the pipe the length",
|
||||||
|
ret, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (retry--);
|
||||||
|
|
||||||
|
out:
|
||||||
|
_ecore_unlock();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Private functions */
|
||||||
|
Ecore_Pipe *
|
||||||
|
_ecore_pipe_add(Ecore_Pipe_Cb handler,
|
||||||
|
const void *data)
|
||||||
|
{
|
||||||
|
Ecore_Pipe *p = NULL;
|
||||||
int fds[2];
|
int fds[2];
|
||||||
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
||||||
|
@ -149,21 +420,15 @@ ecore_pipe_add(Ecore_Pipe_Cb handler,
|
||||||
_ecore_pipe_read,
|
_ecore_pipe_read,
|
||||||
p,
|
p,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void *
|
||||||
* Free an Ecore_Pipe object created with ecore_pipe_add().
|
_ecore_pipe_del(Ecore_Pipe *p)
|
||||||
*
|
|
||||||
* @param p The Ecore_Pipe object to be freed.
|
|
||||||
* @return The pointer to the private data
|
|
||||||
*/
|
|
||||||
EAPI void *
|
|
||||||
ecore_pipe_del(Ecore_Pipe *p)
|
|
||||||
{
|
{
|
||||||
void *data;
|
void *data = NULL;
|
||||||
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
||||||
{
|
{
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
|
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
|
||||||
|
@ -179,97 +444,10 @@ ecore_pipe_del(Ecore_Pipe *p)
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
int
|
||||||
* Close the read end of an Ecore_Pipe object created with ecore_pipe_add().
|
_ecore_pipe_wait(Ecore_Pipe *p,
|
||||||
*
|
int message_count,
|
||||||
* @param p The Ecore_Pipe object.
|
double wait)
|
||||||
*/
|
|
||||||
EAPI void
|
|
||||||
ecore_pipe_read_close(Ecore_Pipe *p)
|
|
||||||
{
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN;
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
|
||||||
{
|
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (p->fd_handler)
|
|
||||||
{
|
|
||||||
_ecore_main_fd_handler_del(p->fd_handler);
|
|
||||||
p->fd_handler = NULL;
|
|
||||||
}
|
|
||||||
if (p->fd_read != PIPE_FD_INVALID)
|
|
||||||
{
|
|
||||||
pipe_close(p->fd_read);
|
|
||||||
p->fd_read = PIPE_FD_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop monitoring if necessary the pipe for reading. See ecore_pipe_thaw()
|
|
||||||
* for monitoring it again.
|
|
||||||
*
|
|
||||||
* @param p The Ecore_Pipe object.
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
EAPI void
|
|
||||||
ecore_pipe_freeze(Ecore_Pipe *p)
|
|
||||||
{
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN;
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
|
||||||
{
|
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_freeze");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (p->fd_handler)
|
|
||||||
{
|
|
||||||
_ecore_main_fd_handler_del(p->fd_handler);
|
|
||||||
p->fd_handler = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start monitoring again the pipe for reading. See ecore_pipe_freeze() for
|
|
||||||
* stopping the monitoring activity. This will not work if
|
|
||||||
* ecore_pipe_read_close() was previously called on the same pipe.
|
|
||||||
*
|
|
||||||
* @param p The Ecore_Pipe object.
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
EAPI void
|
|
||||||
ecore_pipe_thaw(Ecore_Pipe *p)
|
|
||||||
{
|
|
||||||
EINA_MAIN_LOOP_CHECK_RETURN;
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
|
||||||
{
|
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_thaw");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!p->fd_handler && p->fd_read != PIPE_FD_INVALID)
|
|
||||||
{
|
|
||||||
p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
|
|
||||||
ECORE_FD_READ,
|
|
||||||
_ecore_pipe_read,
|
|
||||||
p,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Wait from another thread on the read side of a pipe.
|
|
||||||
*
|
|
||||||
* @param p The pipe to watch on.
|
|
||||||
* @param message_count The minimal number of message to wait before exiting.
|
|
||||||
* @param wait The amount of time in second to wait before exiting.
|
|
||||||
* @return the number of message catched during that wait call.
|
|
||||||
* @since 1.1
|
|
||||||
*
|
|
||||||
* Negative value for @p wait means infite wait.
|
|
||||||
*/
|
|
||||||
EAPI int
|
|
||||||
ecore_pipe_wait(Ecore_Pipe *p,
|
|
||||||
int message_count,
|
|
||||||
double wait)
|
|
||||||
{
|
{
|
||||||
struct timeval tv, *t;
|
struct timeval tv, *t;
|
||||||
fd_set rset;
|
fd_set rset;
|
||||||
|
@ -347,136 +525,27 @@ ecore_pipe_wait(Ecore_Pipe *p,
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the write end of an Ecore_Pipe object created with ecore_pipe_add().
|
|
||||||
*
|
|
||||||
* @param p The Ecore_Pipe object.
|
|
||||||
*/
|
|
||||||
EAPI void
|
|
||||||
ecore_pipe_write_close(Ecore_Pipe *p)
|
|
||||||
{
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
|
||||||
{
|
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (p->fd_write != PIPE_FD_INVALID)
|
|
||||||
{
|
|
||||||
pipe_close(p->fd_write);
|
|
||||||
p->fd_write = PIPE_FD_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write on the file descriptor the data passed as parameter.
|
|
||||||
*
|
|
||||||
* @param p The Ecore_Pipe object.
|
|
||||||
* @param buffer The data to write into the pipe.
|
|
||||||
* @param nbytes The size of the @p buffer in bytes
|
|
||||||
* @return @c EINA_TRUE on a successful write, @c EINA_FALSE on error.
|
|
||||||
*/
|
|
||||||
EAPI Eina_Bool
|
|
||||||
ecore_pipe_write(Ecore_Pipe *p,
|
|
||||||
const void *buffer,
|
|
||||||
unsigned int nbytes)
|
|
||||||
{
|
|
||||||
ssize_t ret;
|
|
||||||
size_t already_written = 0;
|
|
||||||
int retry = ECORE_PIPE_WRITE_RETRY;
|
|
||||||
|
|
||||||
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
|
|
||||||
{
|
|
||||||
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->delete_me) return EINA_FALSE;
|
|
||||||
|
|
||||||
if (p->fd_write == PIPE_FD_INVALID) return EINA_FALSE;
|
|
||||||
|
|
||||||
/* First write the len into the pipe */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes));
|
|
||||||
if (ret == sizeof(nbytes))
|
|
||||||
{
|
|
||||||
retry = ECORE_PIPE_WRITE_RETRY;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (ret > 0)
|
|
||||||
{
|
|
||||||
/* XXX What should we do here? */
|
|
||||||
ERR("The length of the data was not written complete"
|
|
||||||
" to the pipe");
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
else if (ret == PIPE_FD_ERROR && errno == EPIPE)
|
|
||||||
{
|
|
||||||
pipe_close(p->fd_write);
|
|
||||||
p->fd_write = PIPE_FD_INVALID;
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
else if (ret == PIPE_FD_ERROR && errno == EINTR)
|
|
||||||
/* try it again */
|
|
||||||
;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERR("An unhandled error (ret: %zd errno: %d)"
|
|
||||||
"occurred while writing to the pipe the length",
|
|
||||||
ret, errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (retry--);
|
|
||||||
|
|
||||||
if (retry != ECORE_PIPE_WRITE_RETRY) return EINA_FALSE;
|
|
||||||
|
|
||||||
/* and now pass the data to the pipe */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ret = pipe_write(p->fd_write,
|
|
||||||
((unsigned char *)buffer) + already_written,
|
|
||||||
nbytes - already_written);
|
|
||||||
|
|
||||||
if (ret == (ssize_t)(nbytes - already_written))
|
|
||||||
return EINA_TRUE;
|
|
||||||
else if (ret >= 0)
|
|
||||||
{
|
|
||||||
already_written -= ret;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (ret == PIPE_FD_ERROR && errno == EPIPE)
|
|
||||||
{
|
|
||||||
pipe_close(p->fd_write);
|
|
||||||
p->fd_write = PIPE_FD_INVALID;
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
else if (ret == PIPE_FD_ERROR && errno == EINTR)
|
|
||||||
/* try it again */
|
|
||||||
;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERR("An unhandled error (ret: %zd errno: %d)"
|
|
||||||
"occurred while writing to the pipe the length",
|
|
||||||
ret, errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (retry--);
|
|
||||||
|
|
||||||
return EINA_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Private function */
|
|
||||||
static void
|
static void
|
||||||
_ecore_pipe_unhandle(Ecore_Pipe *p)
|
_ecore_pipe_unhandle(Ecore_Pipe *p)
|
||||||
{
|
{
|
||||||
p->handling--;
|
p->handling--;
|
||||||
if (p->delete_me)
|
if (p->delete_me)
|
||||||
{
|
{
|
||||||
ecore_pipe_del(p);
|
_ecore_pipe_del(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_ecore_pipe_handler_call(Ecore_Pipe *p,
|
||||||
|
unsigned char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
void *data = (void*) p->data;
|
||||||
|
if (!p->delete_me)
|
||||||
|
{
|
||||||
|
_ecore_unlock();
|
||||||
|
p->handler(data, buf, len);
|
||||||
|
_ecore_lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,8 +588,7 @@ _ecore_pipe_read(void *data,
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
/* no data on first try through means an error */
|
/* no data on first try through means an error */
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, NULL, 0);
|
||||||
p->handler((void *)p->data, NULL, 0);
|
|
||||||
if (p->passed_data) free(p->passed_data);
|
if (p->passed_data) free(p->passed_data);
|
||||||
p->passed_data = NULL;
|
p->passed_data = NULL;
|
||||||
p->already_read = 0;
|
p->already_read = 0;
|
||||||
|
@ -557,8 +625,7 @@ _ecore_pipe_read(void *data,
|
||||||
{
|
{
|
||||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
{
|
{
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, NULL, 0);
|
||||||
p->handler((void *)p->data, NULL, 0);
|
|
||||||
if (p->passed_data) free(p->passed_data);
|
if (p->passed_data) free(p->passed_data);
|
||||||
p->passed_data = NULL;
|
p->passed_data = NULL;
|
||||||
p->already_read = 0;
|
p->already_read = 0;
|
||||||
|
@ -579,8 +646,7 @@ _ecore_pipe_read(void *data,
|
||||||
* never happen */
|
* never happen */
|
||||||
if (p->len == 0)
|
if (p->len == 0)
|
||||||
{
|
{
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, NULL, 0);
|
||||||
p->handler((void *)p->data, NULL, 0);
|
|
||||||
/* reset all values to 0 */
|
/* reset all values to 0 */
|
||||||
if (p->passed_data) free(p->passed_data);
|
if (p->passed_data) free(p->passed_data);
|
||||||
p->passed_data = NULL;
|
p->passed_data = NULL;
|
||||||
|
@ -598,8 +664,7 @@ _ecore_pipe_read(void *data,
|
||||||
/* alloc failed - error case */
|
/* alloc failed - error case */
|
||||||
if (!p->passed_data)
|
if (!p->passed_data)
|
||||||
{
|
{
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, NULL, 0);
|
||||||
p->handler((void *)p->data, NULL, 0);
|
|
||||||
/* close the pipe */
|
/* close the pipe */
|
||||||
p->already_read = 0;
|
p->already_read = 0;
|
||||||
p->len = 0;
|
p->len = 0;
|
||||||
|
@ -621,8 +686,7 @@ _ecore_pipe_read(void *data,
|
||||||
/* if we read enough data to finish the message/buffer */
|
/* if we read enough data to finish the message/buffer */
|
||||||
if (ret == (ssize_t)(p->len - p->already_read))
|
if (ret == (ssize_t)(p->len - p->already_read))
|
||||||
{
|
{
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, p->passed_data, p->len);
|
||||||
p->handler((void *)p->data, p->passed_data, p->len);
|
|
||||||
free(p->passed_data);
|
free(p->passed_data);
|
||||||
/* reset all values to 0 */
|
/* reset all values to 0 */
|
||||||
p->passed_data = NULL;
|
p->passed_data = NULL;
|
||||||
|
@ -663,8 +727,7 @@ _ecore_pipe_read(void *data,
|
||||||
{
|
{
|
||||||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||||
{
|
{
|
||||||
if (!p->delete_me)
|
_ecore_pipe_handler_call(p, NULL, 0);
|
||||||
p->handler((void *)p->data, NULL, 0);
|
|
||||||
if (p->passed_data) free(p->passed_data);
|
if (p->passed_data) free(p->passed_data);
|
||||||
p->passed_data = NULL;
|
p->passed_data = NULL;
|
||||||
p->already_read = 0;
|
p->already_read = 0;
|
||||||
|
|
|
@ -170,6 +170,20 @@ void *_ecore_event_signal_exit_new(void);
|
||||||
void *_ecore_event_signal_power_new(void);
|
void *_ecore_event_signal_power_new(void);
|
||||||
void *_ecore_event_signal_realtime_new(void);
|
void *_ecore_event_signal_realtime_new(void);
|
||||||
|
|
||||||
|
Ecore_Pipe *_ecore_pipe_add(Ecore_Pipe_Cb handler,
|
||||||
|
const void *data);
|
||||||
|
int _ecore_pipe_wait(Ecore_Pipe *p,
|
||||||
|
int message_count,
|
||||||
|
double wait);
|
||||||
|
void *_ecore_pipe_del(Ecore_Pipe *p);
|
||||||
|
|
||||||
|
Ecore_Fd_Handler *
|
||||||
|
_ecore_main_fd_handler_add(int fd,
|
||||||
|
Ecore_Fd_Handler_Flags flags,
|
||||||
|
Ecore_Fd_Cb func,
|
||||||
|
const void *data,
|
||||||
|
Ecore_Fd_Cb buf_func,
|
||||||
|
const void *buf_data);
|
||||||
void *_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler);
|
void *_ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler);
|
||||||
|
|
||||||
void _ecore_main_shutdown(void);
|
void _ecore_main_shutdown(void);
|
||||||
|
|
Loading…
Reference in New Issue