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