forked from enlightenment/efl
Add a better support of timers
Now, the timers are handled in one dedicated thread. Multiple timers are supported.
This commit is contained in:
parent
39c6a9562b
commit
f5cbb61bf4
|
@ -126,6 +126,7 @@ lib/eina/eina_debug_bt_file.c \
|
||||||
lib/eina/eina_debug_chunk.c \
|
lib/eina/eina_debug_chunk.c \
|
||||||
lib/eina/eina_debug_thread.c \
|
lib/eina/eina_debug_thread.c \
|
||||||
lib/eina/eina_debug_cpu.c \
|
lib/eina/eina_debug_cpu.c \
|
||||||
|
lib/eina/eina_debug_timer.c \
|
||||||
lib/eina/eina_error.c \
|
lib/eina/eina_error.c \
|
||||||
lib/eina/eina_evlog.c \
|
lib/eina/eina_evlog.c \
|
||||||
lib/eina/eina_file_common.h \
|
lib/eina/eina_file_common.h \
|
||||||
|
|
|
@ -86,10 +86,6 @@ static Eina_Hash *_modules_hash = NULL;
|
||||||
|
|
||||||
static int _bridge_keep_alive_opcode = EINA_DEBUG_OPCODE_INVALID;
|
static int _bridge_keep_alive_opcode = EINA_DEBUG_OPCODE_INVALID;
|
||||||
|
|
||||||
static unsigned int _poll_time = 0;
|
|
||||||
static Eina_Debug_Timer_Cb _poll_timer_cb = NULL;
|
|
||||||
static void *_poll_timer_data = NULL;
|
|
||||||
|
|
||||||
static Eina_Semaphore _thread_cmd_ready_sem;
|
static Eina_Semaphore _thread_cmd_ready_sem;
|
||||||
|
|
||||||
typedef void *(*Eina_Debug_Encode_Cb)(const void *buffer, int size, int *ret_size);
|
typedef void *(*Eina_Debug_Encode_Cb)(const void *buffer, int size, int *ret_size);
|
||||||
|
@ -767,15 +763,6 @@ eina_debug_shell_remote_connect(const char *cmds_str)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPI Eina_Bool
|
|
||||||
eina_debug_timer_add(unsigned int timeout_ms, Eina_Debug_Timer_Cb cb, void *data)
|
|
||||||
{
|
|
||||||
_poll_time = timeout_ms;
|
|
||||||
_poll_timer_cb = cb;
|
|
||||||
_poll_timer_data = data;
|
|
||||||
return EINA_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is a DEDICATED debug thread to monitor the application so it works
|
// this is a DEDICATED debug thread to monitor the application so it works
|
||||||
// even if the mainloop is blocked or the app otherwise deadlocked in some
|
// even if the mainloop is blocked or the app otherwise deadlocked in some
|
||||||
// way. this is an alternative to using external debuggers so we can get
|
// way. this is an alternative to using external debuggers so we can get
|
||||||
|
@ -784,17 +771,7 @@ static void *
|
||||||
_monitor(void *_data)
|
_monitor(void *_data)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#define MAX_EVENTS 4
|
|
||||||
int ret;
|
|
||||||
struct epoll_event event;
|
|
||||||
struct epoll_event events[MAX_EVENTS];
|
|
||||||
int epfd = epoll_create(MAX_EVENTS);
|
|
||||||
|
|
||||||
_session = _data;
|
_session = _data;
|
||||||
event.data.fd = _session->fd_in;
|
|
||||||
event.events = EPOLLIN;
|
|
||||||
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, _session->fd_in, &event);
|
|
||||||
if (ret) perror("epoll_ctl/add");
|
|
||||||
|
|
||||||
// set a name for this thread for system debugging
|
// set a name for this thread for system debugging
|
||||||
#ifdef EINA_HAVE_PTHREAD_SETNAME
|
#ifdef EINA_HAVE_PTHREAD_SETNAME
|
||||||
|
@ -811,63 +788,34 @@ _monitor(void *_data)
|
||||||
// impact the application specifically
|
// impact the application specifically
|
||||||
for (;_session;)
|
for (;_session;)
|
||||||
{
|
{
|
||||||
// if we are in a polling mode then set up a timeout and wait for it
|
int size;
|
||||||
int timeout = _poll_time ? (int)_poll_time : -1; //in milliseconds
|
unsigned char *buffer;
|
||||||
|
|
||||||
ret = epoll_wait(epfd, events, MAX_EVENTS, timeout);
|
size = _packet_receive(&buffer);
|
||||||
|
// if not negative - we have a real message
|
||||||
// if the fd for debug daemon says it's alive, process it
|
if (size > 0)
|
||||||
if (ret)
|
|
||||||
{
|
{
|
||||||
int i;
|
if (EINA_DEBUG_OK != _session->dispatch_cb(_session, buffer))
|
||||||
//check which fd are set/ready for read
|
|
||||||
for (i = 0; i < ret; i++)
|
|
||||||
{
|
{
|
||||||
if (events[i].events & EPOLLHUP)
|
// something we don't understand
|
||||||
{
|
e_debug("EINA DEBUG ERROR: Unknown command");
|
||||||
_opcodes_unregister_all(_session);
|
|
||||||
free(_session);
|
|
||||||
_session = NULL;
|
|
||||||
}
|
|
||||||
else if (events[i].events & EPOLLIN)
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
unsigned char *buffer;
|
|
||||||
|
|
||||||
size = _packet_receive(&buffer);
|
|
||||||
// if not negative - we have a real message
|
|
||||||
if (size > 0)
|
|
||||||
{
|
|
||||||
if (EINA_DEBUG_OK != _session->dispatch_cb(_session, buffer))
|
|
||||||
{
|
|
||||||
// something we don't understand
|
|
||||||
e_debug("EINA DEBUG ERROR: Unknown command");
|
|
||||||
}
|
|
||||||
/* Free the buffer only if the default dispatcher is used */
|
|
||||||
if (_session->dispatch_cb == eina_debug_dispatch)
|
|
||||||
free(buffer);
|
|
||||||
}
|
|
||||||
else if (size == 0)
|
|
||||||
{
|
|
||||||
// May be due to a response from a script line
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// major failure on debug daemon control fd - get out of here.
|
|
||||||
// else goto fail;
|
|
||||||
close(_session->fd_in);
|
|
||||||
//TODO if its not main _session we will tell the main_loop
|
|
||||||
//that it disconneted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* Free the buffer only if the default dispatcher is used */
|
||||||
|
if (_session->dispatch_cb == eina_debug_dispatch)
|
||||||
|
free(buffer);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
else if (size == 0)
|
||||||
|
{
|
||||||
|
// May be due to a response from a script line
|
||||||
|
}
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_poll_time && _poll_timer_cb)
|
close(_session->fd_in);
|
||||||
{
|
_opcodes_unregister_all(_session);
|
||||||
if (!_poll_timer_cb(_poll_timer_data)) _poll_time = 0;
|
free(_session);
|
||||||
}
|
_session = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1169,12 +1117,14 @@ eina_debug_init(void)
|
||||||
_signal_init();
|
_signal_init();
|
||||||
_eina_debug_cpu_init();
|
_eina_debug_cpu_init();
|
||||||
_eina_debug_bt_init();
|
_eina_debug_bt_init();
|
||||||
|
_eina_debug_timer_init();
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Eina_Bool
|
Eina_Bool
|
||||||
eina_debug_shutdown(void)
|
eina_debug_shutdown(void)
|
||||||
{
|
{
|
||||||
|
_eina_debug_timer_shutdown();
|
||||||
_eina_debug_bt_shutdown();
|
_eina_debug_bt_shutdown();
|
||||||
_eina_debug_cpu_shutdown();
|
_eina_debug_cpu_shutdown();
|
||||||
eina_semaphore_free(&_thread_cmd_ready_sem);
|
eina_semaphore_free(&_thread_cmd_ready_sem);
|
||||||
|
|
|
@ -107,6 +107,11 @@ typedef Eina_Debug_Error (*Eina_Debug_Dispatch_Cb)(Eina_Debug_Session *session,
|
||||||
*/
|
*/
|
||||||
typedef Eina_Bool (*Eina_Debug_Timer_Cb)(void *);
|
typedef Eina_Bool (*Eina_Debug_Timer_Cb)(void *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Eina_Debug_Timer
|
||||||
|
*/
|
||||||
|
typedef struct _Eina_Debug_Timer Eina_Debug_Timer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef Eina_Debug_Packet_Header
|
* @typedef Eina_Debug_Packet_Header
|
||||||
*
|
*
|
||||||
|
@ -275,15 +280,23 @@ EAPI int eina_debug_session_send_to_thread(Eina_Debug_Session *session, int dest
|
||||||
/**
|
/**
|
||||||
* @brief Add a timer
|
* @brief Add a timer
|
||||||
*
|
*
|
||||||
* Needed for polling debug
|
|
||||||
*
|
|
||||||
* @param timeout_ms timeout in ms
|
* @param timeout_ms timeout in ms
|
||||||
* @param cb callback to call when the timeout is reached
|
* @param cb callback to call when the timeout is reached
|
||||||
* @param data user data
|
* @param data user data
|
||||||
*
|
*
|
||||||
* @return EINA_TRUE on success, EINA_FALSE otherwise
|
* @return the timer handle, NULL on error
|
||||||
*/
|
*/
|
||||||
EAPI Eina_Bool eina_debug_timer_add(unsigned int timeout_ms, Eina_Debug_Timer_Cb cb, void *data);
|
EAPI Eina_Debug_Timer *eina_debug_timer_add(unsigned int timeout_ms, Eina_Debug_Timer_Cb cb, void *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Delete a timer
|
||||||
|
*
|
||||||
|
* @param timer the timer to delete
|
||||||
|
*
|
||||||
|
* If the timer reaches the end and has not be renewed, trying to delete it will lead to a crash, as
|
||||||
|
* it has already been deleted internally.
|
||||||
|
*/
|
||||||
|
EAPI void eina_debug_timer_del(Eina_Debug_Timer *timer);
|
||||||
|
|
||||||
EAPI int eina_debug_thread_id_get(void);
|
EAPI int eina_debug_thread_id_get(void);
|
||||||
|
|
||||||
|
|
|
@ -69,5 +69,8 @@ Eina_Bool _eina_debug_cpu_shutdown(void);
|
||||||
|
|
||||||
Eina_Bool _eina_debug_bt_init(void);
|
Eina_Bool _eina_debug_bt_init(void);
|
||||||
Eina_Bool _eina_debug_bt_shutdown(void);
|
Eina_Bool _eina_debug_bt_shutdown(void);
|
||||||
|
|
||||||
|
Eina_Bool _eina_debug_timer_init(void);
|
||||||
|
Eina_Bool _eina_debug_timer_shutdown(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/* EINA - EFL data type library
|
||||||
|
* Copyright (C) 2017 Carsten Haitzler
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library;
|
||||||
|
* if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# ifndef _GNU_SOURCE
|
||||||
|
# define _GNU_SOURCE 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "eina_debug.h"
|
||||||
|
#include "eina_debug_private.h"
|
||||||
|
|
||||||
|
static Eina_Spinlock _lock;
|
||||||
|
|
||||||
|
struct _Eina_Debug_Timer
|
||||||
|
{
|
||||||
|
unsigned int rel_time;
|
||||||
|
unsigned int timeout;
|
||||||
|
Eina_Debug_Timer_Cb cb;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Eina_List *_timers = NULL;
|
||||||
|
|
||||||
|
static Eina_Bool _thread_runs = EINA_FALSE;
|
||||||
|
static Eina_Bool _exit_required = EINA_FALSE;
|
||||||
|
static pthread_t _thread;
|
||||||
|
|
||||||
|
static int pipeToThread[2];
|
||||||
|
|
||||||
|
static void
|
||||||
|
_timer_append(Eina_Debug_Timer *t)
|
||||||
|
{
|
||||||
|
Eina_Debug_Timer *t2;
|
||||||
|
Eina_List *itr;
|
||||||
|
unsigned int prev_time = 0;
|
||||||
|
char c = '\0';
|
||||||
|
EINA_LIST_FOREACH(_timers, itr, t2)
|
||||||
|
{
|
||||||
|
if (t2->timeout > t->timeout) goto end;
|
||||||
|
prev_time = t2->timeout;
|
||||||
|
}
|
||||||
|
t2 = NULL;
|
||||||
|
end:
|
||||||
|
t->rel_time = t->timeout - prev_time;
|
||||||
|
if (!t2) _timers = eina_list_append(_timers, t);
|
||||||
|
else _timers = eina_list_prepend_relative(_timers, t, t2);
|
||||||
|
write(pipeToThread[1], &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
_monitor(void *_data EINA_UNUSED)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
#define MAX_EVENTS 4
|
||||||
|
struct epoll_event event;
|
||||||
|
struct epoll_event events[MAX_EVENTS];
|
||||||
|
int epfd = epoll_create(MAX_EVENTS), ret;
|
||||||
|
|
||||||
|
event.data.fd = pipeToThread[0];
|
||||||
|
event.events = EPOLLIN;
|
||||||
|
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, event.data.fd, &event);
|
||||||
|
if (ret) perror("epoll_ctl/add");
|
||||||
|
#ifdef EINA_HAVE_PTHREAD_SETNAME
|
||||||
|
# ifndef __linux__
|
||||||
|
pthread_set_name_np
|
||||||
|
# else
|
||||||
|
pthread_setname_np
|
||||||
|
# endif
|
||||||
|
(pthread_self(), "Edbg-tim");
|
||||||
|
#endif
|
||||||
|
for (;!_exit_required;)
|
||||||
|
{
|
||||||
|
int timeout = -1; //in milliseconds
|
||||||
|
eina_spinlock_take(&_lock);
|
||||||
|
if (_timers)
|
||||||
|
{
|
||||||
|
Eina_Debug_Timer *t = eina_list_data_get(_timers);
|
||||||
|
timeout = t->timeout;
|
||||||
|
}
|
||||||
|
eina_spinlock_release(&_lock);
|
||||||
|
|
||||||
|
ret = epoll_wait(epfd, events, MAX_EVENTS, timeout);
|
||||||
|
if (_exit_required) continue;
|
||||||
|
|
||||||
|
/* Some timer has been add/removed or we need to exit */
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
read(pipeToThread[0], &c, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Eina_List *itr, *itr2, *renew = NULL;
|
||||||
|
Eina_Debug_Timer *t;
|
||||||
|
eina_spinlock_take(&_lock);
|
||||||
|
EINA_LIST_FOREACH_SAFE(_timers, itr, itr2, t)
|
||||||
|
{
|
||||||
|
if (itr == _timers || t->rel_time == 0)
|
||||||
|
{
|
||||||
|
_timers = eina_list_remove(_timers, t);
|
||||||
|
if (t->cb(t->data)) renew = eina_list_append(renew, t);
|
||||||
|
else free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EINA_LIST_FREE(renew, t) _timer_append(t);
|
||||||
|
eina_spinlock_release(&_lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_thread_runs = EINA_FALSE;
|
||||||
|
close(pipeToThread[0]);
|
||||||
|
close(pipeToThread[1]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI Eina_Debug_Timer *
|
||||||
|
eina_debug_timer_add(unsigned int timeout_ms, Eina_Debug_Timer_Cb cb, void *data)
|
||||||
|
{
|
||||||
|
if (!cb || !timeout_ms) return NULL;
|
||||||
|
Eina_Debug_Timer *t = calloc(1, sizeof(*t));
|
||||||
|
t->cb = cb;
|
||||||
|
t->data = data;
|
||||||
|
t->timeout = timeout_ms;
|
||||||
|
eina_spinlock_take(&_lock);
|
||||||
|
_timer_append(t);
|
||||||
|
if (!_thread_runs)
|
||||||
|
{
|
||||||
|
int err = pthread_create(&_thread, NULL, _monitor, NULL);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
e_debug("EINA DEBUG ERROR: Can't create debug timer thread!");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
_thread_runs = EINA_TRUE;
|
||||||
|
}
|
||||||
|
eina_spinlock_release(&_lock);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
eina_debug_timer_del(Eina_Debug_Timer *t)
|
||||||
|
{
|
||||||
|
eina_spinlock_take(&_lock);
|
||||||
|
Eina_List *itr = eina_list_data_find_list(_timers, t);
|
||||||
|
if (itr)
|
||||||
|
{
|
||||||
|
_timers = eina_list_remove_list(_timers, itr);
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
eina_spinlock_release(&_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
_eina_debug_timer_init(void)
|
||||||
|
{
|
||||||
|
eina_spinlock_new(&_lock);
|
||||||
|
pipe(pipeToThread);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eina_Bool
|
||||||
|
_eina_debug_timer_shutdown(void)
|
||||||
|
{
|
||||||
|
char c = '\0';
|
||||||
|
_exit_required = EINA_TRUE;
|
||||||
|
write(pipeToThread[1], &c, 1);
|
||||||
|
eina_spinlock_free(&_lock);
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue