2004-05-22 00:05:20 +00:00
|
|
|
/**
|
|
|
|
* TelEngine.cpp
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2013-08-06 13:38:10 +00:00
|
|
|
* Copyright (C) 2004-2013 Null Team
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
2013-08-06 13:38:10 +00:00
|
|
|
* This software is distributed under multiple licenses;
|
|
|
|
* see the COPYING file in the main directory for licensing
|
|
|
|
* information for this specific distribution.
|
|
|
|
*
|
|
|
|
* This use of this software may be subject to additional restrictions.
|
|
|
|
* See the LEGAL file in the main directory for details.
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-08-06 13:38:10 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
2004-05-22 00:05:20 +00:00
|
|
|
*/
|
|
|
|
|
2005-04-08 10:55:22 +00:00
|
|
|
#include "yateclass.h"
|
2004-05-22 00:05:20 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
2006-12-22 00:57:35 +00:00
|
|
|
#include <time.h>
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2006-01-13 05:09:50 +00:00
|
|
|
|
|
|
|
#ifdef _WINDOWS
|
2007-01-02 15:58:37 +00:00
|
|
|
|
|
|
|
#ifndef HAVE_GMTIME_S
|
|
|
|
#include <errno.h>
|
|
|
|
|
2011-11-09 12:41:00 +00:00
|
|
|
static int _gmtime_s(struct tm* _tm, const time_t* time)
|
2007-01-02 15:58:37 +00:00
|
|
|
{
|
2009-05-05 12:25:31 +00:00
|
|
|
static TelEngine::Mutex m(false,"_gmtime_s");
|
2007-01-02 15:58:37 +00:00
|
|
|
struct tm* tmp;
|
|
|
|
if (!_tm)
|
|
|
|
return EINVAL;
|
|
|
|
_tm->tm_isdst = _tm->tm_yday = _tm->tm_wday = _tm->tm_year = _tm->tm_mon = _tm->tm_mday =
|
|
|
|
_tm->tm_hour = _tm->tm_min = _tm->tm_sec = -1;
|
|
|
|
if (!time)
|
|
|
|
return EINVAL;
|
|
|
|
m.lock();
|
|
|
|
tmp = gmtime(time);
|
|
|
|
if (!tmp) {
|
|
|
|
m.unlock();
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
*_tm = *tmp;
|
|
|
|
m.unlock();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-09 12:41:00 +00:00
|
|
|
static int _localtime_s(struct tm* _tm, const time_t* time)
|
|
|
|
{
|
|
|
|
static TelEngine::Mutex m(false,"_localtime_s");
|
|
|
|
struct tm* tmp;
|
|
|
|
if (!_tm)
|
|
|
|
return EINVAL;
|
|
|
|
_tm->tm_isdst = _tm->tm_yday = _tm->tm_wday = _tm->tm_year = _tm->tm_mon = _tm->tm_mday =
|
|
|
|
_tm->tm_hour = _tm->tm_min = _tm->tm_sec = -1;
|
|
|
|
if (!time)
|
|
|
|
return EINVAL;
|
|
|
|
m.lock();
|
|
|
|
tmp = localtime(time);
|
|
|
|
if (!tmp) {
|
|
|
|
m.unlock();
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
*_tm = *tmp;
|
|
|
|
m.unlock();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-02 15:58:37 +00:00
|
|
|
#endif
|
|
|
|
|
2011-06-29 11:19:02 +00:00
|
|
|
#else // !_WINDOWS
|
2006-05-24 10:04:22 +00:00
|
|
|
#include <sys/resource.h>
|
2006-01-13 05:09:50 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
namespace TelEngine {
|
|
|
|
|
2010-10-12 09:27:13 +00:00
|
|
|
#define DebugMin DebugFail
|
|
|
|
#define DebugVis DebugConf
|
2004-05-22 00:05:20 +00:00
|
|
|
#define DebugMax DebugAll
|
|
|
|
|
2006-02-08 16:53:08 +00:00
|
|
|
#define OUT_BUFFER_SIZE 8192
|
2005-01-06 15:33:35 +00:00
|
|
|
|
2010-11-01 14:54:53 +00:00
|
|
|
// RefObject mutex pool array size
|
|
|
|
#ifndef REFOBJECT_MUTEX_COUNT
|
|
|
|
#define REFOBJECT_MUTEX_COUNT 47
|
|
|
|
#endif
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
static int s_debug = DebugWarn;
|
|
|
|
static int s_indent = 0;
|
|
|
|
static bool s_debugging = true;
|
2004-10-14 16:36:24 +00:00
|
|
|
static bool s_abort = false;
|
2006-05-24 10:04:22 +00:00
|
|
|
static u_int64_t s_startTime = 0;
|
2006-12-22 00:57:35 +00:00
|
|
|
static u_int64_t s_timestamp = 0;
|
|
|
|
static Debugger::Formatting s_fmtstamp = Debugger::None;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2006-05-19 15:52:05 +00:00
|
|
|
static const char* const s_colors[11] = {
|
|
|
|
"\033[5;41;1;33m\033[K",// DebugFail - blinking yellow on red
|
2012-03-01 12:14:10 +00:00
|
|
|
"\033[44;1;37m\033[K", // DebugTest - white on blue
|
2006-05-19 15:52:05 +00:00
|
|
|
"\033[41;1;37m\033[K", // DebugGoOn - white on red
|
2010-09-29 15:28:27 +00:00
|
|
|
"\033[41;37m\033[K", // DebugConf - gray on red
|
2006-05-27 14:53:18 +00:00
|
|
|
"\033[40;31m\033[K", // DebugStub - red on black
|
2006-05-19 15:52:05 +00:00
|
|
|
"\033[40;1;31m\033[K", // DebugWarn - light red on black
|
|
|
|
"\033[40;1;33m\033[K", // DebugMild - yellow on black
|
|
|
|
"\033[40;1;37m\033[K", // DebugCall - white on black
|
|
|
|
"\033[40;1;32m\033[K", // DebugNote - light green on black
|
|
|
|
"\033[40;1;36m\033[K", // DebugInfo - light cyan on black
|
|
|
|
"\033[40;36m\033[K" // DebugAll - cyan on black
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char* const s_levels[11] = {
|
|
|
|
"FAIL",
|
2012-03-01 12:14:10 +00:00
|
|
|
"TEST",
|
2006-05-19 15:52:05 +00:00
|
|
|
"GOON",
|
2010-09-29 15:28:27 +00:00
|
|
|
"CONF",
|
2006-05-27 14:53:18 +00:00
|
|
|
"STUB",
|
2006-05-19 15:52:05 +00:00
|
|
|
"WARN",
|
|
|
|
"MILD",
|
|
|
|
"CALL",
|
|
|
|
"NOTE",
|
|
|
|
"INFO",
|
|
|
|
"ALL",
|
|
|
|
};
|
|
|
|
|
2013-07-05 12:40:59 +00:00
|
|
|
static const char* dbg_level(int& level)
|
2006-05-19 15:52:05 +00:00
|
|
|
{
|
|
|
|
if (level < DebugMin)
|
|
|
|
level = DebugMin;
|
|
|
|
if (level > DebugMax)
|
|
|
|
level = DebugMax;
|
|
|
|
return s_levels[level];
|
|
|
|
}
|
|
|
|
|
2005-06-20 20:51:17 +00:00
|
|
|
static void dbg_stderr_func(const char* buf, int level)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-05-24 15:09:19 +00:00
|
|
|
::write(2,buf,::strlen(buf));
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2006-05-19 15:52:05 +00:00
|
|
|
static void dbg_colorize_func(const char* buf, int level)
|
|
|
|
{
|
|
|
|
const char* col = debugColor(level);
|
|
|
|
::write(2,col,::strlen(col));
|
|
|
|
::write(2,buf,::strlen(buf));
|
|
|
|
col = debugColor(-2);
|
|
|
|
::write(2,col,::strlen(col));
|
|
|
|
}
|
|
|
|
|
2005-06-20 20:51:17 +00:00
|
|
|
static void (*s_output)(const char*,int) = dbg_stderr_func;
|
|
|
|
static void (*s_intout)(const char*,int) = 0;
|
2013-07-05 12:40:59 +00:00
|
|
|
static void (*s_alarms)(const char*,int,const char*,const char*) = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2009-05-05 12:25:31 +00:00
|
|
|
static Mutex out_mux(false,"DebugOutput");
|
|
|
|
static Mutex ind_mux(false,"DebugIndent");
|
2007-08-23 09:58:46 +00:00
|
|
|
static Thread* s_thr = 0;
|
|
|
|
|
2012-02-10 13:59:36 +00:00
|
|
|
bool CapturedEvent::s_capturing = false;
|
|
|
|
ObjList CapturedEvent::s_events;
|
|
|
|
|
2007-08-23 09:58:46 +00:00
|
|
|
static bool reentered()
|
|
|
|
{
|
|
|
|
if (!s_thr)
|
|
|
|
return false;
|
|
|
|
return (Thread::current() == s_thr);
|
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
|
2005-06-20 20:51:17 +00:00
|
|
|
static void common_output(int level,char* buf)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-06-20 20:51:17 +00:00
|
|
|
if (level < -1)
|
|
|
|
level = -1;
|
|
|
|
if (level > DebugMax)
|
|
|
|
level = DebugMax;
|
2004-05-22 00:05:20 +00:00
|
|
|
int n = ::strlen(buf);
|
|
|
|
if (n && (buf[n-1] == '\n'))
|
2013-07-05 12:40:59 +00:00
|
|
|
n--;
|
2004-05-22 00:05:20 +00:00
|
|
|
// serialize the output strings
|
|
|
|
out_mux.lock();
|
2007-08-23 09:58:46 +00:00
|
|
|
// TODO: detect reentrant calls from foreign threads and main thread
|
|
|
|
s_thr = Thread::current();
|
2012-02-10 13:59:36 +00:00
|
|
|
if (CapturedEvent::capturing()) {
|
|
|
|
buf[n] = '\0';
|
2012-06-12 23:50:59 +00:00
|
|
|
bool save = s_debugging;
|
|
|
|
s_debugging = false;
|
2012-02-10 13:59:36 +00:00
|
|
|
CapturedEvent::append(level,buf);
|
2012-06-12 23:50:59 +00:00
|
|
|
s_debugging = save;
|
2012-02-10 13:59:36 +00:00
|
|
|
}
|
|
|
|
buf[n] = '\n';
|
|
|
|
buf[n+1] = '\0';
|
2004-05-22 00:05:20 +00:00
|
|
|
if (s_output)
|
2005-06-20 20:51:17 +00:00
|
|
|
s_output(buf,level);
|
2004-05-22 00:05:20 +00:00
|
|
|
if (s_intout)
|
2005-06-20 20:51:17 +00:00
|
|
|
s_intout(buf,level);
|
2013-07-05 12:40:59 +00:00
|
|
|
buf[n] = '\0';
|
2007-08-23 09:58:46 +00:00
|
|
|
s_thr = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
out_mux.unlock();
|
|
|
|
}
|
|
|
|
|
2013-07-05 12:40:59 +00:00
|
|
|
static void dbg_output(int level,const char* prefix, const char* format, va_list ap,
|
|
|
|
const char* alarmComp = 0, const char* alarmInfo = 0)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2013-07-05 12:40:59 +00:00
|
|
|
bool out = (s_output || s_intout) && (prefix || format);
|
|
|
|
bool alarm = alarmComp && format && s_alarms;
|
|
|
|
if (!(out || alarm))
|
2004-05-22 00:05:20 +00:00
|
|
|
return;
|
2005-01-06 15:33:35 +00:00
|
|
|
char buf[OUT_BUFFER_SIZE];
|
2011-11-09 10:55:27 +00:00
|
|
|
unsigned int n = Debugger::formatTime(buf,s_fmtstamp);
|
2005-04-22 20:07:26 +00:00
|
|
|
unsigned int l = s_indent*2;
|
|
|
|
if (l >= sizeof(buf)-n)
|
|
|
|
l = sizeof(buf)-n-1;
|
|
|
|
::memset(buf+n,' ',l);
|
|
|
|
n += l;
|
2004-05-22 00:05:20 +00:00
|
|
|
buf[n] = 0;
|
2005-04-22 20:07:26 +00:00
|
|
|
l = sizeof(buf)-n-2;
|
2004-05-22 00:05:20 +00:00
|
|
|
if (prefix)
|
|
|
|
::strncpy(buf+n,prefix,l);
|
|
|
|
n = ::strlen(buf);
|
|
|
|
l = sizeof(buf)-n-2;
|
2013-07-05 12:40:59 +00:00
|
|
|
char* msg = buf+n;
|
2004-05-22 00:05:20 +00:00
|
|
|
if (format) {
|
2013-07-05 12:40:59 +00:00
|
|
|
::vsnprintf(msg,l,format,ap);
|
2008-09-16 15:25:26 +00:00
|
|
|
buf[OUT_BUFFER_SIZE - 2] = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
2013-07-05 12:40:59 +00:00
|
|
|
if (out)
|
|
|
|
common_output(level,buf);
|
|
|
|
if (alarm) {
|
|
|
|
out_mux.lock();
|
|
|
|
if (s_alarms)
|
|
|
|
s_alarms(msg,level,alarmComp,alarmInfo);
|
|
|
|
out_mux.unlock();
|
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
void Output(const char* format, ...)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-01-06 15:33:35 +00:00
|
|
|
char buf[OUT_BUFFER_SIZE];
|
2004-05-22 00:05:20 +00:00
|
|
|
if (!((s_output || s_intout) && format && *format))
|
|
|
|
return;
|
2007-08-23 09:58:46 +00:00
|
|
|
if (reentered())
|
|
|
|
return;
|
2004-05-22 00:05:20 +00:00
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
::vsnprintf(buf,sizeof(buf)-2,format,va);
|
|
|
|
va_end(va);
|
2005-06-20 20:51:17 +00:00
|
|
|
common_output(-1,buf);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-04-09 22:10:00 +00:00
|
|
|
void Debug(int level, const char* format, ...)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!s_debugging)
|
2005-04-09 22:10:00 +00:00
|
|
|
return;
|
2013-07-05 12:40:59 +00:00
|
|
|
if (level > s_debug || level < DebugMin)
|
2005-05-06 18:13:33 +00:00
|
|
|
return;
|
2007-08-23 09:58:46 +00:00
|
|
|
if (reentered())
|
|
|
|
return;
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!format)
|
|
|
|
format = "";
|
|
|
|
char buf[32];
|
2006-05-19 15:52:05 +00:00
|
|
|
::sprintf(buf,"<%s> ",dbg_level(level));
|
2005-05-06 18:13:33 +00:00
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
2005-06-20 20:51:17 +00:00
|
|
|
dbg_output(level,buf,format,va);
|
2005-05-06 18:13:33 +00:00
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-04-09 22:10:00 +00:00
|
|
|
void Debug(const char* facility, int level, const char* format, ...)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!s_debugging)
|
2005-04-09 22:10:00 +00:00
|
|
|
return;
|
2013-07-05 12:40:59 +00:00
|
|
|
if (level > s_debug || level < DebugMin)
|
2005-05-06 18:13:33 +00:00
|
|
|
return;
|
2007-08-23 09:58:46 +00:00
|
|
|
if (reentered())
|
|
|
|
return;
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!format)
|
|
|
|
format = "";
|
|
|
|
char buf[64];
|
2006-05-19 15:52:05 +00:00
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
|
2005-05-06 18:13:33 +00:00
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
2005-06-20 20:51:17 +00:00
|
|
|
dbg_output(level,buf,format,va);
|
2005-05-06 18:13:33 +00:00
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-04-09 22:10:00 +00:00
|
|
|
void Debug(const DebugEnabler* local, int level, const char* format, ...)
|
2005-03-20 03:11:53 +00:00
|
|
|
{
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!s_debugging)
|
2005-04-09 22:10:00 +00:00
|
|
|
return;
|
2005-06-20 20:51:17 +00:00
|
|
|
const char* facility = 0;
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!local) {
|
2013-07-05 12:40:59 +00:00
|
|
|
if (level > s_debug || level < DebugMin)
|
2005-05-06 18:13:33 +00:00
|
|
|
return;
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
2005-05-06 18:13:33 +00:00
|
|
|
else {
|
|
|
|
if (!local->debugAt(level))
|
|
|
|
return;
|
2005-06-20 20:51:17 +00:00
|
|
|
facility = local->debugName();
|
2005-05-06 18:13:33 +00:00
|
|
|
}
|
2007-08-23 09:58:46 +00:00
|
|
|
if (reentered())
|
|
|
|
return;
|
2005-05-06 18:13:33 +00:00
|
|
|
if (!format)
|
|
|
|
format = "";
|
2005-06-20 20:51:17 +00:00
|
|
|
char buf[64];
|
|
|
|
if (facility)
|
2006-05-19 15:52:05 +00:00
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
|
2005-06-20 20:51:17 +00:00
|
|
|
else
|
2006-05-19 15:52:05 +00:00
|
|
|
::sprintf(buf,"<%s> ",dbg_level(level));
|
2005-05-06 18:13:33 +00:00
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
2005-06-20 20:51:17 +00:00
|
|
|
dbg_output(level,buf,format,va);
|
2005-05-06 18:13:33 +00:00
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
2005-03-20 03:11:53 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 12:40:59 +00:00
|
|
|
void Alarm(const char* component, int level, const char* format, ...)
|
|
|
|
{
|
|
|
|
if (!format || level < DebugMin || reentered())
|
|
|
|
return;
|
|
|
|
if (TelEngine::null(component))
|
|
|
|
component = "unknown";
|
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
|
|
|
dbg_output(level,buf,format,va,component);
|
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Alarm(const DebugEnabler* component, int level, const char* format, ...)
|
|
|
|
{
|
|
|
|
if (!format || level < DebugMin || reentered())
|
|
|
|
return;
|
|
|
|
const char* name = (component && !TelEngine::null(component->debugName()))
|
|
|
|
? component->debugName() : "unknown";
|
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
|
|
|
dbg_output(level,buf,format,va,name);
|
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Alarm(const char* component, const char* info, int level, const char* format, ...)
|
|
|
|
{
|
|
|
|
if (!format || level < DebugMin || reentered())
|
|
|
|
return;
|
|
|
|
if (TelEngine::null(component))
|
|
|
|
component = "unknown";
|
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
|
|
|
dbg_output(level,buf,format,va,component,info);
|
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Alarm(const DebugEnabler* component, const char* info, int level, const char* format, ...)
|
|
|
|
{
|
|
|
|
if (!format || level < DebugMin || reentered())
|
|
|
|
return;
|
|
|
|
const char* name = (component && !TelEngine::null(component->debugName()))
|
|
|
|
? component->debugName() : "unknown";
|
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
|
|
|
ind_mux.lock();
|
|
|
|
dbg_output(level,buf,format,va,name,info);
|
|
|
|
ind_mux.unlock();
|
|
|
|
va_end(va);
|
|
|
|
if (s_abort && (level == DebugFail))
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2004-10-14 16:36:24 +00:00
|
|
|
void abortOnBug()
|
|
|
|
{
|
|
|
|
if (s_abort)
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool abortOnBug(bool doAbort)
|
|
|
|
{
|
|
|
|
bool tmp = s_abort;
|
|
|
|
s_abort = doAbort;
|
|
|
|
return tmp;
|
2011-11-09 10:55:27 +00:00
|
|
|
}
|
2004-10-14 16:36:24 +00:00
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
int debugLevel()
|
|
|
|
{
|
|
|
|
return s_debug;
|
|
|
|
}
|
|
|
|
|
|
|
|
int debugLevel(int level)
|
|
|
|
{
|
2010-10-12 09:27:13 +00:00
|
|
|
if (level < DebugVis)
|
|
|
|
level = DebugVis;
|
2004-05-22 00:05:20 +00:00
|
|
|
if (level > DebugMax)
|
|
|
|
level = DebugMax;
|
|
|
|
return (s_debug = level);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool debugAt(int level)
|
|
|
|
{
|
|
|
|
return (s_debugging && (level <= s_debug));
|
|
|
|
}
|
|
|
|
|
2006-05-19 15:52:05 +00:00
|
|
|
const char* debugColor(int level)
|
|
|
|
{
|
|
|
|
if (level == -2)
|
|
|
|
return "\033[0m\033[K"; // reset to defaults
|
|
|
|
if ((level < DebugMin) || (level > DebugMax))
|
|
|
|
return "\033[0;40;37m\033[K"; // light gray on black
|
|
|
|
return s_colors[level];
|
|
|
|
}
|
|
|
|
|
2013-07-05 12:40:59 +00:00
|
|
|
const char* debugLevelName(int level)
|
|
|
|
{
|
|
|
|
return (level < DebugMin) ? "" : dbg_level(level);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
int DebugEnabler::debugLevel(int level)
|
|
|
|
{
|
2010-10-12 09:27:13 +00:00
|
|
|
if (level < DebugVis)
|
|
|
|
level = DebugVis;
|
2005-03-20 03:11:53 +00:00
|
|
|
if (level > DebugMax)
|
|
|
|
level = DebugMax;
|
2005-03-28 22:27:26 +00:00
|
|
|
m_chain = 0;
|
2005-03-20 03:11:53 +00:00
|
|
|
return (m_level = level);
|
|
|
|
}
|
|
|
|
|
2005-03-28 22:27:26 +00:00
|
|
|
bool DebugEnabler::debugAt(int level) const
|
|
|
|
{
|
|
|
|
if (m_chain)
|
|
|
|
return m_chain->debugAt(level);
|
|
|
|
return (m_enabled && (level <= m_level));
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
void DebugEnabler::debugCopy(const DebugEnabler* original)
|
|
|
|
{
|
|
|
|
if (original) {
|
|
|
|
m_level = original->debugLevel();
|
|
|
|
m_enabled = original->debugEnabled();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_level = TelEngine::debugLevel();
|
|
|
|
m_enabled = debugEnabled();
|
|
|
|
}
|
|
|
|
m_chain = 0;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
Debugger::Debugger(const char* name, const char* format, ...)
|
2012-05-15 11:29:05 +00:00
|
|
|
: m_name(name), m_level(DebugAll)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2007-08-23 09:58:46 +00:00
|
|
|
if (s_debugging && m_name && (s_debug >= DebugAll) && !reentered()) {
|
2004-05-22 00:05:20 +00:00
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),">>> %s",m_name);
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.lock();
|
2012-05-15 11:29:05 +00:00
|
|
|
dbg_output(m_level,buf,format,va);
|
2004-05-22 00:05:20 +00:00
|
|
|
va_end(va);
|
|
|
|
s_indent++;
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.unlock();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
m_name = 0;
|
|
|
|
}
|
|
|
|
|
2005-03-20 03:11:53 +00:00
|
|
|
Debugger::Debugger(int level, const char* name, const char* format, ...)
|
2012-05-15 11:29:05 +00:00
|
|
|
: m_name(name), m_level(level)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2007-08-23 09:58:46 +00:00
|
|
|
if (s_debugging && m_name && (s_debug >= level) && !reentered()) {
|
2004-05-22 00:05:20 +00:00
|
|
|
char buf[64];
|
|
|
|
::snprintf(buf,sizeof(buf),">>> %s",m_name);
|
|
|
|
va_list va;
|
|
|
|
va_start(va,format);
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.lock();
|
2012-05-15 11:29:05 +00:00
|
|
|
dbg_output(m_level,buf,format,va);
|
2004-05-22 00:05:20 +00:00
|
|
|
va_end(va);
|
|
|
|
s_indent++;
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.unlock();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
m_name = 0;
|
|
|
|
}
|
|
|
|
|
2012-05-15 11:29:05 +00:00
|
|
|
static void dbg_dist_helper(int level, const char* buf, const char* fmt, ...)
|
2005-01-16 02:32:40 +00:00
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
va_start(va,fmt);
|
2012-05-15 11:29:05 +00:00
|
|
|
dbg_output(level,buf,fmt,va);
|
2005-01-16 02:32:40 +00:00
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
2013-02-08 15:23:06 +00:00
|
|
|
bool controlReturn(NamedList* params, bool ret, const char* retVal)
|
|
|
|
{
|
|
|
|
if (retVal && params)
|
|
|
|
params->setParam("retVal",retVal);
|
2013-05-10 14:50:36 +00:00
|
|
|
if (!params || !params->getObject(YATOM("Message")))
|
2013-02-08 15:23:06 +00:00
|
|
|
return ret;
|
2013-05-10 14:50:36 +00:00
|
|
|
const String* module = params->getParam("module");
|
|
|
|
if (TelEngine::null(module) || YSTRING("rmanager") != *module)
|
2013-02-08 15:23:06 +00:00
|
|
|
return ret;
|
2013-05-10 14:50:36 +00:00
|
|
|
const String s_opStat("operation-status");
|
|
|
|
if (!params->getParam(s_opStat))
|
|
|
|
params->addParam(s_opStat,String::boolText(ret));
|
|
|
|
return ret;
|
2013-02-08 15:23:06 +00:00
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
Debugger::~Debugger()
|
|
|
|
{
|
|
|
|
if (m_name) {
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.lock();
|
2004-05-22 00:05:20 +00:00
|
|
|
s_indent--;
|
2007-08-23 09:58:46 +00:00
|
|
|
if (s_debugging)
|
2012-05-15 11:29:05 +00:00
|
|
|
dbg_dist_helper(m_level,"<<< ","%s",m_name);
|
2004-10-24 21:35:54 +00:00
|
|
|
ind_mux.unlock();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-20 20:51:17 +00:00
|
|
|
void Debugger::setOutput(void (*outFunc)(const char*,int))
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2004-10-21 23:11:46 +00:00
|
|
|
out_mux.lock();
|
2004-05-22 00:05:20 +00:00
|
|
|
s_output = outFunc ? outFunc : dbg_stderr_func;
|
2004-10-21 23:11:46 +00:00
|
|
|
out_mux.unlock();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2005-06-20 20:51:17 +00:00
|
|
|
void Debugger::setIntOut(void (*outFunc)(const char*,int))
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2004-10-21 23:11:46 +00:00
|
|
|
out_mux.lock();
|
2004-05-22 00:05:20 +00:00
|
|
|
s_intout = outFunc;
|
2004-10-21 23:11:46 +00:00
|
|
|
out_mux.unlock();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 12:40:59 +00:00
|
|
|
void Debugger::setAlarmHook(void (*alarmFunc)(const char*,int,const char*,const char*))
|
|
|
|
{
|
|
|
|
out_mux.lock();
|
|
|
|
s_alarms = alarmFunc;
|
|
|
|
out_mux.unlock();
|
|
|
|
}
|
|
|
|
|
2006-05-19 15:52:05 +00:00
|
|
|
void Debugger::enableOutput(bool enable, bool colorize)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
s_debugging = enable;
|
2006-05-19 15:52:05 +00:00
|
|
|
if (colorize)
|
|
|
|
setOutput(dbg_colorize_func);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2011-11-09 10:55:27 +00:00
|
|
|
Debugger::Formatting Debugger::getFormatting()
|
|
|
|
{
|
|
|
|
return s_fmtstamp;
|
|
|
|
}
|
|
|
|
|
2006-12-22 00:57:35 +00:00
|
|
|
void Debugger::setFormatting(Formatting format)
|
|
|
|
{
|
|
|
|
// start stamp will be rounded to full second
|
|
|
|
s_timestamp = (Time::now() / 1000000) * 1000000;
|
|
|
|
s_fmtstamp = format;
|
|
|
|
}
|
|
|
|
|
2011-11-09 10:55:27 +00:00
|
|
|
unsigned int Debugger::formatTime(char* buf, Formatting format)
|
|
|
|
{
|
|
|
|
if (!buf)
|
|
|
|
return 0;
|
|
|
|
if (None != format) {
|
|
|
|
u_int64_t t = Time::now();
|
|
|
|
if (Relative == format)
|
|
|
|
t -= s_timestamp;
|
|
|
|
unsigned int s = (unsigned int)(t / 1000000);
|
|
|
|
unsigned int u = (unsigned int)(t % 1000000);
|
2013-04-17 15:26:03 +00:00
|
|
|
switch (format) {
|
|
|
|
case Textual:
|
|
|
|
case TextLocal:
|
|
|
|
case TextSep:
|
|
|
|
case TextLSep:
|
|
|
|
{
|
|
|
|
time_t sec = (time_t)s;
|
|
|
|
struct tm tmp;
|
|
|
|
if (TextLocal == format || TextLSep == format)
|
2011-11-09 12:41:00 +00:00
|
|
|
#ifdef _WINDOWS
|
2013-04-17 15:26:03 +00:00
|
|
|
_localtime_s(&tmp,&sec);
|
2011-11-09 12:41:00 +00:00
|
|
|
#else
|
2013-04-17 15:26:03 +00:00
|
|
|
localtime_r(&sec,&tmp);
|
2011-11-09 12:41:00 +00:00
|
|
|
#endif
|
2013-04-17 15:26:03 +00:00
|
|
|
else
|
2011-11-09 10:55:27 +00:00
|
|
|
#ifdef _WINDOWS
|
2013-04-17 15:26:03 +00:00
|
|
|
_gmtime_s(&tmp,&sec);
|
2011-11-09 10:55:27 +00:00
|
|
|
#else
|
2013-04-17 15:26:03 +00:00
|
|
|
gmtime_r(&sec,&tmp);
|
2011-11-09 10:55:27 +00:00
|
|
|
#endif
|
2013-04-17 15:26:03 +00:00
|
|
|
if (Textual == format || TextLocal == format)
|
|
|
|
::sprintf(buf,"%04d%02d%02d%02d%02d%02d.%06u ",
|
|
|
|
tmp.tm_year+1900,tmp.tm_mon+1,tmp.tm_mday,
|
|
|
|
tmp.tm_hour,tmp.tm_min,tmp.tm_sec,u);
|
|
|
|
else
|
|
|
|
::sprintf(buf,"%04d-%02d-%02d_%02d:%02d:%02d.%06u ",
|
|
|
|
tmp.tm_year+1900,tmp.tm_mon+1,tmp.tm_mday,
|
|
|
|
tmp.tm_hour,tmp.tm_min,tmp.tm_sec,u);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
::sprintf(buf,"%07u.%06u ",s,u);
|
2011-11-09 10:55:27 +00:00
|
|
|
}
|
|
|
|
return ::strlen(buf);
|
|
|
|
}
|
|
|
|
buf[0] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-22 00:57:35 +00:00
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
u_int64_t Time::now()
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-04-02 00:49:38 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
FILETIME ft;
|
|
|
|
GetSystemTimeAsFileTime(&ft);
|
|
|
|
// Convert from FILETIME (100 nsec units since January 1, 1601)
|
|
|
|
// to extended time_t (1 usec units since January 1, 1970)
|
|
|
|
u_int64_t rval = ((ULARGE_INTEGER*)&ft)->QuadPart / 10;
|
|
|
|
rval -= 11644473600000000;
|
|
|
|
return rval;
|
|
|
|
#else
|
2004-05-22 00:05:20 +00:00
|
|
|
struct timeval tv;
|
|
|
|
return ::gettimeofday(&tv,0) ? 0 : fromTimeval(&tv);
|
2005-05-10 14:54:04 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int64_t Time::msecNow()
|
|
|
|
{
|
|
|
|
return (u_int64_t)(now() / 1000);
|
|
|
|
}
|
2005-04-02 00:49:38 +00:00
|
|
|
|
2005-05-10 14:54:04 +00:00
|
|
|
u_int32_t Time::secNow()
|
|
|
|
{
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
return (u_int32_t)(now() / 1000000);
|
|
|
|
#else
|
|
|
|
struct timeval tv;
|
|
|
|
return ::gettimeofday(&tv,0) ? 0 : tv.tv_sec;
|
2005-04-02 00:49:38 +00:00
|
|
|
#endif
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2006-05-24 10:04:22 +00:00
|
|
|
u_int64_t Time::fromTimeval(const struct timeval* tv)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2005-04-02 00:49:38 +00:00
|
|
|
u_int64_t rval = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
if (tv) {
|
|
|
|
// Please keep it this way or the compiler may b0rk
|
|
|
|
rval = tv->tv_sec;
|
|
|
|
rval *= 1000000;
|
|
|
|
rval += tv->tv_usec;
|
|
|
|
}
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2005-04-02 00:49:38 +00:00
|
|
|
void Time::toTimeval(struct timeval* tv, u_int64_t usec)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
if (tv) {
|
2005-04-02 00:49:38 +00:00
|
|
|
tv->tv_usec = (long)(usec % 1000000);
|
|
|
|
tv->tv_sec = (long)(usec / 1000000);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-09 14:30:05 +00:00
|
|
|
// Build EPOCH time from date/time components
|
|
|
|
unsigned int Time::toEpoch(int year, unsigned int month, unsigned int day,
|
|
|
|
unsigned int hour, unsigned int minute, unsigned int sec, int offset)
|
|
|
|
{
|
2011-04-27 19:42:37 +00:00
|
|
|
DDebug(DebugAll,"Time::toEpoch(%d,%u,%u,%u,%u,%u,%d)",
|
2009-01-09 14:30:05 +00:00
|
|
|
year,month,day,hour,minute,sec,offset);
|
|
|
|
if (year < 1970)
|
|
|
|
return (unsigned int)-1;
|
|
|
|
if (month < 1 || month > 12 || !day)
|
|
|
|
return (unsigned int)-1;
|
|
|
|
if (hour == 24 && (minute || sec))
|
|
|
|
return (unsigned int)-1;
|
|
|
|
else if (hour > 23 || minute > 59 || sec > 59)
|
|
|
|
return (unsigned int)-1;
|
|
|
|
// Check if month and day are correct in the given year
|
|
|
|
month--;
|
|
|
|
unsigned int m[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
|
|
|
if (isLeap(year))
|
|
|
|
m[1] = 29;
|
|
|
|
if (day > m[month])
|
|
|
|
return (unsigned int)-1;
|
|
|
|
// Count the number of days since EPOCH
|
|
|
|
int64_t days = (year - 1970) * 365;
|
|
|
|
// Add a day for each leap year from 1970 to 'year' (not including)
|
2009-01-12 09:38:53 +00:00
|
|
|
for (int y = 1972; y < year; y += 4) {
|
2009-01-09 14:30:05 +00:00
|
|
|
if (isLeap(y))
|
|
|
|
days++;
|
2009-01-12 09:38:53 +00:00
|
|
|
}
|
2009-01-09 14:30:05 +00:00
|
|
|
// Add days ellapsed in given year
|
|
|
|
for (unsigned int i = 0; i < month; i++)
|
|
|
|
days += m[i];
|
|
|
|
days += day - 1;
|
|
|
|
int64_t ret = (days * 24 + hour) * 3600 + minute * 60 + sec + offset;
|
|
|
|
|
|
|
|
// Check for incorrect time or overflow
|
|
|
|
if (ret < 0 || ret > (unsigned int)-1)
|
|
|
|
return (unsigned int)-1;
|
|
|
|
return (unsigned int)ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Split a given EPOCH time into its date/time components
|
|
|
|
bool Time::toDateTime(unsigned int epochTimeSec, int& year, unsigned int& month,
|
2013-04-17 15:38:44 +00:00
|
|
|
unsigned int& day, unsigned int& hour, unsigned int& minute, unsigned int& sec,
|
|
|
|
unsigned int* wDay)
|
2009-01-09 14:30:05 +00:00
|
|
|
{
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
FILETIME ft;
|
|
|
|
SYSTEMTIME st;
|
|
|
|
// 11644473600: the number of seconds from 1601, January 1st (FILETIME)
|
|
|
|
// to EPOCH (1970, January 1st)
|
|
|
|
// Remember: FILETIME keeps the number of 100 nsec units
|
|
|
|
u_int64_t time = (11644473600 + epochTimeSec) * 10000000;
|
|
|
|
ft.dwLowDateTime = (DWORD)time;
|
|
|
|
ft.dwHighDateTime = (DWORD)(time >> 32);
|
|
|
|
if (!FileTimeToSystemTime(&ft,&st))
|
|
|
|
return false;
|
|
|
|
year = st.wYear;
|
|
|
|
month = st.wMonth;
|
|
|
|
day = st.wDay;
|
|
|
|
hour = st.wHour;
|
|
|
|
minute = st.wMinute;
|
|
|
|
sec = st.wSecond;
|
2013-04-17 15:38:44 +00:00
|
|
|
if (wDay)
|
|
|
|
*wDay = st.wDayOfWeek;
|
2009-01-09 14:30:05 +00:00
|
|
|
#else
|
|
|
|
struct tm t;
|
|
|
|
time_t time = (time_t)epochTimeSec;
|
|
|
|
if (!gmtime_r(&time,&t))
|
|
|
|
return false;
|
|
|
|
year = 1900 + t.tm_year;
|
|
|
|
month = t.tm_mon + 1;
|
|
|
|
day = t.tm_mday;
|
|
|
|
hour = t.tm_hour;
|
|
|
|
minute = t.tm_min;
|
|
|
|
sec = t.tm_sec;
|
2013-04-17 15:38:44 +00:00
|
|
|
if (wDay)
|
|
|
|
*wDay = t.tm_wday;
|
2009-01-09 14:30:05 +00:00
|
|
|
#endif
|
2011-04-27 19:42:37 +00:00
|
|
|
DDebug(DebugAll,"Time::toDateTime(%u,%d,%u,%u,%u,%u,%u)",
|
2009-01-09 14:30:05 +00:00
|
|
|
epochTimeSec,year,month,day,hour,minute,sec);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-17 15:38:44 +00:00
|
|
|
int Time::timeZone()
|
|
|
|
{
|
|
|
|
#ifdef _WINDOWS
|
2013-04-18 12:11:38 +00:00
|
|
|
struct tm t;
|
|
|
|
time_t time = (time_t)secNow();
|
|
|
|
_localtime_s(&t,&time);
|
|
|
|
if (t.tm_isdst)
|
|
|
|
return -(_timezone + _dstbias);
|
|
|
|
return -_timezone;
|
2013-04-17 15:38:44 +00:00
|
|
|
#else
|
|
|
|
#ifdef HAVE_GMTOFF
|
|
|
|
struct tm t;
|
|
|
|
time_t time = (time_t)secNow();
|
|
|
|
if (localtime_r(&time,&t))
|
|
|
|
return t.tm_gmtoff;
|
|
|
|
#endif
|
|
|
|
return -timezone;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-29 11:19:02 +00:00
|
|
|
static Random s_random;
|
|
|
|
static Mutex s_randomMutex(false,"Random");
|
|
|
|
|
|
|
|
u_int32_t Random::next()
|
|
|
|
{
|
|
|
|
return (m_random = (m_random + 1) * 0x8088405);
|
|
|
|
}
|
|
|
|
|
|
|
|
long int Random::random()
|
|
|
|
{
|
|
|
|
s_randomMutex.lock();
|
|
|
|
long int ret = s_random.next() % RAND_MAX;
|
|
|
|
s_randomMutex.unlock();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Random::srandom(unsigned int seed)
|
|
|
|
{
|
|
|
|
s_randomMutex.lock();
|
|
|
|
s_random.set(seed % RAND_MAX);
|
|
|
|
s_randomMutex.unlock();
|
|
|
|
}
|
|
|
|
|
2006-01-12 05:32:06 +00:00
|
|
|
|
|
|
|
bool GenObject::alive() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GenObject::destruct()
|
|
|
|
{
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
2011-11-04 18:24:51 +00:00
|
|
|
|
2011-11-07 17:10:32 +00:00
|
|
|
#ifndef ATOMIC_OPS
|
2010-11-01 14:54:53 +00:00
|
|
|
static MutexPool s_refMutex(REFOBJECT_MUTEX_COUNT,false,"RefObject");
|
2011-11-07 17:10:32 +00:00
|
|
|
#endif
|
2007-05-15 11:16:41 +00:00
|
|
|
|
2010-11-01 14:54:53 +00:00
|
|
|
RefObject::RefObject()
|
2011-08-23 10:03:41 +00:00
|
|
|
: m_refcount(1), m_mutex(0)
|
2010-11-01 14:54:53 +00:00
|
|
|
{
|
2011-11-07 17:10:32 +00:00
|
|
|
#ifndef ATOMIC_OPS
|
2011-08-23 10:03:41 +00:00
|
|
|
m_mutex = s_refMutex.mutex(this);
|
2011-11-07 17:10:32 +00:00
|
|
|
#endif
|
2010-11-01 14:54:53 +00:00
|
|
|
}
|
2004-12-20 04:11:29 +00:00
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
RefObject::~RefObject()
|
|
|
|
{
|
2004-12-20 04:11:29 +00:00
|
|
|
if (m_refcount > 0)
|
2005-03-28 22:27:26 +00:00
|
|
|
Debug(DebugFail,"RefObject [%p] destroyed with count=%d",this,m_refcount);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2012-02-20 14:17:59 +00:00
|
|
|
void* RefObject::getObject(const String& name) const
|
|
|
|
{
|
2013-04-12 13:19:14 +00:00
|
|
|
if (name == YATOM("RefObject"))
|
2012-02-20 14:17:59 +00:00
|
|
|
return (void*)this;
|
|
|
|
return GenObject::getObject(name);
|
|
|
|
}
|
2006-01-12 05:32:06 +00:00
|
|
|
bool RefObject::alive() const
|
|
|
|
{
|
|
|
|
return m_refcount > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RefObject::destruct()
|
|
|
|
{
|
|
|
|
deref();
|
|
|
|
}
|
|
|
|
|
2011-11-04 18:24:51 +00:00
|
|
|
bool RefObject::ref()
|
2004-12-20 04:11:29 +00:00
|
|
|
{
|
2011-11-07 17:10:32 +00:00
|
|
|
#ifdef ATOMIC_OPS
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
if (InterlockedIncrement((LONG*)&m_refcount) > 1)
|
|
|
|
return true;
|
|
|
|
InterlockedDecrement((LONG*)&m_refcount);
|
|
|
|
#else
|
|
|
|
if (__sync_add_and_fetch(&m_refcount,1) > 1)
|
|
|
|
return true;
|
|
|
|
__sync_sub_and_fetch(&m_refcount,1);
|
|
|
|
#endif
|
|
|
|
#else
|
2011-11-04 18:24:51 +00:00
|
|
|
Lock lock(m_mutex);
|
2007-06-07 17:53:01 +00:00
|
|
|
if (m_refcount > 0) {
|
2006-01-12 05:32:06 +00:00
|
|
|
++m_refcount;
|
2007-06-07 17:53:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-11-07 17:10:32 +00:00
|
|
|
#endif
|
2007-06-07 17:53:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-12-20 04:11:29 +00:00
|
|
|
bool RefObject::deref()
|
|
|
|
{
|
2011-11-07 17:10:32 +00:00
|
|
|
#ifdef ATOMIC_OPS
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
int i = InterlockedDecrement((LONG*)&m_refcount) + 1;
|
|
|
|
if (i <= 0)
|
|
|
|
InterlockedIncrement((LONG*)&m_refcount);
|
|
|
|
#else
|
|
|
|
int i = __sync_fetch_and_sub(&m_refcount,1);
|
|
|
|
if (i <= 0)
|
|
|
|
__sync_fetch_and_add(&m_refcount,1);
|
|
|
|
#endif
|
|
|
|
#else
|
2010-11-01 14:54:53 +00:00
|
|
|
m_mutex->lock();
|
2006-01-12 05:32:06 +00:00
|
|
|
int i = m_refcount;
|
|
|
|
if (i > 0)
|
|
|
|
--m_refcount;
|
2010-11-01 14:54:53 +00:00
|
|
|
m_mutex->unlock();
|
2011-11-07 17:10:32 +00:00
|
|
|
#endif
|
2011-11-04 18:24:51 +00:00
|
|
|
if (i == 1)
|
2005-07-18 21:47:18 +00:00
|
|
|
zeroRefs();
|
2006-01-18 16:06:05 +00:00
|
|
|
else if (i <= 0)
|
|
|
|
Debug(DebugFail,"RefObject::deref() called with count=%d [%p]",i,this);
|
2006-01-12 05:32:06 +00:00
|
|
|
return (i <= 1);
|
2004-12-20 04:11:29 +00:00
|
|
|
}
|
|
|
|
|
2005-07-18 21:47:18 +00:00
|
|
|
void RefObject::zeroRefs()
|
2006-01-12 05:32:06 +00:00
|
|
|
{
|
2007-05-15 11:16:41 +00:00
|
|
|
destroyed();
|
2006-01-12 05:32:06 +00:00
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RefObject::resurrect()
|
2005-07-18 21:47:18 +00:00
|
|
|
{
|
2011-11-07 17:10:32 +00:00
|
|
|
#ifdef ATOMIC_OPS
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
if (InterlockedIncrement((LONG*)&m_refcount) == 1)
|
|
|
|
return true;
|
|
|
|
InterlockedDecrement((LONG*)&m_refcount);
|
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
if (__sync_add_and_fetch(&m_refcount,1) == 1)
|
|
|
|
return true;
|
|
|
|
__sync_sub_and_fetch(&m_refcount,1);
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
#else
|
2010-11-01 14:54:53 +00:00
|
|
|
m_mutex->lock();
|
2006-01-12 05:32:06 +00:00
|
|
|
bool ret = (0 == m_refcount);
|
|
|
|
if (ret)
|
|
|
|
m_refcount = 1;
|
2010-11-01 14:54:53 +00:00
|
|
|
m_mutex->unlock();
|
2006-01-12 05:32:06 +00:00
|
|
|
return ret;
|
2011-11-07 17:10:32 +00:00
|
|
|
#endif
|
2005-07-18 21:47:18 +00:00
|
|
|
}
|
|
|
|
|
2007-05-15 12:51:13 +00:00
|
|
|
void RefObject::destroyed()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-11-07 17:10:32 +00:00
|
|
|
bool RefObject::efficientIncDec()
|
|
|
|
{
|
|
|
|
#ifdef ATOMIC_OPS
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
return false;
|
|
|
|
#endif
|
|
|
|
}
|
2011-11-04 18:24:51 +00:00
|
|
|
|
2005-03-28 00:58:26 +00:00
|
|
|
void RefPointerBase::assign(RefObject* oldptr, RefObject* newptr, void* pointer)
|
|
|
|
{
|
|
|
|
if (oldptr == newptr)
|
|
|
|
return;
|
|
|
|
// Always reference the new object before dereferencing the old one
|
2006-01-12 05:32:06 +00:00
|
|
|
// and also don't keep pointers to objects that fail referencing
|
|
|
|
m_pointer = (newptr && newptr->ref()) ? pointer : 0;
|
2005-03-28 00:58:26 +00:00
|
|
|
if (oldptr)
|
|
|
|
oldptr->deref();
|
|
|
|
}
|
|
|
|
|
2006-05-24 10:04:22 +00:00
|
|
|
|
|
|
|
void SysUsage::init()
|
|
|
|
{
|
|
|
|
if (!s_startTime)
|
|
|
|
s_startTime = Time::now();
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int64_t SysUsage::startTime()
|
|
|
|
{
|
|
|
|
init();
|
|
|
|
return s_startTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int64_t SysUsage::usecRunTime(Type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case WallTime:
|
|
|
|
return Time::now() - startTime();
|
|
|
|
case UserTime:
|
|
|
|
{
|
|
|
|
#ifdef _WINDOWS
|
2006-07-01 00:23:11 +00:00
|
|
|
FILETIME dummy,ft;
|
|
|
|
if (GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&dummy,&ft)) {
|
2006-05-24 10:04:22 +00:00
|
|
|
u_int64_t t = ft.dwLowDateTime | (((u_int64_t)ft.dwHighDateTime) << 32);
|
|
|
|
return t / 10;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
struct rusage usage;
|
|
|
|
// FIXME: this is broken, may not sum all threads
|
|
|
|
if (!::getrusage(RUSAGE_SELF,&usage))
|
|
|
|
return Time::fromTimeval(usage.ru_utime);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KernelTime:
|
|
|
|
{
|
|
|
|
#ifdef _WINDOWS
|
2006-07-01 00:23:11 +00:00
|
|
|
FILETIME dummy,ft;
|
|
|
|
if (GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&ft,&dummy)) {
|
2006-05-24 10:04:22 +00:00
|
|
|
u_int64_t t = ft.dwLowDateTime | (((u_int64_t)ft.dwHighDateTime) << 32);
|
|
|
|
return t / 10;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
struct rusage usage;
|
|
|
|
// FIXME: this is broken, may not sum all threads
|
|
|
|
if (!::getrusage(RUSAGE_SELF,&usage))
|
|
|
|
return Time::fromTimeval(usage.ru_stime);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int64_t SysUsage::msecRunTime(Type type)
|
|
|
|
{
|
|
|
|
return usecRunTime(type) / 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int32_t SysUsage::secRunTime(Type type)
|
|
|
|
{
|
|
|
|
return (u_int32_t)(usecRunTime(type) / 1000000);
|
|
|
|
}
|
|
|
|
|
|
|
|
double SysUsage::runTime(Type type)
|
|
|
|
{
|
2006-05-26 08:16:45 +00:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
// VC++ 6 does not implement conversion from UINT64 to double!
|
|
|
|
return 0.000001 * (int64_t)usecRunTime(type);
|
|
|
|
#else
|
2006-05-24 10:04:22 +00:00
|
|
|
return 0.000001 * usecRunTime(type);
|
2006-05-26 08:16:45 +00:00
|
|
|
#endif
|
2006-05-24 10:04:22 +00:00
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
2005-03-28 00:58:26 +00:00
|
|
|
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|