2015-05-13 23:41:11 -07:00
|
|
|
/* EINA - EFL data type library
|
|
|
|
* Copyright (C) 2015 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/>.
|
|
|
|
*/
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
# ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
# endif
|
|
|
|
|
|
|
|
#ifdef HAVE_DLADDR
|
2017-06-04 06:11:16 -07:00
|
|
|
# ifdef _WIN32
|
2019-05-16 10:48:59 -07:00
|
|
|
# include <evil_private.h> /* dladdr */
|
2017-06-04 06:11:16 -07:00
|
|
|
# else
|
|
|
|
# include <dlfcn.h>
|
|
|
|
# endif
|
2016-11-26 21:48:10 -08:00
|
|
|
#endif
|
2017-06-04 06:11:16 -07:00
|
|
|
|
|
|
|
#ifdef HAVE_UNWIND
|
2016-11-26 21:48:10 -08:00
|
|
|
#include <libunwind.h>
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2015-05-04 19:35:16 -07:00
|
|
|
#include "eina_debug.h"
|
2016-11-26 21:48:10 -08:00
|
|
|
#include "eina_debug_private.h"
|
2020-05-09 01:25:04 -07:00
|
|
|
#include "eina_util.h"
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2017-06-05 04:14:29 -07:00
|
|
|
# include <signal.h>
|
2018-06-21 17:29:21 -07:00
|
|
|
// realtime signals guarantee a minimum of 8, so SIGRTMIN + 7 would be valid
|
|
|
|
// at a minimum, so let's choose + 6 ... second last of the minimum set.
|
|
|
|
// SIGRTMAX of course is defined too... note the manual pages for sigation say
|
|
|
|
// that it calls rt_sigaction transparently for us so... no need for anything
|
|
|
|
// else special
|
|
|
|
# ifdef SIGRTMIN
|
|
|
|
# define SIG (SIGRTMIN + 6)
|
|
|
|
# else
|
|
|
|
// OSX seems to not support posix RT signals... too old a kernel. so be partly
|
|
|
|
// broken on OSX in that a HUP signal will maybe cause a crash... but compiling
|
|
|
|
// with -pg would have guaranteed always caused a crash before anyway.
|
|
|
|
// given OSX only supports "old-style" signals like:
|
2020-06-20 02:48:52 -07:00
|
|
|
//
|
2018-06-21 17:29:21 -07:00
|
|
|
// #define SIGHUP 1 /* hangup */
|
|
|
|
// #define SIGINT 2 /* interrupt */
|
|
|
|
// #define SIGQUIT 3 /* quit */
|
|
|
|
// #define SIGILL 4 /* illegal instruction (not reset when caught) */
|
|
|
|
// #define SIGTRAP 5 /* trace trap (not reset when caught) */
|
|
|
|
// #define SIGABRT 6 /* abort() */
|
|
|
|
// #if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
|
|
|
|
// # define SIGPOLL 7 /* pollable event ([XSR] generated, not supported) */
|
|
|
|
// #else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
|
|
|
// # define SIGIOT SIGABRT /* compatibility */
|
|
|
|
// # define SIGEMT 7 /* EMT instruction */
|
|
|
|
// #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
|
|
|
|
// #define SIGFPE 8 /* floating point exception */
|
|
|
|
// #define SIGKILL 9 /* kill (cannot be caught or ignored) */
|
|
|
|
// #define SIGBUS 10 /* bus error */
|
|
|
|
// #define SIGSEGV 11 /* segmentation violation */
|
|
|
|
// #define SIGSYS 12 /* bad argument to system call */
|
|
|
|
// #define SIGPIPE 13 /* write on a pipe with no one to read it */
|
|
|
|
// #define SIGALRM 14 /* alarm clock */
|
|
|
|
// #define SIGTERM 15 /* software termination signal from kill */
|
|
|
|
// #define SIGURG 16 /* urgent condition on IO channel */
|
|
|
|
// #define SIGSTOP 17 /* sendable stop signal not from tty */
|
|
|
|
// #define SIGTSTP 18 /* stop signal from tty */
|
|
|
|
// #define SIGCONT 19 /* continue a stopped process */
|
|
|
|
// #define SIGCHLD 20 /* to parent on child stop or exit */
|
|
|
|
// #define SIGTTIN 21 /* to readers pgrp upon background tty read */
|
|
|
|
// #define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */
|
|
|
|
// #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
|
|
|
|
// # define SIGIO 23 /* input/output possible signal */
|
|
|
|
// #endif
|
|
|
|
// #define SIGXCPU 24 /* exceeded CPU time limit */
|
|
|
|
// #define SIGXFSZ 25 /* exceeded file size limit */
|
|
|
|
// #define SIGVTALRM 26 /* virtual time alarm */
|
|
|
|
// #define SIGPROF 27 /* profiling time alarm */
|
|
|
|
// #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
|
|
|
|
// # define SIGWINCH 28 /* window size changes */
|
|
|
|
// # define SIGINFO 29 /* information request */
|
|
|
|
// #endif
|
|
|
|
// #define SIGUSR1 30 /* user defined signal 1 */
|
|
|
|
// #define SIGUSR2 31 /* user defined signal 2 */
|
2020-06-20 02:48:52 -07:00
|
|
|
//
|
2018-06-21 17:29:21 -07:00
|
|
|
// (excerpt from OSX's signal.h - found at:
|
|
|
|
// http://github.com/st3fan/osx-10.9/blob/master/xnu-2422.1.72/bsd/sys/signal.h
|
|
|
|
// pasting here due to how difficult it was to find a signal list for OSX)
|
|
|
|
# define SIG SIGHUP
|
|
|
|
# endif
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2017-05-30 04:14:59 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Semaphore _wait_for_bts_sem;
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-05-30 04:14:59 -07:00
|
|
|
// _bt_buf[0] is always for mainloop, 1 + is for extra threads
|
2016-11-26 21:48:10 -08:00
|
|
|
static void ***_bt_buf;
|
|
|
|
static int *_bt_buf_len;
|
|
|
|
static struct timespec *_bt_ts;
|
|
|
|
static int *_bt_cpu;
|
|
|
|
|
|
|
|
/* Used by trace timer */
|
|
|
|
static double _trace_t0 = 0.0;
|
2017-05-10 01:57:07 -07:00
|
|
|
static Eina_Debug_Timer *_timer = NULL;
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2018-06-19 11:04:45 -07:00
|
|
|
#ifndef _WIN32
|
|
|
|
static struct sigaction old_sigprof_action;
|
|
|
|
#endif
|
|
|
|
|
2015-05-04 19:35:16 -07:00
|
|
|
void
|
|
|
|
_eina_debug_dump_fhandle_bt(FILE *f, void **bt, int btlen)
|
|
|
|
{
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2015-05-04 19:35:16 -07:00
|
|
|
int i;
|
|
|
|
Dl_info info;
|
|
|
|
const char *file;
|
|
|
|
unsigned long long offset, base;
|
|
|
|
|
|
|
|
for (i = 0; i < btlen; i++)
|
|
|
|
{
|
|
|
|
file = NULL;
|
|
|
|
offset = base = 0;
|
2017-05-10 01:57:07 -07:00
|
|
|
// we have little choice but to hope/assume dladdr() doesn't alloc
|
2015-05-04 19:35:16 -07:00
|
|
|
// anything here
|
2017-12-19 07:33:18 -08:00
|
|
|
if ((dladdr(bt[i], &info)) && (info.dli_fname) && (info.dli_fname[0]))
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2017-02-11 07:29:01 -08:00
|
|
|
offset = (unsigned long long)(uintptr_t)bt[i];
|
|
|
|
base = (unsigned long long)(uintptr_t)info.dli_fbase;
|
2015-05-04 19:35:16 -07:00
|
|
|
file = _eina_debug_file_get(info.dli_fname);
|
|
|
|
}
|
|
|
|
// rely on normal libc buffering for file ops to avoid syscalls.
|
|
|
|
// may or may not be a good idea. good enough for now.
|
2022-04-28 08:28:51 -07:00
|
|
|
if (file) fprintf(f, "%s 0x%llx 0x%llx\n", file, offset, base);
|
|
|
|
else fprintf(f, "?? -\n");
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2017-06-04 06:11:16 -07:00
|
|
|
#else
|
|
|
|
(void)f;
|
|
|
|
(void)bt;
|
|
|
|
(void)btlen;
|
|
|
|
#endif
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
|
|
|
|
// a backtracer that uses libunwind to do the job
|
|
|
|
static inline int
|
|
|
|
_eina_debug_unwind_bt(void **bt, int max)
|
|
|
|
{
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifdef HAVE_UNWIND
|
2016-11-26 21:48:10 -08:00
|
|
|
unw_cursor_t cursor;
|
|
|
|
unw_context_t uc;
|
|
|
|
unw_word_t p;
|
|
|
|
int total;
|
|
|
|
|
|
|
|
// create a context for unwinding
|
|
|
|
unw_getcontext(&uc);
|
|
|
|
// begin our work
|
|
|
|
unw_init_local(&cursor, &uc);
|
|
|
|
// walk up each stack frame until there is no more, storing it
|
|
|
|
for (total = 0; (unw_step(&cursor) > 0) && (total < max); total++)
|
|
|
|
{
|
|
|
|
unw_get_reg(&cursor, UNW_REG_IP, &p);
|
|
|
|
bt[total] = (void *)p;
|
|
|
|
}
|
|
|
|
// return our total backtrace stack size
|
|
|
|
return total;
|
2017-06-04 06:11:16 -07:00
|
|
|
#else
|
|
|
|
(void)bt;
|
|
|
|
(void)max;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// a quick and dirty local time point getter func - not portable
|
|
|
|
static inline double
|
|
|
|
get_time(void)
|
|
|
|
{
|
|
|
|
#if defined(__clockid_t_defined)
|
|
|
|
struct timespec t;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
|
|
|
return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
|
|
|
|
#else
|
|
|
|
struct timeval timev;
|
|
|
|
gettimeofday(&timev, NULL);
|
|
|
|
return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000.0);
|
2015-05-04 19:35:16 -07:00
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2017-05-30 04:14:59 -07:00
|
|
|
static void
|
|
|
|
_signal_handler(int sig EINA_UNUSED,
|
|
|
|
siginfo_t *si EINA_UNUSED, void *foo EINA_UNUSED)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-05-30 04:14:59 -07:00
|
|
|
int i, slot = 0;
|
|
|
|
pthread_t self = pthread_self();
|
2017-07-17 00:02:25 -07:00
|
|
|
#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_SCHED_GETCPU) && defined(__clockid_t_defined)
|
2017-05-10 01:57:07 -07:00
|
|
|
clockid_t cid;
|
2017-07-17 00:02:25 -07:00
|
|
|
#endif
|
2017-05-30 04:14:59 -07:00
|
|
|
|
|
|
|
// find which slot in the array of threads we have so we store info
|
|
|
|
// in the correct slot for us
|
2017-05-31 15:14:37 -07:00
|
|
|
for (i = 0; i < _eina_debug_thread_active_num; i++)
|
2017-05-30 04:14:59 -07:00
|
|
|
{
|
2017-05-31 15:14:37 -07:00
|
|
|
if (self == _eina_debug_thread_active[i].thread)
|
2017-05-30 04:14:59 -07:00
|
|
|
{
|
2017-05-31 15:14:37 -07:00
|
|
|
slot = i;
|
|
|
|
goto found;
|
2017-05-30 04:14:59 -07:00
|
|
|
}
|
|
|
|
}
|
2017-05-31 15:14:37 -07:00
|
|
|
// we couldn't find out thread reference! help!
|
|
|
|
e_debug("EINA DEBUG ERROR: can't find thread slot!");
|
|
|
|
eina_semaphore_release(&_wait_for_bts_sem, 1);
|
|
|
|
return;
|
2017-05-30 04:14:59 -07:00
|
|
|
found:
|
2017-06-05 10:00:22 -07:00
|
|
|
/*
|
|
|
|
* Below is very non-portable code!
|
|
|
|
*
|
|
|
|
* - clock_gettime() is not implemented on macOS < 10.12
|
|
|
|
* - sched_getcpu() is not implemented on macOS
|
|
|
|
* - pthread_getcpuclockid() is not implemented on macOS
|
|
|
|
* - CLOCK_THREAD_CPUTIME_ID should be identical to pthread_getcpuclockid(),
|
|
|
|
* but it requires POSIX thingies to be defined.
|
|
|
|
*/
|
2017-07-17 00:02:25 -07:00
|
|
|
#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_SCHED_GETCPU) && defined(__clockid_t_defined)
|
2017-05-30 04:14:59 -07:00
|
|
|
// store thread info like what cpu core we are on now (not reliable
|
|
|
|
// but hey - better than nothing), the amount of cpu time total
|
|
|
|
// we have consumed (it's cumulative so subtracing deltas can give
|
|
|
|
// you an average amount of cpu time consumed between now and the
|
|
|
|
// previous time we looked) and also a full backtrace
|
2017-05-10 01:57:07 -07:00
|
|
|
_bt_cpu[slot] = sched_getcpu();
|
2017-06-05 10:00:22 -07:00
|
|
|
# ifdef HAVE_PTHREAD_GETCPUCLOCKID
|
|
|
|
/* Try pthread_getcpuclockid() first */
|
2017-05-30 04:14:59 -07:00
|
|
|
pthread_getcpuclockid(self, &cid);
|
2017-06-05 10:00:22 -07:00
|
|
|
# elif defined(_POSIX_THREAD_CPUTIME)
|
|
|
|
/* Fallback to POSIX clock id. */
|
|
|
|
cid = CLOCK_THREAD_CPUTIME_ID;
|
|
|
|
# else
|
|
|
|
/* Boom, we lost */
|
|
|
|
# error Cannot determine the clock id for clock_gettime()
|
|
|
|
# endif
|
2017-05-10 01:57:07 -07:00
|
|
|
clock_gettime(cid, &(_bt_ts[slot]));
|
|
|
|
_bt_buf_len[slot] = _eina_debug_unwind_bt(_bt_buf[slot], EINA_MAX_BT);
|
2017-06-05 10:00:22 -07:00
|
|
|
#endif /* HAVE_CLOCK_GETTIME && HAVE_SCHED_GETCPU */
|
2017-05-30 04:14:59 -07:00
|
|
|
// now wake up the monitor to let them know we are done collecting our
|
|
|
|
// backtrace info
|
|
|
|
eina_semaphore_release(&_wait_for_bts_sem, 1);
|
|
|
|
}
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2017-05-30 04:14:59 -07:00
|
|
|
|
|
|
|
static void
|
|
|
|
_signal_init(void)
|
|
|
|
{
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2017-05-30 04:14:59 -07:00
|
|
|
struct sigaction sa;
|
|
|
|
|
2018-06-19 11:04:45 -07:00
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
|
|
|
|
|
|
|
sa.sa_handler = SIG_DFL;
|
|
|
|
sa.sa_sigaction = NULL;
|
|
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sigaction(SIG, &sa, &old_sigprof_action);
|
|
|
|
|
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
2017-05-30 04:14:59 -07:00
|
|
|
// set up signal handler for our profiling signal - eevery thread should
|
|
|
|
// obey this (this is the case on linux - other OSs may vary)
|
|
|
|
sa.sa_sigaction = _signal_handler;
|
|
|
|
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
if (sigaction(SIG, &sa, NULL) != 0)
|
|
|
|
e_debug("EINA DEBUG ERROR: Can't set up sig %i handler!", SIG);
|
|
|
|
|
|
|
|
sa.sa_sigaction = NULL;
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
if (sigaction(SIGPIPE, &sa, 0) == -1) perror(0);
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2017-05-30 04:14:59 -07:00
|
|
|
}
|
|
|
|
|
2018-06-19 11:04:45 -07:00
|
|
|
static void
|
|
|
|
_signal_shutdown(void)
|
|
|
|
{
|
2018-06-21 14:44:34 -07:00
|
|
|
#ifndef _WIN32
|
2018-06-19 11:04:45 -07:00
|
|
|
sigaction(SIG, &old_sigprof_action, NULL);
|
2018-06-21 14:44:34 -07:00
|
|
|
#endif
|
2018-06-19 11:04:45 -07:00
|
|
|
}
|
|
|
|
|
2017-05-30 04:14:59 -07:00
|
|
|
static void
|
|
|
|
_collect_bt(pthread_t pth)
|
|
|
|
{
|
|
|
|
// this async signals the thread to switch to the deebug signal handler
|
|
|
|
// and collect a backtrace and other info from inside the thread
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2017-05-30 04:14:59 -07:00
|
|
|
pthread_kill(pth, SIG);
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2017-05-30 04:14:59 -07:00
|
|
|
_trace_cb(void *data EINA_UNUSED)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-05-10 01:57:07 -07:00
|
|
|
static int bts = 0;
|
|
|
|
int i;
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2020-05-09 01:25:04 -07:00
|
|
|
if (!EINA_DBL_NONZERO(_trace_t0)) _trace_t0 = get_time();
|
2017-05-10 01:57:07 -07:00
|
|
|
|
2017-05-30 04:14:59 -07:00
|
|
|
// take a lock on grabbing thread debug info like backtraces
|
|
|
|
eina_spinlock_take(&_eina_debug_thread_lock);
|
2017-07-23 03:09:11 -07:00
|
|
|
// too many threads (over 1 million) !!!!
|
|
|
|
if (_eina_debug_thread_active_num > (1024 * 1024)) goto err;
|
2016-11-26 21:48:10 -08:00
|
|
|
// reset our "stack" of memory se use to dump thread info into
|
|
|
|
_eina_debug_chunk_tmp_reset();
|
|
|
|
// get an array of pointers for the backtrace array for main + th
|
2017-05-30 04:14:59 -07:00
|
|
|
_bt_buf = _eina_debug_chunk_tmp_push
|
2017-05-31 15:14:37 -07:00
|
|
|
((_eina_debug_thread_active_num) * sizeof(void *));
|
2016-11-26 21:48:10 -08:00
|
|
|
if (!_bt_buf) goto err;
|
|
|
|
// get an array of pointers for the timespec array for mainloop + th
|
2017-05-30 04:14:59 -07:00
|
|
|
_bt_ts = _eina_debug_chunk_tmp_push
|
2017-05-31 15:14:37 -07:00
|
|
|
((_eina_debug_thread_active_num) * sizeof(struct timespec));
|
2016-11-26 21:48:10 -08:00
|
|
|
if (!_bt_ts) goto err;
|
|
|
|
// get an array of pointers for the cpuid array for mainloop + th
|
2017-05-30 04:14:59 -07:00
|
|
|
_bt_cpu = _eina_debug_chunk_tmp_push
|
2017-05-31 15:14:37 -07:00
|
|
|
((_eina_debug_thread_active_num) * sizeof(int));
|
2016-11-26 21:48:10 -08:00
|
|
|
if (!_bt_cpu) goto err;
|
|
|
|
// get an array of void ptrs for each thread we know about for bt
|
2017-05-30 04:14:59 -07:00
|
|
|
for (i = 0; i < _eina_debug_thread_active_num; i++)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-05-31 15:14:37 -07:00
|
|
|
_bt_buf[i] = _eina_debug_chunk_tmp_push(EINA_MAX_BT * sizeof(void *));
|
|
|
|
if (!_bt_buf[i]) goto err;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
// get an array of ints to stor the bt len for mainloop + threads
|
2017-05-30 04:14:59 -07:00
|
|
|
_bt_buf_len = _eina_debug_chunk_tmp_push
|
2017-05-31 15:14:37 -07:00
|
|
|
((_eina_debug_thread_active_num) * sizeof(int));
|
2016-11-26 21:48:10 -08:00
|
|
|
// now collect per thread
|
2017-05-30 04:14:59 -07:00
|
|
|
for (i = 0; i < _eina_debug_thread_active_num; i++)
|
|
|
|
_collect_bt(_eina_debug_thread_active[i].thread);
|
|
|
|
// we're done probing. now collec all the "i'm done" msgs on the
|
|
|
|
// semaphore for every thread + mainloop
|
2017-05-31 15:14:37 -07:00
|
|
|
for (i = 0; i < (_eina_debug_thread_active_num); i++)
|
2017-05-30 04:14:59 -07:00
|
|
|
eina_semaphore_lock(&_wait_for_bts_sem);
|
2017-05-10 01:57:07 -07:00
|
|
|
// we now have gotten all the data from all threads
|
2016-11-26 21:48:10 -08:00
|
|
|
// we can process it now as we see fit, so release thread lock
|
2017-05-10 01:57:07 -07:00
|
|
|
for (i = 0; i < _eina_debug_thread_active_num; i++)
|
|
|
|
{
|
|
|
|
_eina_debug_dump_fhandle_bt(stderr, _bt_buf[i], _bt_buf_len[i]);
|
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
err:
|
2017-05-30 04:14:59 -07:00
|
|
|
eina_spinlock_release(&_eina_debug_thread_lock);
|
2016-11-26 21:48:10 -08:00
|
|
|
//// XXX: some debug just to see how well we perform - will go
|
|
|
|
bts++;
|
|
|
|
if (bts >= 10000)
|
|
|
|
{
|
|
|
|
double t;
|
|
|
|
t = get_time();
|
|
|
|
e_debug("%1.5f bt's per sec", (double)bts / (t - _trace_t0));
|
|
|
|
_trace_t0 = t;
|
|
|
|
bts = 0;
|
|
|
|
}
|
2017-05-10 01:57:07 -07:00
|
|
|
return EINA_TRUE;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// profiling on with poll time gap as uint payload
|
2017-05-30 04:14:59 -07:00
|
|
|
static Eina_Bool
|
2016-11-26 21:48:10 -08:00
|
|
|
_prof_on_cb(Eina_Debug_Session *session, int cid EINA_UNUSED, void *buffer, int size)
|
|
|
|
{
|
|
|
|
unsigned int time;
|
2018-06-19 11:04:45 -07:00
|
|
|
|
|
|
|
_signal_init();
|
2016-11-26 21:48:10 -08:00
|
|
|
if (size >= 4)
|
|
|
|
{
|
|
|
|
memcpy(&time, buffer, 4);
|
|
|
|
_trace_t0 = 0.0;
|
2017-05-31 15:14:37 -07:00
|
|
|
if (_timer) eina_debug_timer_del(_timer);
|
2017-05-10 01:57:07 -07:00
|
|
|
_timer = eina_debug_timer_add(time, _trace_cb, session);
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2017-05-30 04:14:59 -07:00
|
|
|
return EINA_TRUE;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
2017-05-30 04:14:59 -07:00
|
|
|
static Eina_Bool
|
2016-11-26 21:48:10 -08:00
|
|
|
_prof_off_cb(Eina_Debug_Session *session EINA_UNUSED, int cid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED)
|
|
|
|
{
|
2017-05-10 01:57:07 -07:00
|
|
|
eina_debug_timer_del(_timer);
|
|
|
|
_timer = NULL;
|
2018-06-19 11:04:45 -07:00
|
|
|
_signal_shutdown();
|
2017-05-30 04:14:59 -07:00
|
|
|
return EINA_TRUE;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
2017-06-02 02:13:31 -07:00
|
|
|
EINA_DEBUG_OPCODES_ARRAY_DEFINE(_OPS,
|
|
|
|
{"Profiler/on", NULL, &_prof_on_cb},
|
|
|
|
{"Profiler/off", NULL, &_prof_off_cb},
|
|
|
|
{NULL, NULL, NULL}
|
|
|
|
);
|
2016-11-26 21:48:10 -08:00
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
_eina_debug_bt_init(void)
|
|
|
|
{
|
|
|
|
eina_semaphore_new(&_wait_for_bts_sem, 0);
|
2017-06-02 02:13:31 -07:00
|
|
|
eina_debug_opcodes_register(NULL, _OPS(), NULL, NULL);
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
_eina_debug_bt_shutdown(void)
|
|
|
|
{
|
|
|
|
eina_semaphore_free(&_wait_for_bts_sem);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
2017-06-04 06:11:16 -07:00
|
|
|
|