1 /**
2  * TelEngine.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * Yet Another Telephony Engine - a fully featured software PBX and IVR
6  * Copyright (C) 2004-2014 Null Team
7  *
8  * This software is distributed under multiple licenses;
9  * see the COPYING file in the main directory for licensing
10  * information for this specific distribution.
11  *
12  * This use of this software may be subject to additional restrictions.
13  * See the LEGAL file in the main directory for details.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #include "yateclass.h"
21 
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <time.h>
27 
28 
29 #ifdef _WINDOWS
30 
31 #ifndef HAVE_GMTIME_S
32 #include <errno.h>
33 
_gmtime_s(struct tm * _tm,const time_t * time)34 static int _gmtime_s(struct tm* _tm, const time_t* time)
35 {
36     static TelEngine::Mutex m(false,"_gmtime_s");
37     struct tm* tmp;
38     if (!_tm)
39 	return EINVAL;
40     _tm->tm_isdst = _tm->tm_yday = _tm->tm_wday = _tm->tm_year = _tm->tm_mon = _tm->tm_mday =
41 	_tm->tm_hour = _tm->tm_min = _tm->tm_sec = -1;
42     if (!time)
43 	return EINVAL;
44     m.lock();
45     tmp = gmtime(time);
46     if (!tmp) {
47 	m.unlock();
48 	return EINVAL;
49     }
50     *_tm = *tmp;
51     m.unlock();
52     return 0;
53 }
54 
_localtime_s(struct tm * _tm,const time_t * time)55 static int _localtime_s(struct tm* _tm, const time_t* time)
56 {
57     static TelEngine::Mutex m(false,"_localtime_s");
58     struct tm* tmp;
59     if (!_tm)
60 	return EINVAL;
61     _tm->tm_isdst = _tm->tm_yday = _tm->tm_wday = _tm->tm_year = _tm->tm_mon = _tm->tm_mday =
62 	_tm->tm_hour = _tm->tm_min = _tm->tm_sec = -1;
63     if (!time)
64 	return EINVAL;
65     m.lock();
66     tmp = localtime(time);
67     if (!tmp) {
68 	m.unlock();
69 	return EINVAL;
70     }
71     *_tm = *tmp;
72     m.unlock();
73     return 0;
74 }
75 
76 #endif
77 
78 #else // !_WINDOWS
79 #include <sys/resource.h>
80 #endif
81 
82 namespace { // anonymous
83 
84 class ObjCounterList : public TelEngine::ObjList
85 {
86 public:
ObjCounterList()87     inline ObjCounterList()
88 	: m_invalid(false)
89 	{ }
~ObjCounterList()90     ~ObjCounterList()
91 	{ m_invalid = true; }
invalid() const92     inline bool invalid() const
93 	{ return m_invalid; }
94 private:
95     bool m_invalid;
96 };
97 
98 }; // anonymous namespace
99 
100 namespace TelEngine {
101 
102 #define DebugMin DebugFail
103 #define DebugVis DebugConf
104 #define DebugDef DebugNote
105 #define DebugMax DebugAll
106 
107 #define OUT_BUFFER_SIZE 8192
108 #define OUT_HEADER_SIZE 112
109 
110 // RefObject mutex pool array size
111 #ifndef REFOBJECT_MUTEX_COUNT
112 #define REFOBJECT_MUTEX_COUNT 47
113 #endif
114 
115 // Number of seconds from 1900 to 1970
116 #define SECONDS_1900_TO_1970 2208988800u // 0x83AA7E80
117 // UNIX time of NTP time 07 Feb. 2036 6h 28m 16s
118 // NTP time will overflow at this UNIX time
119 #define UNIX_NTP_MAX 2085978496u         // 0x7C558180
120 
121 static int s_debug = DebugDef;
122 static int s_indent = 0;
123 static bool s_debugging = true;
124 static bool s_abort = false;
125 static u_int64_t s_startTime = 0;
126 static u_int64_t s_timestamp = 0;
127 static Debugger::Formatting s_fmtstamp = Debugger::None;
128 
129 static const char* const s_colors[11] = {
130     "\033[5;41;1;33m\033[K",// DebugFail - blinking yellow on red
131     "\033[44;1;37m\033[K",  // DebugTest - white on blue
132     "\033[41;1;37m\033[K",  // DebugCrit - white on red
133     "\033[41;37m\033[K",    // DebugConf - gray on red
134     "\033[40;31m\033[K",    // DebugStub - red on black
135     "\033[40;1;31m\033[K",  // DebugWarn - light red on black
136     "\033[40;1;33m\033[K",  // DebugMild - yellow on black
137     "\033[40;1;32m\033[K",  // DebugNote - light green on black
138     "\033[40;1;37m\033[K",  // DebugCall - white on black
139     "\033[40;1;36m\033[K",  // DebugInfo - light cyan on black
140     "\033[40;36m\033[K"     // DebugAll  - cyan on black
141 };
142 
143 static const char* const s_levels[11] = {
144     "FAIL",
145     "TEST",
146     "CRIT",
147     "CONF",
148     "STUB",
149     "WARN",
150     "MILD",
151     "NOTE",
152     "CALL",
153     "INFO",
154     "ALL",
155 };
156 
dbg_level(int & level)157 static const char* dbg_level(int& level)
158 {
159     if (level < DebugMin)
160 	level = DebugMin;
161     if (level > DebugMax)
162 	level = DebugMax;
163     return s_levels[level];
164 }
165 
dbg_stderr_func(const char * buf,int level)166 static void dbg_stderr_func(const char* buf, int level)
167 {
168     YIGNORE(::write(2,buf,::strlen(buf)));
169 }
170 
dbg_colorize_func(const char * buf,int level)171 static void dbg_colorize_func(const char* buf, int level)
172 {
173     const char* col = debugColor(level);
174     YIGNORE(::write(2,col,::strlen(col)));
175     YIGNORE(::write(2,buf,::strlen(buf)));
176     col = debugColor(-2);
177     YIGNORE(::write(2,col,::strlen(col)));
178 }
179 
180 static void (*s_output)(const char*,int) = dbg_stderr_func;
181 static void (*s_intout)(const char*,int) = 0;
182 static void (*s_alarms)(const char*,int,const char*,const char*) = 0;
183 static void (*s_relay)(int,const char*,const char*,const char*) = 0;
184 
185 static Mutex out_mux(false,"DebugOutput");
186 static Mutex ind_mux(false,"DebugIndent");
187 static Thread* s_thr = 0;
188 
189 bool CapturedEvent::s_capturing = false;
190 ObjList CapturedEvent::s_events;
191 
reentered()192 static bool reentered()
193 {
194     if (!s_thr)
195 	return false;
196     return (Thread::current() == s_thr);
197 }
198 
common_output(int level,char * buf)199 static void common_output(int level,char* buf)
200 {
201     if (level < -1)
202 	level = -1;
203     if (level > DebugMax)
204 	level = DebugMax;
205     int n = ::strlen(buf);
206     if (n && (buf[n-1] == '\n'))
207 	n--;
208     // serialize the output strings
209     out_mux.lock();
210     // TODO: detect reentrant calls from foreign threads and main thread
211     s_thr = Thread::current();
212     if (CapturedEvent::capturing()) {
213 	buf[n] = '\0';
214 	bool save = s_debugging;
215 	s_debugging = false;
216 	CapturedEvent::append(level,buf);
217 	s_debugging = save;
218     }
219     buf[n] = '\n';
220     buf[n+1] = '\0';
221     if (s_output)
222 	s_output(buf,level);
223     if (s_intout)
224 	s_intout(buf,level);
225     buf[n] = '\0';
226     s_thr = 0;
227     out_mux.unlock();
228 }
229 
dbg_output(int level,const char * prefix,const char * format,va_list ap,const char * alarmComp=0,const char * alarmInfo=0)230 static void dbg_output(int level,const char* prefix, const char* format, va_list ap,
231     const char* alarmComp = 0, const char* alarmInfo = 0)
232 {
233     void (*relay)(int,const char*,const char*,const char*) = s_relay;
234     void (*alarms)(const char*,int,const char*,const char*) = s_alarms;
235     bool out = (s_output || s_intout || relay) && (prefix || format);
236     bool alarm = alarmComp && format && (alarms || relay);
237     if (!(out || alarm))
238 	return;
239     char buf[OUT_BUFFER_SIZE];
240     unsigned int n = Debugger::formatTime(buf,s_fmtstamp);
241     unsigned int l = s_indent*2;
242     if (l >= sizeof(buf)-n)
243 	l = sizeof(buf)-n-1;
244     ::memset(buf+n,' ',l);
245     n += l;
246     buf[n] = 0;
247     l = sizeof(buf)-n-2;
248     if (prefix)
249 	::strncpy(buf+n,prefix,l);
250     n = ::strlen(buf);
251     l = sizeof(buf)-n-2;
252     char* msg = buf+n;
253     if (format) {
254 	::vsnprintf(msg,l,format,ap);
255 	buf[OUT_BUFFER_SIZE - 2] = 0;
256     }
257     if (relay) {
258 	relay(level,buf,alarmComp,alarmInfo);
259 	return;
260     }
261     if (out)
262 	common_output(level,buf);
263     if (alarm)
264 	alarms(msg,level,alarmComp,alarmInfo);
265 }
266 
Output(const char * format,...)267 void Output(const char* format, ...)
268 {
269     char buf[OUT_BUFFER_SIZE];
270     void (*relay)(int,const char*,const char*,const char*) = s_relay;
271     if (!((s_output || s_intout || relay) && format && *format))
272 	return;
273     if (reentered())
274 	return;
275     va_list va;
276     va_start(va,format);
277     ::vsnprintf(buf,sizeof(buf)-2,format,va);
278     va_end(va);
279     if (relay)
280 	relay(-1,buf,0,0);
281     else
282 	common_output(-1,buf);
283 }
284 
Debug(int level,const char * format,...)285 void Debug(int level, const char* format, ...)
286 {
287     if (!s_debugging)
288 	return;
289     if (level > s_debug || level < DebugMin)
290 	return;
291     if (reentered())
292 	return;
293     if (!format)
294 	format = "";
295     char buf[32];
296     ::sprintf(buf,"<%s> ",dbg_level(level));
297     va_list va;
298     va_start(va,format);
299     ind_mux.lock();
300     dbg_output(level,buf,format,va);
301     ind_mux.unlock();
302     va_end(va);
303     if (s_abort && (level == DebugFail))
304 	abort();
305 }
306 
Debug(const char * facility,int level,const char * format,...)307 void Debug(const char* facility, int level, const char* format, ...)
308 {
309     if (!s_debugging)
310 	return;
311     if (level > s_debug || level < DebugMin)
312 	return;
313     if (reentered())
314 	return;
315     if (!format)
316 	format = "";
317     char buf[OUT_HEADER_SIZE];
318     ::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
319     va_list va;
320     va_start(va,format);
321     ind_mux.lock();
322     dbg_output(level,buf,format,va);
323     ind_mux.unlock();
324     va_end(va);
325     if (s_abort && (level == DebugFail))
326 	abort();
327 }
328 
Debug(const DebugEnabler * local,int level,const char * format,...)329 void Debug(const DebugEnabler* local, int level, const char* format, ...)
330 {
331     if (!s_debugging)
332 	return;
333     const char* facility = 0;
334     if (!local) {
335 	if (level > s_debug || level < DebugMin)
336 	    return;
337     }
338     else {
339 	if (!local->debugAt(level))
340 	    return;
341 	facility = local->debugName();
342     }
343     if (reentered())
344 	return;
345     if (!format)
346 	format = "";
347     char buf[OUT_HEADER_SIZE];
348     if (facility)
349 	::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
350     else
351 	::sprintf(buf,"<%s> ",dbg_level(level));
352     va_list va;
353     va_start(va,format);
354     ind_mux.lock();
355     dbg_output(level,buf,format,va);
356     ind_mux.unlock();
357     va_end(va);
358     if (s_abort && (level == DebugFail))
359 	abort();
360 }
361 
Alarm(const char * component,int level,const char * format,...)362 void Alarm(const char* component, int level, const char* format, ...)
363 {
364     if (!format || level < DebugMin || reentered())
365 	return;
366     if (TelEngine::null(component))
367 	component = "unknown";
368     char buf[OUT_HEADER_SIZE];
369     ::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
370     va_list va;
371     va_start(va,format);
372     ind_mux.lock();
373     dbg_output(level,buf,format,va,component);
374     ind_mux.unlock();
375     va_end(va);
376     if (s_abort && (level == DebugFail))
377 	abort();
378 }
379 
Alarm(const DebugEnabler * component,int level,const char * format,...)380 void Alarm(const DebugEnabler* component, int level, const char* format, ...)
381 {
382     if (!format || level < DebugMin || reentered())
383 	return;
384     const char* name = (component && !TelEngine::null(component->debugName()))
385 	? component->debugName() : "unknown";
386     char buf[OUT_HEADER_SIZE];
387     ::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
388     va_list va;
389     va_start(va,format);
390     ind_mux.lock();
391     dbg_output(level,buf,format,va,name);
392     ind_mux.unlock();
393     va_end(va);
394     if (s_abort && (level == DebugFail))
395 	abort();
396 }
397 
Alarm(const char * component,const char * info,int level,const char * format,...)398 void Alarm(const char* component, const char* info, int level, const char* format, ...)
399 {
400     if (!format || level < DebugMin || reentered())
401 	return;
402     if (TelEngine::null(component))
403 	component = "unknown";
404     char buf[OUT_HEADER_SIZE];
405     ::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
406     va_list va;
407     va_start(va,format);
408     ind_mux.lock();
409     dbg_output(level,buf,format,va,component,info);
410     ind_mux.unlock();
411     va_end(va);
412     if (s_abort && (level == DebugFail))
413 	abort();
414 }
415 
Alarm(const DebugEnabler * component,const char * info,int level,const char * format,...)416 void Alarm(const DebugEnabler* component, const char* info, int level, const char* format, ...)
417 {
418     if (!format || level < DebugMin || reentered())
419 	return;
420     const char* name = (component && !TelEngine::null(component->debugName()))
421 	? component->debugName() : "unknown";
422     char buf[OUT_HEADER_SIZE];
423     ::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
424     va_list va;
425     va_start(va,format);
426     ind_mux.lock();
427     dbg_output(level,buf,format,va,name,info);
428     ind_mux.unlock();
429     va_end(va);
430     if (s_abort && (level == DebugFail))
431 	abort();
432 }
433 
TraceDebug(const char * traceId,int level,const char * format,...)434 void TraceDebug(const char* traceId, int level, const char* format, ...)
435 {
436     if (!s_debugging)
437 	return;
438     if (level > s_debug || level < DebugMin)
439 	return;
440     if (reentered())
441 	return;
442     if (!format)
443 	format = "";
444     char buf[OUT_HEADER_SIZE];
445     if (traceId)
446 	::snprintf(buf,sizeof(buf),"<%s> Trace:%s ",dbg_level(level),traceId);
447     else
448 	::sprintf(buf,"<%s> ",dbg_level(level));
449     va_list va;
450     va_start(va,format);
451     ind_mux.lock();
452     dbg_output(level,buf,format,va);
453     ind_mux.unlock();
454     va_end(va);
455     if (s_abort && (level == DebugFail))
456 	abort();
457 }
458 
TraceDebug(const char * traceId,const char * facility,int level,const char * format,...)459 void TraceDebug(const char* traceId, const char* facility, int level, const char* format, ...)
460 {
461     if (!s_debugging)
462 	return;
463     if (level > s_debug || level < DebugMin)
464 	return;
465     if (reentered())
466 	return;
467     if (!format)
468 	format = "";
469     char buf[OUT_HEADER_SIZE];
470     if (traceId)
471 	::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",facility,dbg_level(level),traceId);
472     else
473 	::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
474     va_list va;
475     va_start(va,format);
476     ind_mux.lock();
477     dbg_output(level,buf,format,va);
478     ind_mux.unlock();
479     va_end(va);
480     if (s_abort && (level == DebugFail))
481 	abort();
482 }
483 
TraceDebug(const char * traceId,const DebugEnabler * local,int level,const char * format,...)484 void TraceDebug(const char* traceId, const DebugEnabler* local, int level, const char* format, ...)
485 {
486     if (!s_debugging)
487 	return;
488     const char* facility = 0;
489     if (!local) {
490 	if (level > s_debug || level < DebugMin)
491 	    return;
492     }
493     else {
494 	if (!local->debugAt(level))
495 	    return;
496 	facility = local->debugName();
497     }
498     if (reentered())
499 	return;
500     if (!format)
501 	format = "";
502     char buf[OUT_HEADER_SIZE];
503     if (facility) {
504 	if (traceId)
505 	    ::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",facility,dbg_level(level),traceId);
506 	else
507 	    ::snprintf(buf,sizeof(buf),"<%s:%s> ",facility,dbg_level(level));
508     }
509     else {
510 	if (traceId)
511 	    ::snprintf(buf,sizeof(buf),"<%s> Trace:%s ",dbg_level(level),traceId);
512 	else
513 	    ::sprintf(buf,"<%s> ",dbg_level(level));
514     }
515 
516     va_list va;
517     va_start(va,format);
518     ind_mux.lock();
519     dbg_output(level,buf,format,va);
520     ind_mux.unlock();
521     va_end(va);
522     if (s_abort && (level == DebugFail))
523 	abort();
524 }
525 
TraceAlarm(const char * traceId,const char * component,int level,const char * format,...)526 void TraceAlarm(const char* traceId, const char* component, int level, const char* format, ...)
527 {
528     if (!format || level < DebugMin || reentered())
529 	return;
530     if (TelEngine::null(component))
531 	component = "unknown";
532     char buf[OUT_HEADER_SIZE];
533     if (traceId)
534 	::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",component,dbg_level(level),traceId);
535     else
536 	::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
537     va_list va;
538     va_start(va,format);
539     ind_mux.lock();
540     dbg_output(level,buf,format,va,component);
541     ind_mux.unlock();
542     va_end(va);
543     if (s_abort && (level == DebugFail))
544 	abort();
545 }
546 
TraceAlarm(const char * traceId,const DebugEnabler * component,int level,const char * format,...)547 void TraceAlarm(const char* traceId, const DebugEnabler* component, int level, const char* format, ...)
548 {
549     if (!format || level < DebugMin || reentered())
550 	return;
551     const char* name = (component && !TelEngine::null(component->debugName()))
552 	? component->debugName() : "unknown";
553     char buf[OUT_HEADER_SIZE];
554     if (traceId)
555 	::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",name,dbg_level(level),traceId);
556     else
557 	::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
558     va_list va;
559     va_start(va,format);
560     ind_mux.lock();
561     dbg_output(level,buf,format,va,name);
562     ind_mux.unlock();
563     va_end(va);
564     if (s_abort && (level == DebugFail))
565 	abort();
566 }
567 
TraceAlarm(const char * traceId,const char * component,const char * info,int level,const char * format,...)568 void TraceAlarm(const char* traceId, const char* component, const char* info, int level, const char* format, ...)
569 {
570     if (!format || level < DebugMin || reentered())
571 	return;
572     if (TelEngine::null(component))
573 	component = "unknown";
574     char buf[OUT_HEADER_SIZE];
575        if (traceId)
576 	::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",component,dbg_level(level),traceId);
577     else
578 	::snprintf(buf,sizeof(buf),"<%s:%s> ",component,dbg_level(level));
579     va_list va;
580     va_start(va,format);
581     ind_mux.lock();
582     dbg_output(level,buf,format,va,component,info);
583     ind_mux.unlock();
584     va_end(va);
585     if (s_abort && (level == DebugFail))
586 	abort();
587 }
588 
TraceAlarm(const char * traceId,const DebugEnabler * component,const char * info,int level,const char * format,...)589 void TraceAlarm(const char* traceId, const DebugEnabler* component, const char* info, int level, const char* format, ...)
590 {
591     if (!format || level < DebugMin || reentered())
592 	return;
593     const char* name = (component && !TelEngine::null(component->debugName()))
594 	? component->debugName() : "unknown";
595     char buf[OUT_HEADER_SIZE];
596     if (traceId)
597 	::snprintf(buf,sizeof(buf),"<%s:%s> Trace:%s ",name,dbg_level(level),traceId);
598     else
599 	::snprintf(buf,sizeof(buf),"<%s:%s> ",name,dbg_level(level));
600     va_list va;
601     va_start(va,format);
602     ind_mux.lock();
603     dbg_output(level,buf,format,va,name,info);
604     ind_mux.unlock();
605     va_end(va);
606     if (s_abort && (level == DebugFail))
607 	abort();
608 }
609 
abortOnBug()610 void abortOnBug()
611 {
612     if (s_abort)
613 	abort();
614 }
615 
abortOnBug(bool doAbort)616 bool abortOnBug(bool doAbort)
617 {
618     bool tmp = s_abort;
619     s_abort = doAbort;
620     return tmp;
621 }
622 
debugLevel()623 int debugLevel()
624 {
625     return s_debug;
626 }
627 
debugLevel(int level)628 int debugLevel(int level)
629 {
630     if (level < DebugVis)
631 	level = DebugVis;
632     if (level > DebugMax)
633 	level = DebugMax;
634     return (s_debug = level);
635 }
636 
debugAt(int level)637 bool debugAt(int level)
638 {
639     return (s_debugging && (level <= s_debug));
640 }
641 
debugColor(int level)642 const char* debugColor(int level)
643 {
644     if (level == -2)
645 	return "\033[0m\033[K"; // reset to defaults
646     if ((level < DebugMin) || (level > DebugMax))
647 	return "\033[0;40;37m\033[K"; // light gray on black
648     return s_colors[level];
649 }
650 
debugLevelName(int level)651 const char* debugLevelName(int level)
652 {
653     return (level < DebugMin) ? "" : dbg_level(level);
654 }
655 
656 
debugLevel(int level)657 int DebugEnabler::debugLevel(int level)
658 {
659     if (level < DebugVis)
660 	level = DebugVis;
661     if (level > DebugMax)
662 	level = DebugMax;
663     m_chain = 0;
664     return (m_level = level);
665 }
666 
debugAt(int level) const667 bool DebugEnabler::debugAt(int level) const
668 {
669     if (m_chain)
670 	return m_chain->debugAt(level);
671     return (m_enabled && (level <= m_level));
672 }
673 
debugCopy(const DebugEnabler * original)674 void DebugEnabler::debugCopy(const DebugEnabler* original)
675 {
676     if (original) {
677 	m_level = original->debugLevel();
678 	m_enabled = original->debugEnabled();
679     }
680     else {
681 	m_level = TelEngine::debugLevel();
682 	m_enabled = debugEnabled();
683     }
684     m_chain = 0;
685 }
686 
Debugger(const char * name,const char * format,...)687 Debugger::Debugger(const char* name, const char* format, ...)
688     : m_name(name), m_level(DebugAll)
689 {
690     if (s_debugging && m_name && (s_debug >= DebugAll) && !reentered()) {
691 	char buf[OUT_HEADER_SIZE];
692 	::snprintf(buf,sizeof(buf),">>> %s",m_name);
693 	va_list va;
694 	va_start(va,format);
695 	ind_mux.lock();
696 	dbg_output(m_level,buf,format,va);
697 	va_end(va);
698 	s_indent++;
699 	ind_mux.unlock();
700     }
701     else
702 	m_name = 0;
703 }
704 
Debugger(int level,const char * name,const char * format,...)705 Debugger::Debugger(int level, const char* name, const char* format, ...)
706     : m_name(name), m_level(level)
707 {
708     if (s_debugging && m_name && (s_debug >= level) && !reentered()) {
709 	char buf[OUT_HEADER_SIZE];
710 	::snprintf(buf,sizeof(buf),">>> %s",m_name);
711 	va_list va;
712 	va_start(va,format);
713 	ind_mux.lock();
714 	dbg_output(m_level,buf,format,va);
715 	va_end(va);
716 	s_indent++;
717 	ind_mux.unlock();
718     }
719     else
720 	m_name = 0;
721 }
722 
dbg_dist_helper(int level,const char * buf,const char * fmt,...)723 static void dbg_dist_helper(int level, const char* buf, const char* fmt, ...)
724 {
725     va_list va;
726     va_start(va,fmt);
727     dbg_output(level,buf,fmt,va);
728     va_end(va);
729 }
730 
controlReturn(NamedList * params,bool ret,const char * retVal)731 bool controlReturn(NamedList* params, bool ret, const char* retVal)
732 {
733     if (retVal && params)
734 	params->setParam("retVal",retVal);
735     if (!params || !params->getObject(YATOM("Message")))
736 	return ret;
737     const String* module = params->getParam("module");
738     if (TelEngine::null(module) || YSTRING("rmanager") != *module)
739 	return ret;
740     const String s_opStat("operation-status");
741     if (!params->getParam(s_opStat))
742 	params->addParam(s_opStat,String::boolText(ret));
743     return ret;
744 }
745 
~Debugger()746 Debugger::~Debugger()
747 {
748     if (m_name) {
749 	ind_mux.lock();
750 	s_indent--;
751 	if (s_debugging)
752 	    dbg_dist_helper(m_level,"<<< ","%s",m_name);
753 	ind_mux.unlock();
754     }
755 }
756 
setOutput(void (* outFunc)(const char *,int))757 void Debugger::setOutput(void (*outFunc)(const char*,int))
758 {
759     out_mux.lock();
760     s_output = outFunc ? outFunc : dbg_stderr_func;
761     out_mux.unlock();
762 }
763 
setIntOut(void (* outFunc)(const char *,int))764 void Debugger::setIntOut(void (*outFunc)(const char*,int))
765 {
766     out_mux.lock();
767     s_intout = outFunc;
768     out_mux.unlock();
769 }
770 
setAlarmHook(void (* alarmFunc)(const char *,int,const char *,const char *))771 void Debugger::setAlarmHook(void (*alarmFunc)(const char*,int,const char*,const char*))
772 {
773     s_alarms = alarmFunc;
774 }
775 
setRelayHook(void (* relayFunc)(int,const char *,const char *,const char *))776 void Debugger::setRelayHook(void (*relayFunc)(int,const char*,const char*,const char*))
777 {
778     s_relay = relayFunc;
779 }
780 
enableOutput(bool enable,bool colorize)781 void Debugger::enableOutput(bool enable, bool colorize)
782 {
783     s_debugging = enable;
784     if (colorize)
785 	setOutput(dbg_colorize_func);
786 }
787 
getStartTimeSec()788 uint32_t Debugger::getStartTimeSec()
789 {
790     return (uint32_t)(s_timestamp / 1000000);
791 }
792 
getFormatting()793 Debugger::Formatting Debugger::getFormatting()
794 {
795     return s_fmtstamp;
796 }
797 
setFormatting(Formatting format,uint32_t startTimeSec)798 void Debugger::setFormatting(Formatting format, uint32_t startTimeSec)
799 {
800     // start stamp will be rounded to full second
801     if (!s_timestamp) {
802 	uint64_t sec = Time::now() / 1000000;
803 	if (startTimeSec && startTimeSec < sec)
804 	    sec = startTimeSec;
805 	s_timestamp = sec * 1000000;
806     }
807     s_fmtstamp = format;
808 }
809 
formatTime(char * buf,Formatting format)810 unsigned int Debugger::formatTime(char* buf, Formatting format)
811 {
812     if (!buf)
813 	return 0;
814     if (None != format) {
815 	u_int64_t t = Time::now();
816 	if (Relative == format)
817 	    t -= s_timestamp;
818 	unsigned int s = (unsigned int)(t / 1000000);
819 	unsigned int u = (unsigned int)(t % 1000000);
820 	switch (format) {
821 	    case Textual:
822 	    case TextLocal:
823 	    case TextSep:
824 	    case TextLSep:
825 		{
826 		    time_t sec = (time_t)s;
827 		    struct tm tmp;
828 		    if (TextLocal == format || TextLSep == format)
829 #ifdef _WINDOWS
830 			_localtime_s(&tmp,&sec);
831 #else
832 			localtime_r(&sec,&tmp);
833 #endif
834 		    else
835 #ifdef _WINDOWS
836 			_gmtime_s(&tmp,&sec);
837 #else
838 			gmtime_r(&sec,&tmp);
839 #endif
840 		    if (Textual == format || TextLocal == format)
841 			::sprintf(buf,"%04d%02d%02d%02d%02d%02d.%06u ",
842 			    tmp.tm_year+1900,tmp.tm_mon+1,tmp.tm_mday,
843 			    tmp.tm_hour,tmp.tm_min,tmp.tm_sec,u);
844 		    else
845 			::sprintf(buf,"%04d-%02d-%02d_%02d:%02d:%02d.%06u ",
846 			    tmp.tm_year+1900,tmp.tm_mon+1,tmp.tm_mday,
847 			    tmp.tm_hour,tmp.tm_min,tmp.tm_sec,u);
848 		}
849 		break;
850 	    default:
851 		::sprintf(buf,"%07u.%06u ",s,u);
852 	}
853 	return ::strlen(buf);
854     }
855     buf[0] = '\0';
856     return 0;
857 }
858 
relayOutput(int level,char * buffer,const char * component,const char * info)859 void Debugger::relayOutput(int level, char* buffer, const char* component, const char* info)
860 {
861     if (TelEngine::null(buffer))
862 	return;
863     void (*alarms)(const char*,int,const char*,const char*) = s_alarms;
864     bool out = s_output || s_intout;
865     bool alarm = (level >= 0) && alarms && !TelEngine::null(component);
866     if (!(out || alarm))
867 	return;
868     if (reentered())
869 	return;
870     if (out)
871 	common_output(level,buffer);
872     if (alarm) {
873 	const char* msg = ::strstr(buffer,"> ");
874 	if (msg && msg != buffer)
875 	    msg += 2;
876 	else
877 	    msg = buffer;
878 	if (*msg)
879 	    alarms(msg,level,component,info);
880     }
881 }
882 
883 
now()884 u_int64_t Time::now()
885 {
886 #ifdef _WINDOWS
887     FILETIME ft;
888     GetSystemTimeAsFileTime(&ft);
889     // Convert from FILETIME (100 nsec units since January 1, 1601)
890     //  to extended time_t (1 usec units since January 1, 1970)
891     u_int64_t rval = ((ULARGE_INTEGER*)&ft)->QuadPart / 10;
892     rval -= 11644473600000000;
893     return rval;
894 #else
895     struct timeval tv;
896     return ::gettimeofday(&tv,0) ? 0 : fromTimeval(&tv);
897 #endif
898 }
899 
msecNow()900 u_int64_t Time::msecNow()
901 {
902     return (u_int64_t)(now() / 1000);
903 }
904 
secNow()905 u_int32_t Time::secNow()
906 {
907 #ifdef _WINDOWS
908     return (u_int32_t)(now() / 1000000);
909 #else
910     struct timeval tv;
911     return ::gettimeofday(&tv,0) ? 0 : tv.tv_sec;
912 #endif
913 }
914 
fromTimeval(const struct timeval * tv)915 u_int64_t Time::fromTimeval(const struct timeval* tv)
916 {
917     u_int64_t rval = 0;
918     if (tv) {
919 	// Please keep it this way or the compiler may b0rk
920 	rval = tv->tv_sec;
921 	rval *= 1000000;
922 	rval += tv->tv_usec;
923     }
924     return rval;
925 }
926 
toTimeval(struct timeval * tv,u_int64_t usec)927 void Time::toTimeval(struct timeval* tv, u_int64_t usec)
928 {
929     if (tv) {
930 	tv->tv_usec = (long)(usec % 1000000);
931 	tv->tv_sec = (long)(usec / 1000000);
932     }
933 }
934 
935 // Build EPOCH time from date/time components
toEpoch(int year,unsigned int month,unsigned int day,unsigned int hour,unsigned int minute,unsigned int sec,int offset)936 unsigned int Time::toEpoch(int year, unsigned int month, unsigned int day,
937 	unsigned int hour, unsigned int minute, unsigned int sec, int offset)
938 {
939     DDebug(DebugAll,"Time::toEpoch(%d,%u,%u,%u,%u,%u,%d)",
940 	year,month,day,hour,minute,sec,offset);
941     if (year < 1970)
942 	return (unsigned int)-1;
943     if (month < 1 || month > 12 || !day)
944 	return (unsigned int)-1;
945     if (hour == 24 && (minute || sec))
946 	return (unsigned int)-1;
947     else if (hour > 23 || minute > 59 || sec > 59)
948 	return (unsigned int)-1;
949     // Check if month and day are correct in the given year
950     month--;
951     unsigned int m[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
952     if (isLeap(year))
953 	m[1] = 29;
954     if (day > m[month])
955 	return (unsigned int)-1;
956     // Count the number of days since EPOCH
957     int64_t days = (year - 1970) * 365;
958     // Add a day for each leap year from 1970 to 'year' (not including)
959     for (int y = 1972; y < year; y += 4) {
960 	if (isLeap(y))
961 	    days++;
962     }
963     // Add days ellapsed in given year
964     for (unsigned int i = 0; i < month; i++)
965 	days += m[i];
966     days += day - 1;
967     int64_t ret = (days * 24 + hour) * 3600 + minute * 60 + sec + offset;
968 
969     // Check for incorrect time or overflow
970     if (ret < 0 || ret > (unsigned int)-1)
971 	return (unsigned int)-1;
972     return (unsigned int)ret;
973 }
974 
975 // Split a given EPOCH time into its date/time components
toDateTime(unsigned int epochTimeSec,int & year,unsigned int & month,unsigned int & day,unsigned int & hour,unsigned int & minute,unsigned int & sec,unsigned int * wDay)976 bool Time::toDateTime(unsigned int epochTimeSec, int& year, unsigned int& month,
977     unsigned int& day, unsigned int& hour, unsigned int& minute, unsigned int& sec,
978     unsigned int* wDay)
979 {
980 #ifdef _WINDOWS
981     FILETIME ft;
982     SYSTEMTIME st;
983     // 11644473600: the number of seconds from 1601, January 1st (FILETIME)
984     //  to EPOCH (1970, January 1st)
985     // Remember: FILETIME keeps the number of 100 nsec units
986     u_int64_t time = (11644473600 + epochTimeSec) * 10000000;
987     ft.dwLowDateTime = (DWORD)time;
988     ft.dwHighDateTime = (DWORD)(time >> 32);
989     if (!FileTimeToSystemTime(&ft,&st))
990 	return false;
991     year = st.wYear;
992     month = st.wMonth;
993     day = st.wDay;
994     hour = st.wHour;
995     minute = st.wMinute;
996     sec = st.wSecond;
997     if (wDay)
998 	*wDay = st.wDayOfWeek;
999 #else
1000     struct tm t;
1001     time_t time = (time_t)epochTimeSec;
1002     if (!gmtime_r(&time,&t))
1003 	return false;
1004     year = 1900 + t.tm_year;
1005     month = t.tm_mon + 1;
1006     day = t.tm_mday;
1007     hour = t.tm_hour;
1008     minute = t.tm_min;
1009     sec = t.tm_sec;
1010     if (wDay)
1011 	*wDay = t.tm_wday;
1012 #endif
1013     DDebug(DebugAll,"Time::toDateTime(%u,%d,%u,%u,%u,%u,%u)",
1014 	epochTimeSec,year,month,day,hour,minute,sec);
1015     return true;
1016 }
1017 
toNtp(uint32_t sec,uint32_t * over,bool rfc2030)1018 uint32_t Time::toNtp(uint32_t sec, uint32_t* over, bool rfc2030)
1019 {
1020     if (sec < UNIX_NTP_MAX)
1021 	return sec + SECONDS_1900_TO_1970;
1022     if (rfc2030) {
1023 	sec -= UNIX_NTP_MAX;
1024 	if (sec <= 0x7fffffff)
1025 	    return sec;
1026 	if (over)
1027 	    *over = sec - 0x7fffffff;
1028 	return 0x7fffffff;
1029     }
1030     if (over)
1031 	*over = (uint32_t)(((uint64_t)sec + SECONDS_1900_TO_1970) - 0xffffffff);
1032     return 0xffffffff;
1033 }
1034 
fromNtp(uint32_t val,uint32_t * under,bool rfc2030)1035 uint32_t Time::fromNtp(uint32_t val, uint32_t* under, bool rfc2030)
1036 {
1037     if (rfc2030 && val <= 0x7fffffff)
1038 	return val + UNIX_NTP_MAX;
1039     if (val >= SECONDS_1900_TO_1970)
1040 	return val - SECONDS_1900_TO_1970;
1041     if (under)
1042 	*under = SECONDS_1900_TO_1970 - val;
1043     return 0;
1044 }
1045 
toString(char * buf,uint64_t time,int frac)1046 unsigned int Time::toString(char* buf, uint64_t time, int frac)
1047 {
1048     if (!buf)
1049 	return 0;
1050     int y;
1051     unsigned int m,d,hh,mm,ss;
1052     if (!Time::toDateTime(time / 1000000,y,m,d,hh,mm,ss) || y < 0 || y > 9999)
1053 	return 0;
1054     unsigned int n = 0;
1055     if (!frac)
1056 	n = ::sprintf(buf,"%04d-%02u-%02uT%02u:%02u:%02u",y,m,d,hh,mm,ss);
1057     else {
1058 	unsigned int f = time % 1000000;
1059 	if (frac > 0)
1060 	    n = ::sprintf(buf,"%04d-%02u-%02uT%02u:%02u:%02u.%03u",y,m,d,hh,mm,ss,f / 1000);
1061 	else
1062 	    n = ::sprintf(buf,"%04d-%02u-%02uT%02u:%02u:%02u.%06u",y,m,d,hh,mm,ss,f);
1063     }
1064     if (n)
1065 	buf[n++] = 'Z';
1066     return n;
1067 }
1068 
addNum2(const char * buf,unsigned int & val,unsigned int maxVal=0)1069 static inline bool addNum2(const char* buf, unsigned int& val, unsigned int maxVal = 0)
1070 {
1071     if (buf[0] < '0' || buf[0] > '9' || buf[1] < '0' || buf[1] > '9')
1072 	return false;
1073     val += 10 * (buf[0] - '0') + (buf[1] - '0');
1074     return !maxVal || val <= maxVal;
1075 }
1076 
1077 // Decode yyyy-mm-dd{T|t}hh:mm:ss[.SEC-FRAC]{{Z|z}|{+/-hh:mm}}
toEpoch(const char * buf,unsigned int len,int frac)1078 uint64_t Time::toEpoch(const char* buf, unsigned int len, int frac)
1079 {
1080     if (!buf)
1081 	return (uint64_t)-1;
1082     if (!len)
1083 	len = ::strlen(buf);
1084     if (len < 20)
1085 	return (uint64_t)-1;
1086     // Check mandatory yyyy-mm-ddThh:mm:ss
1087     if (buf[4] != '-' || buf[7] != '-' || (buf[10] != 'T' && buf[10] != 't')
1088 	|| buf[13] != ':' || buf[16] != ':')
1089 	return (uint64_t)-1;
1090     int offsetSec = 0;
1091     unsigned int delta = 0;
1092     if (buf[19] != 'Z' && buf[19] != 'z') {
1093 	// We must receive at least '.' + digit + 'Z' or TZ offset
1094 	if (len < 22)
1095 	    return (uint64_t)-1;
1096 	unsigned int crt = 19;
1097 	// Second fraction ?
1098 	if (buf[19] == '.') {
1099 	    for (crt++; crt < len; crt++) {
1100 		if (buf[crt] < '0' || buf[crt] > '9')
1101 		    break;
1102 	    }
1103 	    unsigned int fracLen = crt - 20;
1104 	    // Empty fraction or buffer end
1105 	    if (!fracLen || crt == len)
1106 		return (uint64_t)-1;
1107 	    if (frac) {
1108 		unsigned int req = frac > 0 ? 3 : 6;
1109 		String tmp(buf + 20,fracLen > req ? req : fracLen);
1110 		delta = tmp.toInteger(0,10);
1111 		for (; fracLen < req; ++fracLen)
1112 		    delta *= 10;
1113 	    }
1114 	}
1115 	// TZ offset: ('+' / '-')hh:mm
1116 	if (buf[crt] != 'Z' && buf[crt] != 'z') {
1117 	    const char* b = buf + crt;
1118 	    unsigned int tzOffsLen = len - crt;
1119 	    if (tzOffsLen != 6 || b[3] != ':')
1120 		return (uint64_t)-1;
1121 	    int mul = 1;
1122 	    if (*b == '-')
1123 		mul = -1;
1124 	    else if (*b != '+')
1125 		return (uint64_t)-1;
1126 	    unsigned int hh = 0, mm = 0;
1127 	    if (!(addNum2(b + 1,hh,23) && addNum2(b + 4,mm,59)))
1128 		return (uint64_t)-1;
1129 	    offsetSec = mul * (int)(hh * 3600 + mm * 60);
1130 	}
1131     }
1132     unsigned int y = 0, m = 0, d = 0, hh = 0, mm = 0, ss = 0;
1133     if (!addNum2(buf,y))
1134 	return (uint64_t)-1;
1135     y *= 100;
1136     if (!(addNum2(buf + 2,y) && (addNum2(buf + 5,m,12) || !m) && (addNum2(buf + 8,d,31) || !d)
1137 	&& addNum2(buf + 11,hh,23) && addNum2(buf + 14,mm,59) && addNum2(buf + 17,ss,60)))
1138 	return (uint64_t)-1;
1139     bool leapSec = (ss == 60);
1140     if (leapSec)
1141 	ss = 59;
1142     uint64_t sec = toEpoch(y,m,d,hh,mm,ss,offsetSec);
1143     if (sec == (unsigned int)-1)
1144 	return (uint64_t)-1;
1145     if (leapSec)
1146 	sec++;
1147     if (!frac)
1148 	return sec;
1149     if (frac > 0)
1150 	return sec * 1000 + delta;
1151     return sec * 1000000 + delta;
1152 }
1153 
timeZone(u_int32_t when)1154 int Time::timeZone(u_int32_t when)
1155 {
1156 #ifdef _WINDOWS
1157     struct tm t;
1158     time_t time = (time_t)when;
1159     _localtime_s(&t,&time);
1160     if (t.tm_isdst)
1161 	return -(_timezone + _dstbias);
1162     return -_timezone;
1163 #else
1164 #ifdef HAVE_GMTOFF
1165     struct tm t;
1166     time_t time = (time_t)when;
1167     if (localtime_r(&time,&t))
1168 	return t.tm_gmtoff;
1169 #endif
1170 #ifdef HAVE_INT_TZ
1171     return -timezone;
1172 #else
1173     return 0;
1174 #endif
1175 #endif
1176 }
1177 
1178 
1179 static Random s_random;
1180 static Mutex s_randomMutex(false,"Random");
1181 
next()1182 u_int32_t Random::next()
1183 {
1184     return (m_random = (m_random + 1) * 0x8088405);
1185 }
1186 
random()1187 long int Random::random()
1188 {
1189     s_randomMutex.lock();
1190     long int ret = s_random.next() % RAND_MAX;
1191     s_randomMutex.unlock();
1192     return ret;
1193 }
1194 
srandom(unsigned int seed)1195 void Random::srandom(unsigned int seed)
1196 {
1197     s_randomMutex.lock();
1198     s_random.set(seed % RAND_MAX);
1199     s_randomMutex.unlock();
1200 }
1201 
1202 
1203 bool GenObject::s_counting = false;
1204 static ObjCounterList s_counters;
1205 static Mutex s_countersMutex(false,"Counters");
1206 
GenObject()1207 GenObject::GenObject()
1208     : m_counter(0)
1209 {
1210     NamedCounter* counter = Thread::getCurrentObjCounter();
1211     if (counter && counter->enabled())
1212 	setObjCounter(counter);
1213 }
1214 
alive() const1215 bool GenObject::alive() const
1216 {
1217     return true;
1218 }
1219 
destruct()1220 void GenObject::destruct()
1221 {
1222     delete this;
1223 }
1224 
setObjCounter(NamedCounter * counter)1225 NamedCounter* GenObject::setObjCounter(NamedCounter* counter)
1226 {
1227     if (counter == m_counter)
1228 	return counter;
1229     if (s_counters.invalid())
1230 	return 0;
1231     Lock mylock(0);
1232     if (Mutex::count() >= 0)
1233 	mylock.acquire(s_countersMutex);
1234     NamedCounter* oldCounter = m_counter;
1235     if (counter != oldCounter) {
1236 	m_counter = counter;
1237 	mylock.drop();
1238 	if (counter)
1239 	    counter->inc();
1240 	if (oldCounter)
1241 	    oldCounter->dec();
1242     }
1243     return oldCounter;
1244 }
1245 
getObjCounter(const String & name,bool create)1246 NamedCounter* GenObject::getObjCounter(const String& name, bool create)
1247 {
1248     if (name.null() || s_counters.invalid())
1249 	return 0;
1250     Lock mylock(s_countersMutex);
1251     NamedCounter* cnt = static_cast<NamedCounter*>(s_counters[name]);
1252     if (create && !cnt) {
1253 	NamedCounter* saved = Thread::setCurrentObjCounter(0);
1254 	s_counters.append(cnt = new NamedCounter(name));
1255 	Thread::setCurrentObjCounter(saved);
1256     }
1257     return cnt;
1258 }
1259 
getObjCounters()1260 ObjList& GenObject::getObjCounters()
1261 {
1262     return s_counters;
1263 }
1264 
1265 
1266 #ifndef ATOMIC_OPS
1267 static MutexPool s_refMutex(REFOBJECT_MUTEX_COUNT,false,"RefObject");
1268 #endif
1269 
RefObject()1270 RefObject::RefObject()
1271     : m_refcount(1), m_mutex(0)
1272 {
1273 #ifndef ATOMIC_OPS
1274     m_mutex = s_refMutex.mutex(this);
1275 #endif
1276 }
1277 
~RefObject()1278 RefObject::~RefObject()
1279 {
1280     if (m_refcount > 0)
1281 	Debug(DebugFail,"RefObject [%p] destroyed with count=%d",this,m_refcount);
1282 }
1283 
getObject(const String & name) const1284 void* RefObject::getObject(const String& name) const
1285 {
1286     if (name == YATOM("RefObject"))
1287 	return (void*)this;
1288     return GenObject::getObject(name);
1289 }
alive() const1290 bool RefObject::alive() const
1291 {
1292     return m_refcount > 0;
1293 }
1294 
destruct()1295 void RefObject::destruct()
1296 {
1297     deref();
1298 }
1299 
ref()1300 bool RefObject::ref()
1301 {
1302 #ifdef ATOMIC_OPS
1303 #ifdef _WINDOWS
1304     if (InterlockedIncrement((LONG*)&m_refcount) > 1)
1305 	return true;
1306     InterlockedDecrement((LONG*)&m_refcount);
1307 #else
1308     if (__sync_add_and_fetch(&m_refcount,1) > 1)
1309 	return true;
1310     __sync_sub_and_fetch(&m_refcount,1);
1311 #endif
1312 #else
1313     Lock lock(m_mutex);
1314     if (m_refcount > 0) {
1315 	++m_refcount;
1316 	return true;
1317     }
1318 #endif
1319     return false;
1320 }
1321 
deref()1322 bool RefObject::deref()
1323 {
1324 #ifdef ATOMIC_OPS
1325 #ifdef _WINDOWS
1326     int i = InterlockedDecrement((LONG*)&m_refcount) + 1;
1327     if (i <= 0)
1328 	InterlockedIncrement((LONG*)&m_refcount);
1329 #else
1330     int i = __sync_fetch_and_sub(&m_refcount,1);
1331     if (i <= 0)
1332 	__sync_fetch_and_add(&m_refcount,1);
1333 #endif
1334 #else
1335     m_mutex->lock();
1336     int i = m_refcount;
1337     if (i > 0)
1338 	--m_refcount;
1339     m_mutex->unlock();
1340 #endif
1341     if (i == 1)
1342 	zeroRefs();
1343     else if (i <= 0)
1344 	Debug(DebugFail,"RefObject::deref() called with count=%d [%p]",i,this);
1345     return (i <= 1);
1346 }
1347 
zeroRefs()1348 void RefObject::zeroRefs()
1349 {
1350     destroyed();
1351     delete this;
1352 }
1353 
resurrect()1354 bool RefObject::resurrect()
1355 {
1356 #ifdef ATOMIC_OPS
1357 #ifdef _WINDOWS
1358     if (InterlockedIncrement((LONG*)&m_refcount) == 1)
1359 	return true;
1360     InterlockedDecrement((LONG*)&m_refcount);
1361     return false;
1362 #else
1363     if (__sync_add_and_fetch(&m_refcount,1) == 1)
1364 	return true;
1365     __sync_sub_and_fetch(&m_refcount,1);
1366     return false;
1367 #endif
1368 #else
1369     m_mutex->lock();
1370     bool ret = (0 == m_refcount);
1371     if (ret)
1372 	m_refcount = 1;
1373     m_mutex->unlock();
1374     return ret;
1375 #endif
1376 }
1377 
destroyed()1378 void RefObject::destroyed()
1379 {
1380 }
1381 
efficientIncDec()1382 bool RefObject::efficientIncDec()
1383 {
1384 #ifdef ATOMIC_OPS
1385     return true;
1386 #else
1387     return false;
1388 #endif
1389 }
1390 
assign(RefObject * oldptr,RefObject * newptr,void * pointer)1391 void RefPointerBase::assign(RefObject* oldptr, RefObject* newptr, void* pointer)
1392 {
1393     if (oldptr == newptr)
1394 	return;
1395     // Always reference the new object before dereferencing the old one
1396     //  and also don't keep pointers to objects that fail referencing
1397     m_pointer = (newptr && newptr->ref()) ? pointer : 0;
1398     if (oldptr)
1399 	oldptr->deref();
1400 }
1401 
1402 
NamedCounter(const String & name)1403 NamedCounter::NamedCounter(const String& name)
1404     : String(name), m_count(0), m_enabled(getObjCounting()), m_mutex(0)
1405 {
1406 #ifndef ATOMIC_OPS
1407     m_mutex = s_refMutex.mutex(this);
1408 #endif
1409 }
1410 
inc()1411 int NamedCounter::inc()
1412 {
1413 #ifdef ATOMIC_OPS
1414 #ifdef _WINDOWS
1415     return InterlockedIncrement((LONG*)&m_count);
1416 #else
1417     return __sync_add_and_fetch(&m_count,1);
1418 #endif
1419 #else
1420     Lock lock(m_mutex);
1421     return ++m_count;
1422 #endif
1423 }
1424 
dec()1425 int NamedCounter::dec()
1426 {
1427 #ifdef ATOMIC_OPS
1428 #ifdef _WINDOWS
1429     return InterlockedDecrement((LONG*)&m_count);
1430 #else
1431     return __sync_fetch_and_sub(&m_count,1);
1432 #endif
1433 #else
1434     Lock lock(m_mutex);
1435     return --m_count;
1436 #endif
1437 }
1438 
1439 
init()1440 void SysUsage::init()
1441 {
1442     if (!s_startTime)
1443 	s_startTime = Time::now();
1444 }
1445 
startTime()1446 u_int64_t SysUsage::startTime()
1447 {
1448     init();
1449     return s_startTime;
1450 }
1451 
usecRunTime(Type type)1452 u_int64_t SysUsage::usecRunTime(Type type)
1453 {
1454     switch (type) {
1455 	case WallTime:
1456 	    return Time::now() - startTime();
1457 	case UserTime:
1458 	    {
1459 #ifdef _WINDOWS
1460 		FILETIME dummy,ft;
1461 		if (GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&dummy,&ft)) {
1462 		    u_int64_t t = ft.dwLowDateTime | (((u_int64_t)ft.dwHighDateTime) << 32);
1463 		    return t / 10;
1464 		}
1465 #else
1466 		struct rusage usage;
1467 		// FIXME: this is broken, may not sum all threads
1468 		if (!::getrusage(RUSAGE_SELF,&usage))
1469 		    return Time::fromTimeval(usage.ru_utime);
1470 #endif
1471 	    }
1472 	    break;
1473 	case KernelTime:
1474 	    {
1475 #ifdef _WINDOWS
1476 		FILETIME dummy,ft;
1477 		if (GetProcessTimes(GetCurrentProcess(),&dummy,&dummy,&ft,&dummy)) {
1478 		    u_int64_t t = ft.dwLowDateTime | (((u_int64_t)ft.dwHighDateTime) << 32);
1479 		    return t / 10;
1480 		}
1481 #else
1482 		struct rusage usage;
1483 		// FIXME: this is broken, may not sum all threads
1484 		if (!::getrusage(RUSAGE_SELF,&usage))
1485 		    return Time::fromTimeval(usage.ru_stime);
1486 #endif
1487 	    }
1488 	    break;
1489     }
1490     return 0;
1491 }
1492 
msecRunTime(Type type)1493 u_int64_t SysUsage::msecRunTime(Type type)
1494 {
1495     return usecRunTime(type) / 1000;
1496 }
1497 
secRunTime(Type type)1498 u_int32_t SysUsage::secRunTime(Type type)
1499 {
1500     return (u_int32_t)(usecRunTime(type) / 1000000);
1501 }
1502 
runTime(Type type)1503 double SysUsage::runTime(Type type)
1504 {
1505 #ifdef _WINDOWS
1506     // VC++ 6 does not implement conversion from UINT64 to double!
1507     return 0.000001 * (int64_t)usecRunTime(type);
1508 #else
1509     return 0.000001 * usecRunTime(type);
1510 #endif
1511 }
1512 
1513 };
1514 
1515 /* vi: set ts=8 sw=4 sts=4 noet: */
1516