forked from enlightenment/efl
ecore/signal: increase maximum signal throughput
this adds 4 more signal handling fds and loops over them for reading/writing signal info in order to handle more signals when the buffer of one (or more) pipes is full also update the unit test to verify that we are receiving all the events without dropping any and bump the number of signals to 2000 since we should now be able to handle that many Reviewed-by: Cedric BAIL <cedric.bail@free.fr> Differential Revision: https://phab.enlightenment.org/D10027
This commit is contained in:
parent
af5abbe4bc
commit
da5fcb8ea0
|
@ -34,8 +34,10 @@ static void _ecore_signal_generic_free(void *data, void *event);
|
|||
|
||||
typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo);
|
||||
|
||||
static int sig_pipe[2] = { -1, -1 }; // [0] == read, [1] == write
|
||||
static Eo *sig_pipe_handler = NULL;
|
||||
#define NUM_PIPES 5
|
||||
|
||||
static int sig_pipe[NUM_PIPES][2] = {{ -1 }}; // [0] == read, [1] == write
|
||||
static Eo *sig_pipe_handler[NUM_PIPES] = {NULL};
|
||||
static Eina_Spinlock sig_pid_lock;
|
||||
static Eina_List *sig_pid_info_list = NULL;
|
||||
|
||||
|
@ -48,114 +50,111 @@ typedef struct _Signal_Data
|
|||
siginfo_t info;
|
||||
} Signal_Data;
|
||||
|
||||
static Eina_Bool
|
||||
static void
|
||||
_ecore_signal_pipe_read(Eo *obj)
|
||||
{
|
||||
Signal_Data sdata;
|
||||
int ret;
|
||||
|
||||
if (pipe_dead) return EINA_TRUE;
|
||||
ret = read(sig_pipe[0], &sdata, sizeof(sdata));
|
||||
if (ret != sizeof(sdata)) return EINA_FALSE;
|
||||
switch (sdata.sig)
|
||||
if (pipe_dead) return;
|
||||
for (unsigned int i = 0; i < NUM_PIPES; i++)
|
||||
{
|
||||
case SIGPIPE:
|
||||
break;
|
||||
case SIGALRM:
|
||||
break;
|
||||
case SIGCHLD:
|
||||
_ecore_signal_waitpid(EINA_FALSE, sdata.info);
|
||||
break;
|
||||
case SIGUSR1:
|
||||
case SIGUSR2:
|
||||
while (1)
|
||||
{
|
||||
Ecore_Event_Signal_User *e = _ecore_event_signal_user_new();
|
||||
if (e)
|
||||
ret = read(sig_pipe[i][0], &sdata, sizeof(sdata));
|
||||
|
||||
/* read as many signals as we can, trying again if we get interrupted */
|
||||
if ((ret != sizeof(sdata)) && (errno != EINTR)) break;
|
||||
switch (sdata.sig)
|
||||
{
|
||||
if (sdata.sig == SIGUSR1) e->number = 1;
|
||||
else e->number = 2;
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
case SIGPIPE:
|
||||
break;
|
||||
case SIGALRM:
|
||||
break;
|
||||
case SIGCHLD:
|
||||
_ecore_signal_waitpid(EINA_FALSE, sdata.info);
|
||||
break;
|
||||
case SIGUSR1:
|
||||
case SIGUSR2:
|
||||
{
|
||||
Ecore_Event_Signal_User *e = _ecore_event_signal_user_new();
|
||||
if (e)
|
||||
{
|
||||
if (sdata.sig == SIGUSR1) e->number = 1;
|
||||
else e->number = 2;
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_USER, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
{
|
||||
if (sdata.sig == SIGUSR1)
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR1, NULL);
|
||||
else
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR2, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SIGHUP:
|
||||
{
|
||||
Ecore_Event_Signal_Hup *e = _ecore_event_signal_hup_new();
|
||||
if (e)
|
||||
{
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_HUP, NULL);
|
||||
}
|
||||
break;
|
||||
case SIGQUIT:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
{
|
||||
Ecore_Event_Signal_Exit *e = _ecore_event_signal_exit_new();
|
||||
if (e)
|
||||
{
|
||||
if (sdata.sig == SIGQUIT) e->quit = 1;
|
||||
else if (sdata.sig == SIGINT) e->interrupt = 1;
|
||||
else e->terminate = 1;
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
efl_event_callback_call(loop, EFL_LOOP_EVENT_QUIT, NULL);
|
||||
}
|
||||
break;
|
||||
#ifdef SIGPWR
|
||||
case SIGPWR:
|
||||
{
|
||||
Ecore_Event_Signal_Power *e = _ecore_event_signal_power_new();
|
||||
if (e)
|
||||
{
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
{
|
||||
if (sdata.sig == SIGUSR1)
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR1, NULL);
|
||||
else
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR2, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SIGHUP:
|
||||
{
|
||||
Ecore_Event_Signal_Hup *e = _ecore_event_signal_hup_new();
|
||||
if (e)
|
||||
{
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_HUP, NULL);
|
||||
}
|
||||
break;
|
||||
case SIGQUIT:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
{
|
||||
Ecore_Event_Signal_Exit *e = _ecore_event_signal_exit_new();
|
||||
if (e)
|
||||
{
|
||||
if (sdata.sig == SIGQUIT) e->quit = 1;
|
||||
else if (sdata.sig == SIGINT) e->interrupt = 1;
|
||||
else e->terminate = 1;
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
|
||||
if (loop)
|
||||
efl_event_callback_call(loop, EFL_LOOP_EVENT_QUIT, NULL);
|
||||
}
|
||||
break;
|
||||
#ifdef SIGPWR
|
||||
case SIGPWR:
|
||||
{
|
||||
Ecore_Event_Signal_Power *e = _ecore_event_signal_power_new();
|
||||
if (e)
|
||||
{
|
||||
e->data = sdata.info;
|
||||
ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e,
|
||||
_ecore_signal_generic_free, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_signal_cb_read(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
|
||||
{
|
||||
while (_ecore_signal_pipe_read(event->object));
|
||||
_ecore_signal_pipe_read(event->object);
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_signal_cb_del(void *data EINA_UNUSED, const Efl_Event *event)
|
||||
{
|
||||
if (event->object == sig_pipe_handler) sig_pipe_handler = NULL;
|
||||
}
|
||||
|
||||
EFL_CALLBACKS_ARRAY_DEFINE(_event_watch,
|
||||
{ EFL_LOOP_HANDLER_EVENT_READ, _ecore_signal_cb_read },
|
||||
{ EFL_EVENT_DEL, _ecore_signal_cb_del });
|
||||
|
||||
static void
|
||||
_ecore_signal_callback(int sig, siginfo_t *si, void *foo EINA_UNUSED)
|
||||
{
|
||||
|
@ -168,17 +167,25 @@ _ecore_signal_callback(int sig, siginfo_t *si, void *foo EINA_UNUSED)
|
|||
{
|
||||
int err = errno;
|
||||
if (pipe_dead) return;
|
||||
do
|
||||
for (unsigned int i = 0; i < NUM_PIPES; i++)
|
||||
{
|
||||
const ssize_t bytes = write(sig_pipe[1], &sdata, sizeof(sdata));
|
||||
if (EINA_UNLIKELY(bytes != sizeof(sdata)))
|
||||
do
|
||||
{
|
||||
err = errno;
|
||||
ERR("write() failed: %d: %s", err, strerror(err));
|
||||
}
|
||||
errno = err;
|
||||
/* loop if we got preempted */
|
||||
} while (err == EINTR);
|
||||
err = 0;
|
||||
const ssize_t bytes = write(sig_pipe[i][1], &sdata, sizeof(sdata));
|
||||
if (EINA_UNLIKELY(bytes != sizeof(sdata)))
|
||||
{
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
DBG("signal pipe %u full", i);
|
||||
else if (i == NUM_PIPES - 1) //only print errors on last pipe
|
||||
ERR("write() failed: %d: %s", err, strerror(err));
|
||||
}
|
||||
errno = err;
|
||||
/* loop if we got preempted */
|
||||
} while (err == EINTR);
|
||||
if (!err) break;
|
||||
}
|
||||
}
|
||||
switch (sig)
|
||||
{
|
||||
|
@ -242,45 +249,52 @@ static void
|
|||
_ecore_signal_pipe_init(void)
|
||||
{
|
||||
eina_spinlock_new(&sig_pid_lock);
|
||||
if (sig_pipe[0] == -1)
|
||||
{
|
||||
if (pipe(sig_pipe) != 0)
|
||||
{
|
||||
sig_pipe[0] = -1;
|
||||
return;
|
||||
}
|
||||
eina_file_close_on_exec(sig_pipe[0], EINA_TRUE);
|
||||
eina_file_close_on_exec(sig_pipe[1], EINA_TRUE);
|
||||
if (fcntl(sig_pipe[0], F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("can't set pipe to NONBLOCK");
|
||||
if (fcntl(sig_pipe[1], F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("can't set pipe to NONBLOCK");
|
||||
|
||||
}
|
||||
_signalhandler_setup();
|
||||
if (!sig_pipe_handler)
|
||||
sig_pipe_handler =
|
||||
efl_add(EFL_LOOP_HANDLER_CLASS, ML_OBJ,
|
||||
efl_loop_handler_fd_set(efl_added, sig_pipe[0]),
|
||||
efl_loop_handler_active_set(efl_added, EFL_LOOP_HANDLER_FLAGS_READ),
|
||||
efl_event_callback_array_add(efl_added, _event_watch(), NULL));
|
||||
if (sig_pipe[0][0] == -1)
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_PIPES; i++)
|
||||
{
|
||||
if (pipe(sig_pipe[i]) != 0)
|
||||
{
|
||||
CRI("failed setting up signal pipes! %s", strerror(errno));
|
||||
for (unsigned int j = 0; j < i; j++)
|
||||
{
|
||||
close(sig_pipe[j][0]);
|
||||
close(sig_pipe[j][1]);
|
||||
}
|
||||
memset(sig_pipe, -1, sizeof(sig_pipe));
|
||||
return;
|
||||
}
|
||||
eina_file_close_on_exec(sig_pipe[i][0], EINA_TRUE);
|
||||
eina_file_close_on_exec(sig_pipe[i][1], EINA_TRUE);
|
||||
if (fcntl(sig_pipe[i][0], F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("can't set pipe to NONBLOCK");
|
||||
if (fcntl(sig_pipe[i][1], F_SETFL, O_NONBLOCK) < 0)
|
||||
ERR("can't set pipe to NONBLOCK");
|
||||
efl_add(EFL_LOOP_HANDLER_CLASS, ML_OBJ,
|
||||
efl_loop_handler_fd_set(efl_added, sig_pipe[i][0]),
|
||||
efl_loop_handler_active_set(efl_added, EFL_LOOP_HANDLER_FLAGS_READ),
|
||||
efl_event_callback_add(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _ecore_signal_cb_read, NULL),
|
||||
efl_wref_add(efl_added, &sig_pipe_handler[i])
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_signal_pipe_shutdown(void)
|
||||
{
|
||||
if (sig_pipe_handler)
|
||||
if (sig_pipe[0][0] != -1)
|
||||
{
|
||||
efl_del(sig_pipe_handler);
|
||||
sig_pipe_handler = NULL;
|
||||
}
|
||||
if (sig_pipe[0] != -1)
|
||||
{
|
||||
close(sig_pipe[0]);
|
||||
close(sig_pipe[1]);
|
||||
sig_pipe[0] = -1;
|
||||
sig_pipe[1] = -1;
|
||||
for (unsigned int i = 0; i < NUM_PIPES; i++)
|
||||
{
|
||||
close(sig_pipe[i][0]);
|
||||
close(sig_pipe[i][1]);
|
||||
efl_del(sig_pipe_handler[i]);
|
||||
}
|
||||
}
|
||||
memset(sig_pipe, -1, sizeof(sig_pipe));
|
||||
eina_spinlock_free(&sig_pid_lock);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,21 +29,31 @@ EFL_START_TEST(ecore_test_job)
|
|||
EFL_END_TEST
|
||||
|
||||
#ifndef _WIN32
|
||||
#define NUM_SIGNALS 2000
|
||||
static Eina_Bool
|
||||
_signal_cb(void *data, int t EINA_UNUSED, void *ev EINA_UNUSED)
|
||||
{
|
||||
int *called = data;
|
||||
(*called)++;
|
||||
if (*called == NUM_SIGNALS) ecore_main_loop_quit();
|
||||
return ECORE_CALLBACK_RENEW;
|
||||
}
|
||||
|
||||
static void
|
||||
_ecore_signal_job(void *data EINA_UNUSED)
|
||||
{
|
||||
EXPECT_ERROR_START;
|
||||
for (unsigned int i = 0; i < 1000; i++)
|
||||
for (unsigned int i = 0; i < NUM_SIGNALS; i++)
|
||||
raise(SIGUSR2);
|
||||
ecore_main_loop_quit();
|
||||
EXPECT_ERROR_END;
|
||||
}
|
||||
|
||||
EFL_START_TEST(ecore_test_job_signal)
|
||||
{
|
||||
int called = 0;
|
||||
ecore_job_add(_ecore_signal_job, NULL);
|
||||
ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, _signal_cb, &called);
|
||||
|
||||
ecore_main_loop_begin();
|
||||
ck_assert_int_eq(called, NUM_SIGNALS);
|
||||
}
|
||||
EFL_END_TEST
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue