efl/src/lib/ecore/ecore_pipe.c

758 lines
21 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <math.h>
#ifdef HAVE_IEEEFP_H
# include <ieeefp.h> /* for Solaris */
#endif
#ifdef HAVE_ISFINITE
# define ECORE_FINITE(t) isfinite(t)
#else
# define ECORE_FINITE(t) finite(t)
#endif
#define FIX_HZ 1
#ifdef FIX_HZ
# include <sys/param.h>
# ifndef HZ
# define HZ 100
# endif
#endif
/*
* On Windows, pipe() is implemented with sockets.
* Contrary to Linux, Windows uses different functions
* for sockets and fd's: write() is for fd's and send
* is for sockets. So I need to put some win32 code
* here. I can't think of a solution where the win32
* code is in Evil and not here.
*/
#define PIPE_FD_INVALID -1
#define PIPE_FD_ERROR -1
#ifdef _WIN32
# include <winsock2.h>
# include <evil_private.h> /* pipe fcntl */
#else
# ifdef HAVE_SYS_EPOLL_H
# include <sys/epoll.h>
# endif /* HAVE_SYS_EPOLL_H */
# ifdef HAVE_SYS_TIMERFD_H
# include <sys/timerfd.h>
# endif
# include <unistd.h>
# include <fcntl.h>
#endif /* ! _WIN32 */
#include "Ecore.h"
#include "ecore_private.h"
// How of then we should retry to write to the pipe
#define ECORE_PIPE_WRITE_RETRY 6
struct _Ecore_Pipe
{
ECORE_MAGIC;
int fd_read;
int fd_write;
Ecore_Fd_Handler *fd_handler;
const void *data;
Ecore_Pipe_Cb handler;
unsigned int len;
int handling;
unsigned int already_read;
void *passed_data;
int message;
#ifndef _WIN32
int pollfd;
int timerfd;
#endif
Eina_Bool delete_me : 1;
};
GENERIC_ALLOC_SIZE_DECLARE(Ecore_Pipe);
static Eina_Bool _ecore_pipe_read(void *data,
Ecore_Fd_Handler *fd_handler);
2010-10-17 00:03:28 -07:00
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Pipe *
ecore_pipe_add(Ecore_Pipe_Cb handler,
const void *data)
{
return _ecore_pipe_add(handler, data);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void *
ecore_pipe_del(Ecore_Pipe *p)
{
if (!p) return NULL;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
return _ecore_pipe_del(p);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_pipe_read_close(Ecore_Pipe *p)
{
EINA_MAIN_LOOP_CHECK_RETURN;
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
{
2010-09-29 23:09:20 -07:00
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
return;
}
if (p->fd_handler)
{
_ecore_main_fd_handler_del(ML_OBJ, ML_DAT, p->fd_handler);
p->fd_handler = NULL;
}
if (p->fd_read != PIPE_FD_INVALID)
{
eina_pipe_free(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
}
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_pipe_read_fd(Ecore_Pipe *p)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(PIPE_FD_INVALID);
if (!p) return PIPE_FD_INVALID;
return p->fd_read;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API 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(ML_OBJ, ML_DAT, p->fd_handler);
p->fd_handler = NULL;
}
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
2011-05-31 01:05:16 -07:00
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);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_pipe_wait(Ecore_Pipe *p,
int message_count,
double wait)
{
return _ecore_pipe_wait(p, message_count, wait);
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API void
ecore_pipe_write_close(Ecore_Pipe *p)
{
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
{
2010-09-29 23:09:20 -07:00
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
return;
}
if (p->fd_write != PIPE_FD_INVALID)
{
eina_pipe_free(p->fd_write);
p->fd_write = PIPE_FD_INVALID;
}
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API int
ecore_pipe_write_fd(Ecore_Pipe *p)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(PIPE_FD_INVALID);
if (!p) return PIPE_FD_INVALID;
return p->fd_write;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API 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;
unsigned int bytes = nbytes;
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
{
2010-09-29 23:09:20 -07:00
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;
do // First write the len into the pipe
{
ret = eina_pipe_write(p->fd_write, &bytes, sizeof(bytes));
2010-09-29 23:09:20 -07:00
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;
2010-09-29 23:09:20 -07:00
}
else if ((ret == PIPE_FD_ERROR) && (errno == EPIPE))
2010-09-29 23:09:20 -07:00
{
eina_pipe_free(p->fd_write);
2010-09-29 23:09:20 -07:00
p->fd_write = PIPE_FD_INVALID;
goto out;
2010-09-29 23:09:20 -07:00
}
else if ((ret == PIPE_FD_ERROR) && (errno == EINTR))
// try it again
2010-09-29 23:09:20 -07:00
;
else
{
ERR("An unhandled error (ret: %zd errno: %d)"
2010-09-29 23:09:20 -07:00
"occurred while writing to the pipe the length",
ret, errno);
}
}
while (retry--);
if (retry != ECORE_PIPE_WRITE_RETRY) goto out;
do // and now pass the data to the pipe
{
ret = eina_pipe_write(p->fd_write,
2009-08-12 17:27:53 -07:00
((unsigned char *)buffer) + already_written,
nbytes - already_written);
2010-09-29 23:09:20 -07:00
if (ret == (ssize_t)(nbytes - already_written))
{
ok = EINA_TRUE;
goto out;
}
2010-09-29 23:09:20 -07:00
else if (ret >= 0)
{
already_written -= ret;
continue;
}
else if ((ret == PIPE_FD_ERROR) && (errno == EPIPE))
2010-09-29 23:09:20 -07:00
{
eina_pipe_free(p->fd_write);
2010-09-29 23:09:20 -07:00
p->fd_write = PIPE_FD_INVALID;
goto out;
2010-09-29 23:09:20 -07:00
}
else if ((ret == PIPE_FD_ERROR) && (errno == EINTR))
// try it again
2010-09-29 23:09:20 -07:00
;
else
{
ERR("An unhandled error (ret: %zd errno: %d)"
2010-09-29 23:09:20 -07:00
"occurred while writing to the pipe the length",
ret, errno);
}
}
while (retry--);
out:
return ok;
}
ecore: Rename EAPI macro to ECORE_API in Ecore library Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass ```__attribute__ ((visibility ("default")))``` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as ```__atttribute__((visibility("default")))```. However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com>
2020-09-20 06:23:26 -07:00
ECORE_API Ecore_Pipe *
ecore_pipe_full_add(Ecore_Pipe_Cb handler,
const void *data,
int fd_read,
int fd_write,
Eina_Bool read_survive_fork,
Eina_Bool write_survive_fork)
{
Ecore_Pipe *p = NULL;
int fds[2];
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!handler) return NULL;
p = ecore_pipe_calloc(1);
if (!p) return NULL;
if ((fd_read == -1) && (fd_write == -1))
{
if (eina_pipe_new(fds))
{
ecore_pipe_mp_free(p);
return NULL;
}
fd_read = fds[0];
fd_write = fds[1];
}
else
{
fd_read = (fd_read == -1) ? PIPE_FD_INVALID : fd_read;
fd_write = (fd_write == -1) ? PIPE_FD_INVALID : fd_write;
}
ECORE_MAGIC_SET(p, ECORE_MAGIC_PIPE);
p->fd_read = fd_read;
p->fd_write = fd_write;
p->handler = handler;
p->data = data;
if (!read_survive_fork) eina_file_close_on_exec(fd_read, EINA_TRUE);
if (!write_survive_fork) eina_file_close_on_exec(fd_write, EINA_TRUE);
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H)
struct epoll_event pollev = { 0 };
p->pollfd = epoll_create(1);
p->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
eina_file_close_on_exec(p->pollfd, EINA_TRUE);
pollev.data.ptr = &(p->fd_read);
pollev.events = EPOLLIN;
epoll_ctl(p->pollfd, EPOLL_CTL_ADD, p->fd_read, &pollev);
pollev.data.ptr = &(p->timerfd);
pollev.events = EPOLLIN;
epoll_ctl(p->pollfd, EPOLL_CTL_ADD, p->timerfd, &pollev);
#endif
2017-04-17 17:55:50 -07:00
if (fcntl(p->fd_read, F_SETFL, O_NONBLOCK) < 0)
ERR("can't set pipe to NONBLOCK");
p->fd_handler = ecore_main_fd_handler_add(p->fd_read, ECORE_FD_READ,
_ecore_pipe_read, p, NULL, NULL);
return p;
}
// Private functions
Ecore_Pipe *
_ecore_pipe_add(Ecore_Pipe_Cb handler,
const void *data)
{
return ecore_pipe_full_add(handler, data, -1, -1, EINA_FALSE, EINA_FALSE);
}
void *
_ecore_pipe_del(Ecore_Pipe *p)
{
void *data = NULL;
if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
{
ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
return NULL;
}
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H)
epoll_ctl(p->pollfd, EPOLL_CTL_DEL, p->fd_read, NULL);
epoll_ctl(p->pollfd, EPOLL_CTL_DEL, p->timerfd, NULL);
if (p->timerfd >= 0) close(p->timerfd);
if (p->pollfd >= 0) close(p->pollfd);
p->timerfd = PIPE_FD_INVALID;
p->pollfd = PIPE_FD_INVALID;
#endif
p->delete_me = EINA_TRUE;
if (p->handling > 0) return (void *)p->data;
if (p->fd_handler) _ecore_main_fd_handler_del(ML_OBJ, ML_DAT,
p->fd_handler);
if (p->fd_read != PIPE_FD_INVALID) eina_pipe_free(p->fd_read);
if (p->fd_write != PIPE_FD_INVALID) eina_pipe_free(p->fd_write);
p->fd_handler = NULL;
p->fd_read = PIPE_FD_INVALID;
p->fd_write = PIPE_FD_INVALID;
data = (void *)p->data;
ecore_pipe_mp_free(p);
return data;
}
static void
_ecore_pipe_unhandle(Ecore_Pipe *p)
{
p->handling--;
if (p->delete_me) _ecore_pipe_del(p);
}
#if ! defined(HAVE_SYS_EPOLL_H) || ! defined(HAVE_SYS_TIMERFD_H)
int
_ecore_pipe_wait(Ecore_Pipe *p,
int message_count,
double wait)
{
struct timeval tv, *t;
fd_set rset, wset, exset;
double end = 0.0;
double timeout;
int ret;
int total = 0;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1);
if (p->fd_read == PIPE_FD_INVALID) return -1;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&exset);
FD_SET(p->fd_read, &rset);
if (wait >= 0.0) end = ecore_time_get() + wait;
timeout = wait;
while ((message_count > 0) && ((timeout > 0.0) || (wait <= 0.0)))
{
if (wait >= 0.0)
{
// finite() tests for NaN, too big, too small, and infinity.
if ((!ECORE_FINITE(timeout)) || (EINA_DBL_EQ(timeout, 0.0)))
{
tv.tv_sec = 0;
tv.tv_usec = 0;
}
else if (timeout > 0.0)
{
int sec, usec;
#ifdef FIX_HZ
timeout += (0.5 / HZ);
#endif
sec = (int)timeout;
usec = (int)((timeout - (double)sec) * 1000000);
tv.tv_sec = sec;
tv.tv_usec = usec;
}
t = &tv;
}
else t = NULL;
ret = main_loop_select(p->fd_read + 1, &rset, &wset, &exset, t);
if (ret > 0)
{
p->handling++;
_ecore_pipe_read(p, NULL);
message_count -= p->message;
total += p->message;
p->message = 0;
_ecore_pipe_unhandle(p);
}
else if (ret == 0) break;
else if (errno != EINTR)
{
if (p->fd_read != PIPE_FD_INVALID)
{
close(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
}
break;
}
if (wait >= 0.0) timeout = end - ecore_time_get();
}
return total;
}
#else
int
_ecore_pipe_wait(Ecore_Pipe *p,
int message_count,
double wait)
{
int64_t timerfdbuf;
struct epoll_event pollincoming[2];
double timeout;
int ret = 0;
int total = 0;
int time_exit = -1;
Eina_Bool fd_read_found;
Eina_Bool fd_timer_found;
struct itimerspec tspec_new;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(-1);
if (p->fd_read == PIPE_FD_INVALID) return -1;
timeout = wait;
int sec, usec;
if (wait >= 0.0)
{
if ((!ECORE_FINITE(timeout)) || (EINA_DBL_EQ(timeout, 0.0)))
{
tspec_new.it_value.tv_sec = 0;
tspec_new.it_value.tv_nsec = 0;
tspec_new.it_interval.tv_sec = 0;
tspec_new.it_interval.tv_nsec = 0;
time_exit = 0;
}
else
{
#ifdef FIX_HZ
timeout += (0.5 / HZ);
#endif
sec = (int)timeout;
usec = (int)((timeout - (double)sec) * 1000000000);
tspec_new.it_value.tv_sec = sec;
tspec_new.it_value.tv_nsec = (int)(usec) % 1000000000;
tspec_new.it_interval.tv_sec = 0;
tspec_new.it_interval.tv_nsec = 0;
timerfd_settime(p->timerfd, 0, &tspec_new, NULL);
}
}
while ((p->pollfd != PIPE_FD_INVALID) && (ret = epoll_wait(p->pollfd, pollincoming, 2, time_exit)) > 0)
{
fd_read_found = EINA_FALSE;
fd_timer_found = EINA_FALSE;
for (int i = 0; i < ret;i++)
{
if ((&p->fd_read == pollincoming[i].data.ptr))
fd_read_found = EINA_TRUE;
if ((&p->timerfd == pollincoming[i].data.ptr))
fd_timer_found = EINA_TRUE;
}
p->handling++;
if (fd_read_found)
{
_ecore_pipe_read(p, NULL);
message_count -= p->message;
total += p->message;
p->message = 0;
if (message_count <= 0)
{
_ecore_pipe_unhandle(p);
break;
}
}
if ((fd_timer_found) && (p->timerfd != PIPE_FD_INVALID))
{
if (eina_pipe_read(p->timerfd, &timerfdbuf, sizeof(timerfdbuf)) <
(int)sizeof(int64_t))
WRN("Could not read timerfd data");
_ecore_pipe_unhandle(p);
break;
}
_ecore_pipe_unhandle(p);
}
if (ret < 0)
{
if (errno != EBADF)
WRN("epoll file descriptor is not a valid");
else if (errno != EINVAL)
WRN("epoll file descriptor is not an epoll file descriptor, or maxevents is less than or equal to zero.");
else if (errno != EFAULT)
WRN("The memory area pointed to by epoll_event is not accessible with write permissions.");
else if (errno != EINTR)
WRN("The call was interrupted by a signal handler before any of the requested epoll_event "
"occurred or the timeout expired; see signal(7).");
}
return total;
}
#endif
static void
_ecore_pipe_handler_call(Ecore_Pipe *p,
unsigned char *buf,
size_t len)
{
void *data = (void*) p->data;
// clear all values of pipe first.
p->passed_data = NULL;
p->already_read = 0;
p->len = 0;
p->message++;
if (!p->delete_me) p->handler(data, buf, len);
// free p->passed_data
free(buf);
}
static Eina_Bool
_ecore_pipe_read(void *data,
Ecore_Fd_Handler *fd_handler EINA_UNUSED)
{
Ecore_Pipe *p = (Ecore_Pipe *)data;
int i;
p->handling++;
for (i = 0; i < 16; i++)
{
ssize_t ret;
2010-09-29 23:09:20 -07:00
// if we already have read some data we don't need to read the len
// but to finish the already started job
2010-09-29 23:09:20 -07:00
if (p->len == 0)
{
// read the len of the passed data
ret = eina_pipe_read(p->fd_read, &p->len, sizeof(p->len));
// catch the non error case first
// read amount ok - nothing more to do
if (ret == sizeof(p->len))
;
else if (ret > 0)
{
// we got more data than we asked for - definite error
ERR("Only read %i bytes from the pipe, although"
" we need to read %i bytes.",
(int)ret, (int)sizeof(p->len));
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_CANCEL;
}
else if (ret == 0)
{
// we got no data
if (i == 0)
{
// no data on first try through means an error
_ecore_pipe_handler_call(p, NULL, 0);
eina_pipe_free(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
p->fd_handler = NULL;
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_CANCEL;
}
else
{
// no data after first loop try is ok
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}
}
#ifndef _WIN32
else if ((ret == PIPE_FD_ERROR) &&
((errno == EINTR) || (errno == EAGAIN)))
{
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}
else
{
ERR("An unhandled error (ret: %i errno: %i [%s])"
"occurred while reading from the pipe the length",
(int)ret, errno, strerror(errno));
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}
#else
else // ret == PIPE_FD_ERROR is the only other case on Windows
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
_ecore_pipe_handler_call(p, NULL, 0);
eina_pipe_free(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
p->fd_handler = NULL;
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_CANCEL;
}
}
#endif
2010-09-29 23:09:20 -07:00
}
// if somehow we got less than or equal to 0 we got an errnoneous
// messages so call callback with null and len we got. this case should
// never happen
if (p->len == 0)
{
_ecore_pipe_handler_call(p, NULL, 0);
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}
// we dont have a buffer to hold the data, so alloc it
2010-09-29 23:09:20 -07:00
if (!p->passed_data)
{
p->passed_data = malloc(p->len);
// alloc failed - error case
if (!p->passed_data)
{
_ecore_pipe_handler_call(p, NULL, 0);
// close the pipe
eina_pipe_free(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
p->fd_handler = NULL;
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_CANCEL;
}
}
// and read the passed data
ret = eina_pipe_read(p->fd_read,
2009-08-12 17:27:53 -07:00
((unsigned char *)p->passed_data) + p->already_read,
p->len - p->already_read);
// catch the non error case first
// if we read enough data to finish the message/buffer
if (ret == (ssize_t)(p->len - p->already_read))
_ecore_pipe_handler_call(p, p->passed_data, p->len);
else if (ret > 0)
2010-09-29 23:09:20 -07:00
{
// more data left to read
p->already_read += (unsigned int)ret;
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
2010-09-29 23:09:20 -07:00
}
else if (ret == 0)
{
// 0 bytes to read - could be more to read next select wake up
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
2010-09-29 23:09:20 -07:00
}
#ifndef _WIN32
else if ((ret == PIPE_FD_ERROR) &&
((errno == EINTR) || (errno == EAGAIN)))
{
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}
2010-09-29 23:09:20 -07:00
else
{
ERR("An unhandled error (ret: %zd errno: %d)"
"occurred while reading from the pipe the data",
ret, errno);
_ecore_pipe_unhandle(p);
2010-09-29 23:09:20 -07:00
return ECORE_CALLBACK_RENEW;
}
#else
else // ret == PIPE_FD_ERROR is the only other case on Windows
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
_ecore_pipe_handler_call(p, NULL, 0);
eina_pipe_free(p->fd_read);
p->fd_read = PIPE_FD_INVALID;
p->fd_handler = NULL;
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_CANCEL;
}
else break;
}
#endif
}
_ecore_pipe_unhandle(p);
return ECORE_CALLBACK_RENEW;
}