CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
Utils.cpp
Go to the documentation of this file.
1
7#ifdef _WIN32
8 // To avoid complaints about fopen and _open
9 #define _CRT_SECURE_NO_WARNINGS
10#endif
11
12#include "Utils.h"
13#include "ObjectIDs.h"
14#include "HTML.h"
15#include "ThreadManager.h"
16#include "UnitTestFramework.h"
17
18#ifdef __APPLE__
19#include <mach/vm_statistics.h>
20#include <mach/host_info.h>
21#include <mach/task_info.h>
22#include <mach/thread_act.h>
23#include <sys/sysctl.h>
24#endif
25
26namespace cmlabs {
27
29// INIT/EXIT //
31
34
38
48
50
53 std::map<std::string, utils::Semaphore*>::iterator si;
54 while (utils::SharedMemorySemaphoreMap->size()) {
56 delete(si->second);
57 utils::SharedMemorySemaphoreMap->erase(si->first);
58 }
64 }
65
68 std::map<std::string, utils::Event*>::iterator ei;
69 while (utils::SharedMemoryEventMap->size()) {
70 ei = utils::SharedMemoryEventMap->begin();
71 delete(ei->second);
72 utils::SharedMemoryEventMap->erase(ei->first);
73 }
79 }
80
83 std::map<std::string, utils::Mutex*>::iterator mi;
84 while (utils::SharedMemoryMutexMap->size()) {
85 mi = utils::SharedMemoryMutexMap->begin();
86 delete(mi->second);
87 utils::SharedMemoryMutexMap->erase(mi->first);
88 }
94 }
95
96 delete(utils::DrumBeatMap);
97 utils::DrumBeatMap = NULL;
98
101
102 delete(utils::Timer::timers);
104
107
108 return true;
109}
110
111utils::CommandLineInfo* utils::CommandLineInfo::CommandLineInfoSingleton = NULL;
112
114// Objects //
116
117std::string GetDataTypeName(uint32 datatype) {
118 switch (datatype) {
119 case CONSTCHARID:
120 return "String";
121 case TIMEID:
122 return "Time";
123 case INTID:
124 return "Integer";
125 case DOUBLEID:
126 return "Float";
127 case CHARDATAID:
128 return "Binary";
129 case DATAMESSAGEID:
130 return "Message";
131 case CONSTCHARINFOID:
132 return "String info";
133 case CHARDATAINFOID:
134 return "Binary info";
136 return "Message info";
137 default:
138 return "Unknown type";
139 }
140}
141
142uint32 GetDataTypeID(const char* typeName) {
143 if ((stricmp(typeName, "string") == 0) || (stricmp(typeName, "text") == 0))
144 return CONSTCHARID;
145 else if (stricmp(typeName, "time") == 0)
146 return CONSTCHARID;
147 else if ((stricmp(typeName, "integer") == 0) || (stricmp(typeName, "int") == 0))
148 return INTID;
149 else if ((stricmp(typeName, "float") == 0) || (stricmp(typeName, "double") == 0))
150 return DOUBLEID;
151 else if (stricmp(typeName, "binary") == 0)
152 return CHARDATAID;
153 else if (stricmp(typeName, "message") == 0)
154 return DATAMESSAGEID;
155 else if (stricmp(typeName, "string info") == 0)
156 return CONSTCHARINFOID;
157 else if (stricmp(typeName, "binary info") == 0)
158 return CHARDATAINFOID;
159 else if (stricmp(typeName, "message info") == 0)
160 return DATAMESSAGEINFOID;
161 else
162 return 0;
163}
164
166// Logging //
168
170 if (!LogSingleton) {
171 LogSingleton = new LogSystem();
172 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
173 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
174 LogSingleton->logReceiverObj = NULL;
175 }
176 LogSingleton->logReceiverObj = rec;
177 return true;
178}
179
181 if (!LogSingleton) {
182 LogSingleton = new LogSystem();
183 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
184 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
185 LogSingleton->logReceiverObj = NULL;
186 }
187 memset(LogSingleton->logLevelDebug, level, LOG_MAXCOUNT);
188 return true;
189}
190
191bool LogSystem::SetLogLevelDebug(uint8 subject, uint8 level) {
192 if (subject >= LOG_MAXCOUNT)
193 return false;
194 if (!LogSingleton) {
195 LogSingleton = new LogSystem();
196 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
197 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
198 LogSingleton->logReceiverObj = NULL;
199 }
200 LogSingleton->logLevelDebug[subject] = level;
201 return true;
202}
203
205 if (!LogSingleton) {
206 LogSingleton = new LogSystem();
207 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
208 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
209 LogSingleton->logReceiverObj = NULL;
210 }
211 memset(LogSingleton->logLevelVerbose, level, LOG_MAXCOUNT);
212 return true;
213}
214
215bool LogSystem::SetLogLevelVerbose(uint8 subject, uint8 level) {
216 if (subject >= LOG_MAXCOUNT)
217 return false;
218 if (!LogSingleton) {
219 LogSingleton = new LogSystem();
220 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
221 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
222 LogSingleton->logReceiverObj = NULL;
223 }
224 LogSingleton->logLevelVerbose[subject] = level;
225 return true;
226}
227
228
230 logfile = NULL;
231 printToStdOut = true;
232}
234 if (logfile)
235 delete [] logfile;
236 logfile = NULL;
237 printToStdOut = true;
238}
239
240const char* LogEntry::getText(uint32& len) {
241 if (len = this->size - sizeof(LogEntry))
242 return (char*)this+sizeof(LogEntry);
243 else
244 return NULL;
245}
246
247bool LogEntry::setText(char* text, uint32 len) {
248 if (!text || !len)
249 return false;
250 int32 avail = (int32)size - sizeof(LogEntry) - 1;
251 if (avail < (int32)len)
252 return false;
253 memcpy((char*)this+sizeof(LogEntry), text, len);
254 *((char*)this+sizeof(LogEntry)+len) = 0;
255 return true;
256}
257
258std::string LogEntry::toJSON() {
259 uint32 len;
260 const char* text = getText(len);
261 return utils::StringFormat(
262 "{ \"time\": %llu, \"level\": %u, \"source\": %u, \"subject\": %u, \"type\": %u, \"text\": \"%s\" }",
263 time, level, source, subject, type, utils::EncodeJSON(text).c_str());
264}
265
266std::string LogEntry::toXML() {
267 uint32 len;
268 const char* text = getText(len);
269 return utils::StringFormat(
270 "<entry time=\"%llu\" level=\"%u\" source=\"%u\" subject=\"%u\" type=\"%u\" text=\"%s\" />\n",
271 time, level, source, subject, type, html::EncodeHTML(text).c_str());
272}
273
274
275bool LogSystem::SetLogFileOutput(const char* logfile, bool printOut) {
276
277 if (!LogSingleton) {
278 LogSingleton = new LogSystem();
279 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
280 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
281 LogSingleton->logReceiverObj = NULL;
282 }
283
284 uint32 len;
285 if (!logfile || !(len = (uint32)strlen(logfile))) {
286 if (LogSingleton->logfile) {
287 delete [] LogSingleton->logfile;
288 LogSingleton->logfile = NULL;
289 }
290 }
291 else {
292 if (LogSingleton->logfile)
293 delete [] LogSingleton->logfile;
294 LogSingleton->logfile = new char[len+1];
295 utils::strcpyavail(LogSingleton->logfile, logfile, len+1, true);
296 }
297 LogSingleton->printToStdOut = printOut;
298 return true;
299}
300
301//#pragma data_seg(".shared") // Begin the shared data segment.
303//#pragma data_seg() // End the shared data segment
304//#pragma comment(linker, "/section:.shared,RWS")
305
306bool LogSystem::LogSystemPrint(uint32 source, uint8 subject, uint8 level, const char *formatstring, ... ) {
307
308 if (!LogSingleton) {
309 LogSingleton = new LogSystem();
310 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
311 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
312 LogSingleton->logReceiverObj = NULL;
313 }
314
315 LogEntry* entry;
316 char* str;
317 uint32 len;
318 bool res = true;
319
320 if (LogSingleton->logLevelVerbose[subject] >= level) {
321 va_list args;
322 va_start(args, formatstring);
323 str = utils::StringFormatVA(len, formatstring, args);
324 va_end(args);
325 if (!str || !len)
326 res = false;
327 else {
328 if (LogSingleton->logReceiverObj) {
329 entry = (LogEntry*) malloc(sizeof(LogEntry)+len+1);
330 entry->size = sizeof(LogEntry)+len+1;
331 entry->cid = LOGENTRYID;
332 entry->time = GetTimeNow();
333 entry->source = source;
334 entry->subject = subject;
335 entry->level = level;
336 entry->type = LOGPRINT;
337 entry->setText(str, len);
338 free(str);
339 return LogSingleton->logReceiverObj->logEntry(entry);
340 }
341 if (LogSingleton->logfile || LogSingleton->printToStdOut) {
342 std::string strline = utils::StringFormat("%s %s\n", PrintTimeNowString().c_str(), str);
343 if (LogSingleton->logfile && strlen(LogSingleton->logfile))
344 utils::AppendToAFile(LogSingleton->logfile, strline.c_str(), (uint32)strline.length());
345 if (LogSingleton->printToStdOut)
346 std::cout << strline;
347 }
348 }
349 free(str);
350 }
351 return res;
352}
353
354bool LogSystem::LogSystemDebug(uint32 source, uint8 subject, uint8 level, const char *formatstring, ... ) {
355
356 if (!LogSingleton) {
357 LogSingleton = new LogSystem();
358 memset(LogSingleton->logLevelVerbose, 1, LOG_MAXCOUNT);
359 memset(LogSingleton->logLevelDebug, 0, LOG_MAXCOUNT);
360 LogSingleton->logReceiverObj = NULL;
361 }
362
363 LogEntry* entry;
364 char* str;
365 uint32 len;
366 bool res = true;
367
368 if (LogSingleton->logLevelDebug[subject] >= level) {
369 va_list args;
370 va_start(args, formatstring);
371 str = utils::StringFormatVA(len, formatstring, args);
372 va_end(args);
373 if (!str || !len)
374 res = false;
375 else {
376 if (LogSingleton->logReceiverObj) {
377 entry = (LogEntry*) malloc(sizeof(LogEntry)+len+1);
378 entry->size = sizeof(LogEntry)+len+1;
379 entry->cid = LOGENTRYID;
380 entry->time = GetTimeNow();
381 entry->source = source;
382 entry->subject = subject;
383 entry->level = level;
384 entry->type = LOGDEBUG;
385 entry->setText(str, len);
386 free(str);
387 return LogSingleton->logReceiverObj->logEntry(entry);
388 }
389 else
390 std::cout << PrintTimeNowString() << " [DEBUG] " << str << std::endl;
391 }
392 free(str);
393 }
394 return res;
395}
396
397#ifdef __APPLE__
398 /*
399 * A pthread_mutex_timedlock() impl for OSX/macOS, which lacks the
400 * real thing.
401 * NOTE: Unlike the real McCoy, won't return EOWNERDEAD, EDEADLK
402 * or EOWNERDEAD
403 */
404 static int macos_pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout)
405 {
406 // abs_timeout is an ABSOLUTE deadline (CalcTimeout builds it from
407 // gettimeofday()). The previous implementation mistook it for a relative
408 // "remaining" duration and initialised its countdown to the absolute
409 // epoch time (~1.78e9 s), so the deadline check effectively never fired
410 // and mutex.enter(timeoutMS) would wait FOREVER whenever the lock was
411 // actually held by another thread - a process-wide latent hang on macOS.
412 // Compare the real clock against the deadline and poll trylock instead.
413 int rv;
414 while ((rv = pthread_mutex_trylock(mutex)) == EBUSY) {
415 struct timeval now;
416 gettimeofday(&now, NULL);
417 if (now.tv_sec > abs_timeout->tv_sec ||
418 (now.tv_sec == abs_timeout->tv_sec &&
419 (long)(now.tv_usec) * 1000L >= abs_timeout->tv_nsec))
420 return ETIMEDOUT;
421 struct timespec nap = { 0, 1000000 }; // poll every 1ms
422 nanosleep(&nap, NULL);
423 }
424 return rv;
425 }
426#endif
427
428
429namespace utils {
430
431#ifndef WINDOWS
432//#if defined LINUX
433 bool CalcTimeout(struct timespec &timeout, uint32 ms) {
434 struct timeval now;
435 if (gettimeofday(&now, NULL) != 0)
436 return false;
437
438 timeout.tv_sec = now.tv_sec + (ms / 1000);
439 int64 us = (int64)(now.tv_usec) + ((ms % 1000)*1000);
440 while (us >= 1000000) {
441 timeout.tv_sec++;
442 us -= 1000000;
443 }
444 timeout.tv_nsec = (long)(us * 1000); // usec -> nsec
445 return true;
446 }
447
448 uint64 GetTime() {
449 struct timeval tv;
450 if ( gettimeofday(&tv, NULL))
451 return 0;
452 return (tv.tv_usec + tv.tv_sec * 1000000LL);
453 }
454#endif
455
456// https://stackoverflow.com/questions/44807302/create-c-timer-in-macos/52905687#52905687
457
458#ifdef WINDOWS
459 VOID CALLBACK DrumBeatCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired) {
460 DrumBeatInfo* info = (DrumBeatInfo*) lpParameter;
461 DrumBeatFunc func = info->func;
462 if (!info->id || !info->createdTime || !info->started || !func)
463 return;
464 info->count++;
465 if (!info->func(info->id, info->count))
466 StopDrumBeat(info->id);
467 }
468#else
469 #ifndef __APPLE__
470 static void DrumBeatCallback(union sigval p) {
471 DrumBeatInfo* info = (DrumBeatInfo*) p.sival_ptr;
472 DrumBeatFunc func = info->func;
473 if (!info->id || !info->createdTime || !info->started || !func)
474 return;
475 info->count++;
476 if (!info->func(info->id, info->count))
477 StopDrumBeat(info->id);
478 }
479 #endif
480#endif
481
482bool CreateDrumBeat(uint32 id, uint32 interval, DrumBeatFunc func, bool autostart) {
483
484 if (!DrumBeatMap)
485 DrumBeatMap = new std::map<uint32, DrumBeatInfo>;
486 DrumBeatInfo* info = &(*DrumBeatMap)[id];
487
488 // check if it already exists
489 if (info->id && info->createdTime)
490 return false;
491
492 // Windows threadpool size limit is 500, we probably shouldn't create more than that anyway
493 // Could change the limit with WT_SET_MAX_THREADPOOL_THREAD
494 if (DrumBeatMap->size() > 450)
495 return false;
496
497 info->id = id;
498 info->createdTime = GetTimeNow();
499 info->func = func;
500 info->count = 0;
501 info->interval = interval;
502
503 #ifdef WINDOWS
504 #else
505 #ifdef __APPLE__
506 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
507 dispatch_source_t timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
508 if (timer_source)
509 info->handle = timer_source;
510 #else
511 // struct sigaction sa;
512 struct sigevent timer_event;
513
514 //sigemptyset(&sa.sa_mask);
515 //sa.sa_flags = SA_SIGINFO; /* Real-Time signal */
516 //sa.sa_sigaction = timer_signal_handler;
517 //sigaction(SIGRTMIN, &sa, NULL);
518
519 timer_event.sigev_notify = SIGEV_THREAD;
520 timer_event.sigev_notify_attributes = NULL;
521 timer_event.sigev_notify_function = DrumBeatCallback;
522 timer_event.sigev_value.sival_ptr = (void *)info;
523 int ret = timer_create(CLOCK_REALTIME, &timer_event, &info->handle);
524 if (ret != 0) {
525 LogPrint(0,LOG_SYSTEM,0,"Error creating timer: %d", ret);
526 }
527 #endif
528 #endif
529
530 if (autostart)
531 StartDrumBeat(id);
532 return true;
533}
534
535bool StartDrumBeat(uint32 id) {
536 if (!DrumBeatMap)
537 return false;
538 DrumBeatInfo* info = &(*DrumBeatMap)[id];
539 if (!info->id || !info->createdTime)
540 return false;
541
542 if (info->started)
543 return true;
544
545 #ifdef WINDOWS
546 // To compile an application that uses this function, define _WIN32_WINNT as 0x0500 or later
547 CreateTimerQueueTimer(&info->handle, NULL, DrumBeatCallback, info, info->interval, info->interval, WT_EXECUTEINTIMERTHREAD);
548 info->started = info->createdTime;
549 #else
550 #ifdef __APPLE__
551 if (info->handle) {
552 uint64 intervalNs = (uint64)info->interval * 1000000;
553 dispatch_source_set_timer(info->handle, dispatch_time(DISPATCH_TIME_NOW, (int64_t)intervalNs), intervalNs, 0);
554 DrumBeatInfo* inf = info;
555 dispatch_source_set_event_handler(info->handle, ^{
556 inf->count++;
557 if (!inf->func(inf->id, inf->count))
558 StopDrumBeat(inf->id);
559 });
560 dispatch_resume(info->handle);
561 info->started = info->createdTime;
562 }
563 #else
564 struct itimerspec newtv;
565 uint64 p = info->interval * 1000; // convert to nanosec
566 newtv.it_interval.tv_sec = p / 1000000;
567 newtv.it_interval.tv_nsec = (p % 1000000)*1000;
568 newtv.it_value.tv_sec = p / 1000000;
569 newtv.it_value.tv_nsec = (p % 1000000)*1000;
570
571 int ret = timer_settime(info->handle, 0, &newtv, NULL);
572 if (ret != 0) {
573 LogPrint(0,LOG_SYSTEM,0,"Error arming timer: %d", ret);
574 }
575 info->started = info->createdTime;
576 #endif
577 #endif
578 return true;
579}
580
581bool StopDrumBeat(uint32 id) {
582 if (!DrumBeatMap)
583 return false;
584 DrumBeatInfo* info = &(*DrumBeatMap)[id];
585 if (!info->id || !info->createdTime)
586 return false;
587
588 if (!info->started)
589 return true;
590
591 #ifdef WINDOWS
592 DeleteTimerQueueTimer(NULL, info->handle, NULL);
593 info->started = 0;
594 info->handle = NULL;
595 #else
596 #ifdef __APPLE__
597 if (info->handle) {
598 dispatch_suspend(info->handle);
599 info->started = 0;
600 }
601 #else
602 struct itimerspec newtv;
603 memset(&newtv, 0, sizeof(itimerspec));
604 int ret = timer_settime(info->handle, 0, &newtv, NULL);
605 if (ret != 0) {
606 LogPrint(0,LOG_SYSTEM,0,"Error arming timer: %d", ret);
607 }
608 info->started = 0;
609 #endif
610 #endif
611 return true;
612}
613
614bool EndDrumBeat(uint32 id) {
615 if (!DrumBeatMap)
616 return false;
617 DrumBeatInfo* info = &(*DrumBeatMap)[id];
618 if (!info->id || !info->createdTime)
619 return false;
620
621 #ifdef WINDOWS
622 if (info->started)
623 StopDrumBeat(id);
624 #else
625 #ifdef __APPLE__
626 if (info->handle) {
627 if (info->started)
628 dispatch_suspend(info->handle);
629 dispatch_source_cancel(info->handle);
630 dispatch_release(info->handle);
631 info->handle = NULL;
632 info->started = 0;
633 }
634 #else
635 timer_delete(info->handle);
636 info->started = 0;
637 info->handle = 0;
638 #endif
639 #endif
640
641 info->createdTime = 0;
642 info->func = NULL;
643 info->count = 0;
644 info->interval = 0;
645 return true;
646}
647
648
649bool EnterMutex(const char* name, uint32 ms, bool autocreate) {
651 SharedMemoryMutexMap = new std::map<std::string, Mutex*>;
654
655 Mutex* mutex;
656 std::map<std::string, Mutex*>::iterator i = SharedMemoryMutexMap->find(name);
657 std::map<std::string, Mutex*>::iterator e = SharedMemoryMutexMap->end();
658 if (i == e) {
660 i = SharedMemoryMutexMap->find(name);
661 if (i == e) {
662 if (!autocreate) {
664 return false;
665 }
666 mutex = new Mutex(name);
668 }
669 else {
670 // try again
671 if (i->second)
672 mutex = i->second;
673 else {
674 if (!autocreate) {
676 return false;
677 }
678 mutex = new Mutex(name);
680 }
681 }
683 }
684 else
685 mutex = i->second;
686 return (mutex->enter(ms));
687}
688
689bool LeaveMutex(const char* name) {
691 SharedMemoryMutexMap = new std::map<std::string, Mutex*>;
694
695 std::map<std::string, Mutex*>::iterator i = SharedMemoryMutexMap->find(name);
696 std::map<std::string, Mutex*>::iterator e = SharedMemoryMutexMap->end();
697 if (i == e)
698 return false;
699 return (i->second->leave());
700}
701
702bool DestroyMutex(const char* name) {
704 SharedMemoryMutexMap = new std::map<std::string, Mutex*>;
708
709 std::map<std::string, Mutex*>::iterator i = SharedMemoryMutexMap->find(name);
710 std::map<std::string, Mutex*>::iterator e = SharedMemoryMutexMap->end();
711 if (i == e)
712 return false;
713 delete(i->second);
714 SharedMemoryMutexMap->erase(i);
716 return true;
717}
718
719
720
721
722
723
724
725
726Semaphore* GetSemaphore(const char* name, bool autocreate) {
728 SharedMemorySemaphoreMap = new std::map<std::string, Semaphore*>;
731 Semaphore* semaphore;
732 std::map<std::string, Semaphore*>::iterator i = SharedMemorySemaphoreMap->find(name);
733 std::map<std::string, Semaphore*>::iterator e = SharedMemorySemaphoreMap->end();
734 if (i == e) {
736 i = SharedMemorySemaphoreMap->find(name);
737 if (i == e) {
738 if (!autocreate) {
740 return NULL;
741 }
742 semaphore = new Semaphore(name);
744 }
745 else {
746 // try again
747 if (i->second)
748 semaphore = i->second;
749 else {
750 if (!autocreate) {
752 return NULL;
753 }
754 semaphore = new Semaphore(name);
756 }
757 }
759 }
760 else
761 semaphore = i->second;
762 return semaphore;
763}
764
765bool WaitForSemaphore(const char* name, uint32 ms, bool autocreate) {
767 SharedMemorySemaphoreMap = new std::map<std::string, Semaphore*>;
770 Semaphore* semaphore;
771 std::map<std::string, Semaphore*>::iterator i = SharedMemorySemaphoreMap->find(name);
772 std::map<std::string, Semaphore*>::iterator e = SharedMemorySemaphoreMap->end();
773 if (i == e) {
775 i = SharedMemorySemaphoreMap->find(name);
776 if (i == e) {
777 if (!autocreate) {
779 return false;
780 }
781 semaphore = new Semaphore(name);
783 }
784 else {
785 // try again
786 if (i->second)
787 semaphore = i->second;
788 else {
789 if (!autocreate) {
791 return false;
792 }
793 semaphore = new Semaphore(name);
795 }
796 }
798 }
799 else
800 semaphore = i->second;
801 return (semaphore->wait(ms));
802}
803
804bool SignalSemaphore(const char* name) {
806 SharedMemorySemaphoreMap = new std::map<std::string, Semaphore*>;
809
810 Semaphore* semaphore;
811 std::map<std::string, Semaphore*>::iterator i = SharedMemorySemaphoreMap->find(name);
812 std::map<std::string, Semaphore*>::iterator e = SharedMemorySemaphoreMap->end();
813 if (i == e) {
815 i = SharedMemorySemaphoreMap->find(name);
816 if (i == e) {
817 semaphore = new Semaphore(name);
819 }
820 else {
821 // try again
822 if (i->second)
823 semaphore = i->second;
824 else {
825 semaphore = new Semaphore(name);
827 }
828 }
830 }
831 else
832 semaphore = i->second;
833 return (semaphore->signal());
834}
835
836bool DestroySemaphore(const char* name) {
838 SharedMemorySemaphoreMap = new std::map<std::string, Semaphore*>;
842
843 std::map<std::string, Semaphore*>::iterator i = SharedMemorySemaphoreMap->find(name);
844 std::map<std::string, Semaphore*>::iterator e = SharedMemorySemaphoreMap->end();
845 if (i == e) {
847 return false;
848 }
849 delete(i->second);
850 SharedMemorySemaphoreMap->erase(i);
852 return true;
853}
854
855
856
857
858
859
860
861
862
863
864
865bool WaitForNextEvent(const char* name, uint32 ms, bool autocreate) {
867 SharedMemoryEventMap = new std::map<std::string, Event*>;
870 Event* event;
871 std::map<std::string, Event*>::iterator i = SharedMemoryEventMap->find(name);
872 std::map<std::string, Event*>::iterator e = SharedMemoryEventMap->end();
873 if (i == e) {
875 i = SharedMemoryEventMap->find(name);
876 if (i == e) {
877 if (!autocreate) {
879 return false;
880 }
881 event = new Event(name);
883 }
884 else {
885 // try again
886 if (i->second)
887 event = i->second;
888 else {
889 if (!autocreate) {
891 return false;
892 }
893 event = new Event(name);
895 }
896 }
898 }
899 else
900 event = i->second;
901 return (event->waitNext(ms));
902}
903
904bool SignalEvent(const char* name) {
906 SharedMemoryEventMap = new std::map<std::string, Event*>;
909 std::map<std::string, Event*>::iterator i = SharedMemoryEventMap->find(name);
910 std::map<std::string, Event*>::iterator e = SharedMemoryEventMap->end();
911 if (i == e)
912 return false;
913 else
914 return (i->second->signal());
915}
916
917bool DestroyEvent(const char* name) {
919 SharedMemoryEventMap = new std::map<std::string, Event*>;
923
924 std::map<std::string, Event*>::iterator i = SharedMemoryEventMap->find(name);
925 std::map<std::string, Event*>::iterator e = SharedMemoryEventMap->end();
926 if (i == e)
927 return false;
928 delete(i->second);
929 SharedMemoryEventMap->erase(i);
931 return true;
932}
933
934
935
936
937
938bool SetSharedSystemInstance(uint32 inst) {
940 return true;
941}
942
946
947
949 //uint32 tt;
950 //utils::GetCurrentThreadOSID(tt);
951 //printf("Mutex[%p] create by thread: %u\n", this, tt);
952 name = NULL;
953 osid = 0;
954 count = 0;
955 total = 0;
956 created = true;
957 #ifdef WINDOWS
958 mutex = ::CreateMutex(NULL, FALSE, NULL);
959 #else
960 mutex = new pthread_mutex_t;
961 pthread_mutexattr_t attr;
962 pthread_mutexattr_init(&attr);
963 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
964 pthread_mutex_init(mutex, &attr);
965
966 //semaphore = new sem_t;
967 //if (sem_init(semaphore, 0, 1) != 0) {
968 // delete(semaphore);
969 // semaphore = NULL;
970 //}
971
972 pthread_mutexattr_destroy(&attr);
973 #endif
974}
975
976Mutex::Mutex(const char* name, bool force) {
977 this->name = new char[MAXSHMEMNAMELEN];
978 osid = 0;
979 count = 0;
980 total = 0;
981 created = true;
982 #ifdef WINDOWS
983 //sprintf(this->name, "Global\\Mutex_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
984 snprintf(this->name, MAXSHMEMNAMELEN, "%s\\Mutex_%s", WINSHMEMSPACE, name);
985 mutex = ::CreateMutex(NULL, FALSE, this->name);
986 #else
987 mutex = NULL;
988// sprintf(this->name, "/Cond_%s", name);
989// semaphore = sem_open(name, O_CREAT, 0666, 1);
990
991 snprintf(this->name, MAXSHMEMNAMELEN, "Mutex_%s", name);
992
993 // test if shared memory exists
994 char* data = NULL;
995
996 if (!force)
997 data = OpenSharedMemorySegment(this->name, MUTEXMEMSIZE);
998 if (data) {
999 mutex = (pthread_mutex_t*) data;
1000 created = false;
1001 }
1002 else {
1003 // create shared mutex
1004 if (data = CreateSharedMemorySegment(this->name, MUTEXMEMSIZE, force)) {
1005 // create mutex
1006 mutex = (pthread_mutex_t*) data;
1007 pthread_mutexattr_t attr;
1008 pthread_mutexattr_init(&attr);
1009 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1010 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1011 pthread_mutex_init(mutex, &attr);
1012 pthread_mutexattr_destroy(&attr);
1013 }
1014 }
1015 #endif
1016}
1017
1018#ifdef WINDOWS
1019bool CloseMutexHandle(HANDLE mutex) {
1020 // had to do this to catch exceptions in 32-bit Windows
1021 // as using __try+__except in C++ objects gave linker error
1022 __try {
1023 CloseHandle(mutex);
1024 }
1025 __except (EXCEPTION_EXECUTE_HANDLER) {
1026 }
1027 return true;
1028}
1029#endif
1030
1032 //uint32 tt;
1033 //utils::GetCurrentThreadOSID(tt);
1034 //printf("Mutex[%p] DELETE by thread: %u\n", this, tt);
1035 #ifdef WINDOWS
1036 if (mutex == NULL)
1037 return;
1038
1039 CloseMutexHandle(mutex);
1040 mutex = NULL;
1041 delete [] name;
1042 #else
1043 if (!name) {
1044 pthread_mutex_destroy(mutex);
1045 // sem_destroy(semaphore);
1046 // delete(semaphore);
1047 }
1048 else {
1049 if (created)
1050 pthread_mutex_destroy(mutex);
1052 mutex = NULL;
1053 // sem_close(semaphore);
1054 delete [] name;
1055 }
1056 #endif
1057}
1058
1060 #ifdef WINDOWS
1061 DWORD reply;
1062 if ( (reply = WaitForSingleObject(mutex, INFINITE)) == WAIT_OBJECT_0) {
1064// if (count)
1065// int n=0;
1066 count++;
1067 total++;
1068 return true;
1069 }
1070 else {
1071 if (reply != WAIT_ABANDONED) {
1072 //if (name)
1073 // LogPrint(0, LOG_SYSTEM, 0, "Lock of mutex failed: %s", name);
1074 //else
1075 // LogPrint(0, LOG_SYSTEM, 0, "Lock of unnamed mutex failed");
1076 }
1077 return false;
1078 }
1079 #else
1080 int error = pthread_mutex_lock(mutex);
1081 if (error == 0) {
1083 count++;
1084 return true;
1085 }
1086 else {
1087 LogPrint(0, LOG_SYSTEM, 0, "Lock of mutex failed: %s (%d)", name ? name : "-", error);
1088 return false;
1089 }
1090 #endif
1091}
1092
1093bool Mutex::enter(uint32 timeout, const char* errorMsg) {
1094// printf("*** %s ***\n", errorMsg);
1095// uint32 tt;
1096// utils::GetCurrentThreadOSID(tt);
1097// printf("Mutex[%p] locking by thread: %u\n", this, tt);
1098
1099 #ifdef WINDOWS
1100 DWORD reply;
1101 if ((reply = WaitForSingleObject(mutex, timeout)) == WAIT_OBJECT_0) {
1103 //if (count)
1104 // printf("*** [%u]Mutex[%p](%s) locked more than once: %u\n", osid, mutex, errorMsg, count);
1105 //else
1106 // printf("--- [%u]Mutex[%p](%s) locked\n", osid, mutex, errorMsg);
1107 // if (count)
1108 // printf("Mutex[%p] double locking by thread: %u\n", this, tt);
1109
1110 count++;
1111 total++;
1112 return true;
1113 }
1114 //if (errorMsg) {
1115 uint32 osid2;
1117 if (reply == WAIT_TIMEOUT) {
1118 LogPrint(0, LOG_SYSTEM, 0, "[%u]Mutex enter timeout[%p](%s) - currently held by %u, count %u, total %u",
1119 osid2, mutex, errorMsg ? errorMsg : "-", osid, count, total);
1120 //if (!errorMsg)
1121 // int n = 0;
1122 }
1123 else if (reply == WAIT_FAILED) {
1124 DWORD mtxErr = GetLastError();
1125 if (mtxErr == ERROR_INVALID_HANDLE)
1126 return true;
1127 char* msg = new char[2048];
1128 int length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1129 NULL, mtxErr, 0, msg, 2048, NULL);
1130 msg[length] = '\0';
1131 LogPrint(0, LOG_SYSTEM, 0, "[%u]Mutex enter failed[%p](%s): %s - currently held by %u, count %u, total %u",
1132 osid2, mutex, errorMsg ? errorMsg : "-", msg, osid, count, total);
1133 delete[] msg;
1134 }
1135 else
1136 //[36136]Mutex enter error[00000000000016E0](-): 4294967295 - currently held by 0, count 0, total 7
1137 LogPrint(0,LOG_SYSTEM,0,"[%u]Mutex enter error[%p](%s): %d - currently held by %u, count %u, total %u",
1138 osid2, mutex, errorMsg ? errorMsg : "-", reply, osid, count, total);
1139 //}
1140 return false;
1141 #else
1142 struct timespec ts;
1143 CalcTimeout(ts, timeout);
1144 #ifdef __APPLE__
1145 int error = macos_pthread_mutex_timedlock(mutex, &ts);
1146 #else
1147 int error = pthread_mutex_timedlock(mutex, &ts);
1148 #endif
1149 if (error == 0) {
1151 count++;
1152 // if (count > 1)
1153 // printf("Lock count now %u...\n", count);
1154 // LogPrint(0,LOG_SYSTEM,0,"Mutex enter success: '%s' (%d) [%p] - I am %u", errorMsg, error, this, osid);
1155 return true;
1156 }
1157 else if (error == EINVAL) {
1158 LogPrint(0,LOG_SYSTEM,0,"Mutex enter error: '%s' (%d) [%u = %llu.%lld]",
1159 errorMsg ? errorMsg : "-", error, timeout, (uint64)(ts.tv_sec), (int64)(ts.tv_nsec));
1160 return false;
1161 }
1162// if (errorMsg)
1163 LogPrint(0,LOG_SYSTEM,0,"Mutex enter timeout %u: '%s' (%d) [%p] - held by %u", timeout, errorMsg ? errorMsg : "-", error, this, osid);
1164 return false;
1165
1166 //if (pthread_mutex_trylock(mutex) == 0)
1167 // return true;
1168
1169 //printf("[w-%s]", errorMsg);
1170 //fflush(stdout);
1172 //uint64 start = GetTimeNow();
1173 //struct timespec ts;
1174 //CalcTimeout(ts, timeout);
1175
1176 //int res = 1;
1177 //do {
1178 // if (sem_timedwait(semaphore, &ts) != 0)
1179 // break;
1180 // res = pthread_mutex_trylock(mutex);
1181 //} while ( !res && (GetTimeAgeMS(start) < (int32)timeout) );
1182
1183 //if (res) {
1184 // printf("s");
1185 // fflush(stdout);
1186 // return true;
1187 //}
1188 //if (errorMsg)
1189 // LogPrint(0,LOG_SYSTEM,0,"Mutex enter timeout: %s", errorMsg);
1190 //return false;
1191 #endif
1192}
1193
1195// uint32 tt;
1196// utils::GetCurrentThreadOSID(tt);
1197// printf("Mutex[%p] leaving by thread: %u\n", this, tt);
1198 #ifdef WINDOWS
1199 uint32 osid2 = osid;
1200 //utils::GetCurrentThreadOSID(osid2);
1201 //else
1202 // return true;
1203 //if (osid != osid2)
1204 // printf("*** [%u]Mutex[%p] unlocked by someone else: %u\n", osid, mutex, osid2);
1205 //if (!count)
1206 // osid = 0;
1207 if (ReleaseMutex(mutex) != 0) {
1208 if (count)
1209 count--;
1210 if (!count)
1211 osid = 0;
1212 //else
1213 // printf("Mutex[%p] double release by thread: %u\n", this, tt);
1214 //osid = 0;
1215 return true;
1216 }
1217 else {
1218 // reinstate values
1219 //count++;
1220 osid = osid2;
1221 return false;
1222 }
1223 #else
1224 if (pthread_mutex_unlock(mutex) != 0)
1225 return false;
1226 else {
1227 osid = 0;
1228 count--;
1229 return true;
1230 }
1231
1232 // Signal semaphore
1233 // return (sem_post(semaphore) == 0);
1234 #endif
1235}
1236
1237//bool Mutex::destroy() {
1238// #ifdef WINDOWS
1239// #else
1240// pthread_mutex_destroy(mutex);
1241// DestroySharedMemorySegment((char*)mutex, MUTEXMEMSIZE);
1242// mutex = NULL;
1243// sem_unlink(name);
1244// #endif
1245// return true;
1246//}
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260Semaphore::Semaphore(uint32 maxCount) {
1261 name = NULL;
1262 #ifdef WINDOWS
1263 semaphore = CreateSemaphore(
1264 NULL, // no security attributes
1265 0, // initial count
1266 10, // maximum count
1267 NULL); // unnamed semaphore
1268 #else
1269 #ifdef __APPLE__
1270 semaphore_impl = dispatch_semaphore_create(0);
1271 #else
1272 semaphore = new sem_t;
1273 if (sem_init(semaphore, 0, 0) != 0) {
1274 delete(semaphore);
1275 semaphore = NULL;
1276 }
1277 #endif
1278 #endif
1279}
1280
1281Semaphore::Semaphore(const char* name, uint32 maxCount) {
1282 this->name = new char[MAXSHMEMNAMELEN];
1283 #ifdef WINDOWS
1284 //sprintf(this->name, "Global\\Semaphore_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
1285 snprintf(this->name, MAXSHMEMNAMELEN, "%s\\Semaphore_%s", WINSHMEMSPACE, name);
1286 // Creates or gets an existing Semaphore
1287 semaphore = CreateSemaphore(
1288 NULL, // no security attributes
1289 0, // initial count
1290 maxCount, // maximum count
1291 this->name); // unnamed semaphore
1292 #else
1293 #ifdef __APPLE__
1294 char shmemname[MAXSHMEMNAMELEN];
1295 snprintf(shmemname, sizeof(shmemname), "Semaphore_%s", name);
1296 char* data = OpenSharedMemorySegment(shmemname, SEMAPHOREMEMSIZE);
1297 if (!data) {
1298 data = CreateSharedMemorySegment(shmemname, SEMAPHOREMEMSIZE, true);
1299 if (data) {
1300 pthread_mutex_t* m = (pthread_mutex_t*)data;
1301 pthread_mutexattr_t attr;
1302 pthread_mutexattr_init(&attr);
1303 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1304 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1305 pthread_mutex_init(m, &attr);
1306 pthread_mutexattr_destroy(&attr);
1307 pthread_cond_t* c = (pthread_cond_t*)(data + sizeof(pthread_mutex_t));
1308 pthread_condattr_t cattr;
1309 pthread_condattr_init(&cattr);
1310 pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
1311 pthread_cond_init(c, &cattr);
1312 pthread_condattr_destroy(&cattr);
1313 uint32* cnt = (uint32*)(data + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t));
1314 *cnt = 1;
1315 }
1316 }
1317 semaphore_impl = data;
1318 #else
1319 snprintf(this->name, MAXSHMEMNAMELEN, "/Semaphore_%s", name);
1320// sprintf(this->name, "/Semaphore_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
1321 semaphore = sem_open(this->name, O_CREAT, 0666, 1);
1322 if (semaphore == SEM_FAILED)
1323 semaphore = NULL;
1324 #endif
1325 #endif
1326 // Rewrite the original name
1327 utils::strcpyavail(this->name, name, MAXKEYNAMELEN, true);
1328}
1329
1331 #ifdef WINDOWS
1332 if (semaphore) {
1333 CloseHandle(semaphore);
1334 semaphore = NULL;
1335 }
1336 delete [] name;
1337 #else
1338 #ifdef __APPLE__
1339 if (!name) {
1340 if (semaphore_impl)
1341 dispatch_release((dispatch_semaphore_t)semaphore_impl);
1342 semaphore_impl = NULL;
1343 }
1344 else {
1345 if (semaphore_impl) {
1346 CloseSharedMemorySegment((char*)semaphore_impl, SEMAPHOREMEMSIZE);
1347 semaphore_impl = NULL;
1348 }
1349 delete [] name;
1350 }
1351 #else
1352 // printf("Deleting semaphore '%s'...\n", name);
1353 if (!name) {
1354 sem_destroy(semaphore);
1355 delete(semaphore);
1356 }
1357 else {
1358 sem_close(semaphore);
1359 delete [] name;
1360 }
1361 #endif
1362 #endif
1363}
1364
1366 #ifdef WINDOWS
1367 return (WaitForSingleObject(semaphore, INFINITE) == WAIT_OBJECT_0);
1368 #else
1369 #ifdef __APPLE__
1370 if (!name)
1371 return dispatch_semaphore_wait((dispatch_semaphore_t)semaphore_impl, DISPATCH_TIME_FOREVER) == 0;
1372 else {
1373 char* data = (char*)semaphore_impl;
1374 if (!data) return false;
1375 pthread_mutex_t* m = (pthread_mutex_t*)data;
1376 pthread_cond_t* c = (pthread_cond_t*)(data + sizeof(pthread_mutex_t));
1377 uint32* cnt = (uint32*)(data + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t));
1378 pthread_mutex_lock(m);
1379 while (*cnt == 0)
1380 pthread_cond_wait(c, m);
1381 (*cnt)--;
1382 pthread_mutex_unlock(m);
1383 return true;
1384 }
1385 #else
1386 int r = sem_wait(semaphore);
1387 return r == 0;
1388 #endif
1389 #endif
1390}
1391
1392bool Semaphore::wait(uint32 timeout) {
1393 #ifdef WINDOWS
1394 return (WaitForSingleObject(semaphore, timeout) == WAIT_OBJECT_0);
1395 #else
1396 #ifdef __APPLE__
1397 if (!name) {
1398 dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeout * 1000000);
1399 return dispatch_semaphore_wait((dispatch_semaphore_t)semaphore_impl, when) == 0;
1400 }
1401 else {
1402 char* data = (char*)semaphore_impl;
1403 if (!data) return false;
1404 pthread_mutex_t* m = (pthread_mutex_t*)data;
1405 pthread_cond_t* c = (pthread_cond_t*)(data + sizeof(pthread_mutex_t));
1406 uint32* cnt = (uint32*)(data + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t));
1407 pthread_mutex_lock(m);
1408 struct timespec t;
1409 CalcTimeout(t, timeout);
1410 while (*cnt == 0) {
1411 int r = pthread_cond_timedwait(c, m, &t);
1412 if (r == ETIMEDOUT) {
1413 pthread_mutex_unlock(m);
1414 return false;
1415 }
1416 if (r != 0) {
1417 pthread_mutex_unlock(m);
1418 return false;
1419 }
1420 }
1421 (*cnt)--;
1422 pthread_mutex_unlock(m);
1423 return true;
1424 }
1425 #else
1426 struct timespec t;
1427 CalcTimeout(t, timeout);
1428 int r = sem_timedwait(semaphore, &t);
1429 return r == 0;
1430 #endif
1431 #endif
1432}
1433
1435 #ifdef WINDOWS
1436 return (ReleaseSemaphore(
1437 semaphore, // handle to semaphore
1438 1, // increase count by one
1439 NULL) != 0); // not interested in previous count
1440 #else
1441 #ifdef __APPLE__
1442 if (!name)
1443 return dispatch_semaphore_signal((dispatch_semaphore_t)semaphore_impl) != 0;
1444 else {
1445 char* data = (char*)semaphore_impl;
1446 if (!data) return false;
1447 pthread_mutex_t* m = (pthread_mutex_t*)data;
1448 pthread_cond_t* c = (pthread_cond_t*)(data + sizeof(pthread_mutex_t));
1449 uint32* cnt = (uint32*)(data + sizeof(pthread_mutex_t) + sizeof(pthread_cond_t));
1450 pthread_mutex_lock(m);
1451 (*cnt)++;
1452 pthread_cond_signal(c);
1453 pthread_mutex_unlock(m);
1454 return true;
1455 }
1456 #else
1457 int r = sem_post(semaphore);
1458 return (r == 0);
1459 #endif
1460 #endif
1461}
1462
1463//bool Semaphore::destroy() {
1464// #ifdef WINDOWS
1465// return true;
1466// #else
1467// if (name)
1468// sem_unlink(name);
1469// return true;
1470// #endif
1471//}
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1486 name = NULL;
1487 #ifdef WINDOWS
1488 event = CreateEvent(
1489 NULL, // default security attributes
1490 TRUE, // manual-reset event
1491 FALSE, // initial state is nonsignaled
1492 NULL); // object name
1493 #else
1494 event = new pthread_cond_t;
1495 pthread_cond_init(event, NULL);
1496
1497 mutex = new pthread_mutex_t;
1498 pthread_mutex_init(mutex, NULL);
1499 #endif
1500}
1501
1502Event::Event(const char* name) {
1503 this->name = new char[MAXSHMEMNAMELEN];
1504 #ifdef WINDOWS
1505 //sprintf(this->name, "Global\\Event_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
1506 snprintf(this->name, MAXSHMEMNAMELEN, "%s\\Event_%s", WINSHMEMSPACE, name);
1507 // Creates or gets an existing Event
1508 event = CreateEvent(
1509 NULL, // default security attributes
1510 TRUE, // manual-reset event
1511 FALSE, // initial state is nonsignaled
1512 this->name); // object name
1513 #else
1514 char* data = OpenSharedMemorySegment(this->name, EVENTMEMSIZE);
1515 if (data) {
1516 mutex = (pthread_mutex_t*) data;
1517 event = (pthread_cond_t*) (data + sizeof(pthread_mutex_t));
1518 }
1519 else {
1520 // create shared event
1521 if (data = CreateSharedMemorySegment(this->name, EVENTMEMSIZE, true)) {
1522 // create mutex
1523 mutex = (pthread_mutex_t*) data;
1524 pthread_mutexattr_t attr;
1525 pthread_mutexattr_init(&attr);
1526 pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
1527 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1528 pthread_mutex_init(mutex, &attr);
1529 pthread_mutexattr_destroy(&attr);
1530
1531 event = (pthread_cond_t*) (data + sizeof(pthread_mutex_t));
1532 pthread_condattr_t cattr;
1533 pthread_condattr_init(&cattr);
1534 pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
1535 // pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1536 pthread_cond_init(event, &cattr);
1537 pthread_mutexattr_destroy(&attr);
1538 }
1539 }
1540 #endif
1541}
1542
1544 #ifdef WINDOWS
1545 if (event) {
1546 CloseHandle(event);
1547 event = NULL;
1548 }
1549 delete [] name;
1550 #else
1551 if (!name) {
1552 pthread_cond_destroy(event);
1553 delete(event);
1554 pthread_mutex_destroy(mutex);
1555 delete(mutex);
1556 }
1557 else {
1558 pthread_cond_destroy(event);
1559 pthread_mutex_destroy(mutex);
1561 mutex = NULL;
1562 event = NULL;
1563 delete [] name;
1564 }
1565 #endif
1566}
1567
1569 #ifdef WINDOWS
1570 return (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0);
1571 #else
1572 pthread_mutex_lock(mutex);
1573 int r = pthread_cond_wait(event, mutex);
1574 pthread_mutex_unlock(mutex);
1575 return r == 0;
1576 #endif
1577}
1578
1579bool Event::waitNext(uint32 timeout) {
1580 #ifdef WINDOWS
1581 return (WaitForSingleObject(event, timeout) == WAIT_OBJECT_0);
1582 #else
1583 pthread_mutex_lock(mutex);
1584 struct timespec t;
1585 CalcTimeout(t, timeout);
1586 int r = pthread_cond_timedwait(event, mutex, &t);
1587 pthread_mutex_unlock(mutex);
1588 return r == 0;
1589 #endif
1590}
1591
1593 #ifdef WINDOWS
1594 if (!SetEvent(event))
1595 return false;
1596// Sleep(1);
1597 ResetEvent(event);
1598 return true;
1599 #else
1600 pthread_mutex_lock(mutex);
1601 int r = pthread_cond_broadcast(event);
1602 pthread_mutex_unlock(mutex);
1603 return (r == 0);
1604 #endif
1605}
1606
1607//bool Event::destroy() {
1608// #ifdef WINDOWS
1609// return true;
1610// #else
1611// if (name)
1612// sem_unlink(name);
1613// return true;
1614// #endif
1615//}
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630std::map<uint32, Timer*>* Timer::timers = NULL;
1631
1633 if (!timers)
1634 timers = new std::map<uint32, Timer*>;
1635 globalID = 0;
1636 while (timers->find(globalID) != timers->end())
1637 globalID++;
1638 (*timers)[globalID] = this;
1639}
1640
1642 if (!timers)
1643 return;
1644 timers->erase(globalID);
1645 mutex.enter();
1646 std::map<uint32, TimerSchedule*>::iterator it = schedules.begin();
1647 std::map<uint32, TimerSchedule*>::iterator itEnd = schedules.end();
1648 while (it != itEnd)
1649 removeTimer((it++)->first);
1650
1651 // Now delete the remaining old schedules that were kept
1652 // in case a timer returned the same time as it was removed
1653 std::list<TimerSchedule*>::iterator it2 = oldSchedules.begin();
1654 std::list<TimerSchedule*>::iterator it2End = oldSchedules.end();
1655 while (it2 != it2End)
1656 delete(*it2++);
1657 oldSchedules.clear();
1658
1659 mutex.leave();
1660}
1661
1662bool Timer::addTimer(uint32 id, uint32 interval, uint64 start, uint64 end) {
1663 mutex.enter();
1664 if (schedules[id]) {
1665 mutex.leave();
1666 return false;
1667 }
1668
1669 TimerSchedule* schedule = new TimerSchedule;
1670 schedule->globalID = globalID;
1671 schedule->id = id;
1672 schedule->handle = 0;
1673 schedule->start = start;
1674 schedule->end = end;
1675 schedule->interval = interval;
1676 schedules[id] = schedule;
1677
1678 uint64 now = GetTimeNow();
1679 uint32 firstDelay = 0;
1680 if (start && (start > now))
1681 firstDelay = (uint32)(start - now)/1000;
1682
1683 // Create and set timer
1684 #ifdef WINDOWS
1685 if (!CreateTimerQueueTimer(&schedule->handle, NULL, TimerCallback, schedule, firstDelay, interval, WT_EXECUTEINTIMERTHREAD)) {
1686 schedules[id] = NULL;
1687 delete(schedule);
1688 mutex.leave();
1689 return false;
1690 }
1691 #else
1692 #ifdef __APPLE__
1693 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
1694 dispatch_source_t timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
1695 if (!timer_source) {
1696 schedules[id] = NULL;
1697 delete(schedule);
1698 mutex.leave();
1699 return false;
1700 }
1701 schedule->handle = timer_source;
1702 uint64 firstDelayNs = (uint64)firstDelay * 1000000;
1703 uint64 intervalNs = (uint64)interval * 1000000;
1704 dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (int64_t)firstDelayNs), intervalNs, 0);
1705 dispatch_source_set_event_handler(timer_source, ^{
1706 if (!Timer::timers)
1707 return;
1708 TimerSchedule* sched = schedule;
1709 if (!sched)
1710 return;
1711 Timer* timer = (*Timer::timers)[sched->globalID];
1712 if (timer)
1713 timer->triggerTimer(sched->id);
1714 });
1715 dispatch_resume(timer_source);
1716 #else
1717 struct sigaction sa;
1718 struct sigevent timer_event;
1719
1720 sigemptyset(&sa.sa_mask);
1721 sa.sa_flags = SA_SIGINFO; /* Real-Time signal */
1722 sa.sa_sigaction = TimerCallback;
1723 sigaction(SIGRTMIN, &sa, NULL);
1724
1725 timer_event.sigev_notify = SIGEV_SIGNAL;
1726 timer_event.sigev_signo = SIGRTMIN;
1727 timer_event.sigev_value.sival_ptr = (void *)schedule;
1728 if (timer_create(CLOCK_REALTIME, &timer_event, &schedule->handle) != 0) {
1729 schedules[id] = NULL;
1730 delete(schedule);
1731 mutex.leave();
1732 return false;
1733 }
1734
1735 struct itimerspec newtv;
1736 sigset_t allsigs;
1737
1738 uint64 period = interval * 1000;
1739 newtv.it_value.tv_sec = firstDelay / 1000000;
1740 newtv.it_value.tv_nsec = (firstDelay % 1000000)*1000;
1741 newtv.it_interval.tv_sec = period / 1000000;
1742 newtv.it_interval.tv_nsec = (period % 1000000)*1000;
1743
1744 if (timer_settime(schedule->handle, 0, &newtv, NULL) != 0) {
1745 timer_delete(schedule->handle);
1746 schedules[id] = NULL;
1747 delete(schedule);
1748 mutex.leave();
1749 return false;
1750 }
1751 sigemptyset(&allsigs);
1752 #endif
1753 #endif
1754
1755 mutex.leave();
1756 return true;
1757}
1758
1759bool Timer::removeTimer(uint32 id) {
1760 mutex.enter();
1761
1762 TimerSchedule* schedule = schedules[id];
1763 if (!schedule) {
1764 mutex.leave();
1765 return true;
1766 }
1767
1768 schedules[id] = NULL;
1769
1770 #ifdef WINDOWS
1771 DeleteTimerQueueTimer(NULL, schedule->handle, NULL);
1772 #else
1773 #ifdef __APPLE__
1774 dispatch_source_cancel(schedule->handle);
1775 dispatch_release(schedule->handle);
1776 #else
1777 timer_delete(schedule->handle);
1778 #endif
1779 #endif
1780
1781 oldSchedules.push_back(schedule);
1782 mutex.leave();
1783 return true;
1784}
1785
1786bool Timer::triggerTimer(uint32 id) {
1787 mutex.enter();
1788 TimerSchedule* schedule = schedules[id];
1789 if (!schedule) {
1790 mutex.leave();
1791 return false;
1792 }
1793
1794 TimerTrigger* trigger = new TimerTrigger;
1795 trigger->id = schedule->id;
1796 trigger->time = GetTimeNow();
1797
1798 triggers.push(trigger);
1799 semaphore.signal();
1800
1801 if ( schedule->end && ((int32)(schedule->end - trigger->time) < (int32)schedule->interval))
1802 removeTimer(schedule->id);
1803
1804 mutex.leave();
1805 return true;
1806}
1807
1808bool Timer::waitForTimer(uint32 timeout, uint32& id, uint64& time) {
1809 TimerTrigger* trigger;
1810 uint64 start = GetTimeNow();
1811 int64 timeleft;
1812
1813 mutex.enter();
1814 while (!triggers.size()) {
1815 mutex.leave();
1816 if ( (timeleft = (int32)timeout - GetTimeAgeMS(start)) <= 0)
1817 return false;
1818 semaphore.wait((uint32)timeleft);
1819 mutex.enter();
1820 }
1821
1822 trigger = triggers.front();
1823 triggers.pop();
1824 id = trigger->id;
1825 time = trigger->time;
1826 delete(trigger);
1827 mutex.leave();
1828 return true;
1829}
1830
1831#ifdef WINDOWS
1832 void CALLBACK TimerCallback(PVOID arg, BOOLEAN TimerOrWaitFired) {
1833 if (!Timer::timers)
1834 return;
1835 TimerSchedule* schedule = (TimerSchedule*)arg;
1836 if (!schedule)
1837 return;
1838 Timer* timer = (*Timer::timers)[schedule->globalID];
1839 if (timer)
1840 timer->triggerTimer(schedule->id);
1841 }
1842#else
1843 #ifndef __APPLE__
1844 void TimerCallback(int sig, siginfo_t *siginfo, void *context) {
1845 if (!Timer::timers)
1846 return;
1847 TimerSchedule* schedule = (TimerSchedule*) siginfo->si_value.sival_ptr;
1848 if (!schedule)
1849 return;
1850 Timer* timer = (*Timer::timers)[schedule->globalID];
1851 if (timer)
1852 timer->triggerTimer(schedule->id);
1853 }
1854 #endif
1855#endif
1856
1858 unittest::progress(5, "create timer");
1859 uint32 id;
1860 uint64 time, now = GetTimeNow();
1861
1862 Timer* timer = new Timer();
1863 if (!timer) {
1864 unittest::fail("Timer test: failed to create Timer");
1865 return false;
1866 }
1867
1868 unittest::progress(20, "schedule timers");
1869 if (!timer->addTimer(1, 1000, now+50000, now+10000000)) {
1870 unittest::fail("Timer test: addTimer 1 failed");
1871 delete(timer);
1872 return false;
1873 }
1874 if (!timer->addTimer(2, 2000, now+55000, now+15000000)) {
1875 unittest::fail("Timer test: addTimer 2 failed");
1876 delete(timer);
1877 return false;
1878 }
1879 if (!timer->addTimer(3, 3000, now+60000, now+20000000)) {
1880 unittest::fail("Timer test: addTimer 3 failed");
1881 delete(timer);
1882 return false;
1883 }
1884
1885 unittest::progress(40, "wait for triggers");
1886 uint32 triggers = 0;
1887 double totalLatencyUs = 0;
1888 uint64 t0 = GetTimeNow();
1889 // Bounded loop: timers fire every 1-3ms after ~50ms, so this returns quickly.
1890 // Stop once we have collected a stable sample or the wall-clock budget elapses.
1891 for (uint32 n = 0; n < 60; n++) {
1892 if (timer->waitForTimer(100, id, time)) {
1893 now = GetTimeNow();
1894 triggers++;
1895 totalLatencyUs += (double)(now - time);
1896 unittest::detail("Timer %u triggered %.3f ms ago", id, (now - time) / 1000.0);
1897 }
1898 else {
1899 unittest::detail("(Timeout)");
1900 }
1901 // Keep the test well under a second of wall time.
1902 if ((GetTimeNow() - t0) > 2000000ULL)
1903 break;
1904 }
1905
1906 unittest::progress(85, "verify triggers");
1907 if (triggers == 0) {
1908 unittest::fail("Timer test: no timer triggers received");
1909 delete(timer);
1910 return false;
1911 }
1912
1913 unittest::metric("timer_triggers", (double)triggers, "count", true);
1914 unittest::metric("avg_trigger_latency", totalLatencyUs / (double)triggers, "us", false);
1915
1916 delete(timer);
1917 unittest::progress(100, "done");
1918 return true;
1919}
1920
1922 unittest::progress(5, "allocate bitfield");
1923
1924 uint32 slotCount = 350;
1925 uint32 bitFieldSize = Calc32BitFieldSize(slotCount);
1926 char* bitField = new char[bitFieldSize];
1927 uint32 loc;
1928
1929 // First set the full new bitfield to unoccupied
1930 Reset32BitField(bitField, bitFieldSize);
1931 unittest::detail("%s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
1932
1933 unittest::progress(15, "empty bitfield queries");
1934 if (GetLastOccupiedBitLoc(bitField, bitFieldSize, loc)) {
1935 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: false", loc);
1936 delete[] bitField;
1937 return false;
1938 }
1939
1940 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 0)) {
1941 unittest::fail("GetFirstFreeBitLoc failed: %u, expected: 0", loc);
1942 delete[] bitField;
1943 return false;
1944 }
1945 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 0)) {
1946 unittest::fail("GetFirstFreeBitLocN failed: %u, expected: 0", loc);
1947 delete[] bitField;
1948 return false;
1949 }
1950
1951 unittest::progress(30, "single SetBit");
1952 if (!SetBit(10, BITOCCUPIED, bitField, bitFieldSize)) {
1953 unittest::fail("SetBit failed");
1954 delete[] bitField;
1955 return false;
1956 }
1957 unittest::detail("Bitfield: %s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
1958
1959 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 0)) {
1960 unittest::fail("GetFirstFreeBitLoc 2 failed: %u, expected: 0", loc);
1961 delete[] bitField;
1962 return false;
1963 }
1964 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 0)) {
1965 unittest::fail("GetFirstFreeBitLocN 2 failed: %u, expected: 0", loc);
1966 delete[] bitField;
1967 return false;
1968 }
1969
1970 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 11, loc) || (loc != 11)) {
1971 unittest::detail("Bitfield: %s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
1972 unittest::fail("GetFirstFreeBitLocN 3 failed: %u, expected: 11", loc);
1973 delete[] bitField;
1974 return false;
1975 }
1976 if (!GetLastOccupiedBitLoc(bitField, bitFieldSize, loc) || (loc != 10)) {
1977 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: 10", loc);
1978 delete[] bitField;
1979 return false;
1980 }
1981
1982 unittest::progress(50, "SetBitN occupied ranges");
1983 if (!SetBit(0, BITOCCUPIED, bitField, bitFieldSize)) {
1984 unittest::fail("SetBit 2 failed");
1985 delete[] bitField;
1986 return false;
1987 }
1988 if (!SetBitN(100, 50, BITOCCUPIED, bitField, bitFieldSize)) {
1989 unittest::fail("SetBitN 100 failed");
1990 delete[] bitField;
1991 return false;
1992 }
1993 unittest::detail("%s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
1994
1995 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 1)) {
1996 unittest::fail("GetFirstFreeBitLoc 4 failed: %u, expected: 1", loc);
1997 delete[] bitField;
1998 return false;
1999 }
2000 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 11)) {
2001 unittest::fail("GetFirstFreeBitLocN 5 failed: %u, expected: 11", loc);
2002 delete[] bitField;
2003 return false;
2004 }
2005 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 11, loc) || (loc != 11)) {
2006 unittest::fail("GetFirstFreeBitLocN 6 failed: %u, expected: 11", loc);
2007 delete[] bitField;
2008 return false;
2009 }
2010 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 100, loc) || (loc != 150)) {
2011 unittest::fail("GetFirstFreeBitLocN 7 failed: %u, expected: 150", loc);
2012 delete[] bitField;
2013 return false;
2014 }
2015 if (!GetLastOccupiedBitLoc(bitField, bitFieldSize, loc) || (loc != 149)) {
2016 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: 149", loc);
2017 delete[] bitField;
2018 return false;
2019 }
2020
2021 if (!SetBitN(200, 50, BITOCCUPIED, bitField, bitFieldSize)) {
2022 unittest::fail("SetBitN 200 failed");
2023 delete[] bitField;
2024 return false;
2025 }
2026 unittest::detail("%s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
2027
2028 unittest::progress(70, "free-loc searches");
2029 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 1)) {
2030 unittest::fail("GetFirstFreeBitLoc 8 failed: %u, expected: 1", loc);
2031 delete[] bitField;
2032 return false;
2033 }
2034 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 11)) {
2035 unittest::fail("GetFirstFreeBitLocN 9 failed: %u, expected: 11", loc);
2036 delete[] bitField;
2037 return false;
2038 }
2039 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 11, loc) || (loc != 11)) {
2040 unittest::fail("GetFirstFreeBitLocN 10 failed: %u, expected: 11", loc);
2041 delete[] bitField;
2042 return false;
2043 }
2044 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 100, loc) || (loc != 250)) {
2045 unittest::fail("GetFirstFreeBitLocN 11 failed: %u, expected: 250", loc);
2046 delete[] bitField;
2047 return false;
2048 }
2049 if (GetFirstFreeBitLocN(bitField, bitFieldSize, 200, loc)) {
2050 unittest::fail("GetFirstFreeBitLocN 12 failed: %u, expected: false", loc);
2051 delete[] bitField;
2052 return false;
2053 }
2054
2055 if (!GetLastOccupiedBitLoc(bitField, bitFieldSize, loc) || (loc != 249)) {
2056 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: 249", loc);
2057 delete[] bitField;
2058 return false;
2059 }
2060
2061 unittest::progress(85, "clear range and re-search");
2062 if (!SetBitN(210, 30, BITFREE, bitField, bitFieldSize)) {
2063 unittest::fail("SetBitN 210 failed");
2064 delete[] bitField;
2065 return false;
2066 }
2067 unittest::detail("%s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
2068
2069 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 1)) {
2070 unittest::fail("GetFirstFreeBitLoc 13 failed: %u, expected: 1", loc);
2071 delete[] bitField;
2072 return false;
2073 }
2074 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 11)) {
2075 unittest::fail("GetFirstFreeBitLocN 14 failed: %u, expected: 11", loc);
2076 delete[] bitField;
2077 return false;
2078 }
2079 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 11, loc) || (loc != 11)) {
2080 unittest::fail("GetFirstFreeBitLocN 15 failed: %u, expected: 11", loc);
2081 delete[] bitField;
2082 return false;
2083 }
2084 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 52, loc) || (loc != 11)) {
2085 unittest::fail("GetFirstFreeBitLocN 16 failed: %u, expected: 11", loc);
2086 delete[] bitField;
2087 return false;
2088 }
2089 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 100, loc) || (loc != 250)) {
2090 unittest::fail("GetFirstFreeBitLocN 17 failed: %u, expected: 250", loc);
2091 delete[] bitField;
2092 return false;
2093 }
2094 if (!GetLastOccupiedBitLoc(bitField, bitFieldSize, loc) || (loc != 249)) {
2095 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: 249", loc);
2096 delete[] bitField;
2097 return false;
2098 }
2099
2100 if (!SetBitN(50, 30, BITOCCUPIED, bitField, bitFieldSize)) {
2101 unittest::fail("SetBitN 50 failed");
2102 delete[] bitField;
2103 return false;
2104 }
2105 unittest::detail("%s", PrintBitFieldString(bitField, bitFieldSize, slotCount, "").c_str());
2106
2107 if (!GetFirstFreeBitLoc(bitField, bitFieldSize, loc) || (loc != 1)) {
2108 unittest::fail("GetFirstFreeBitLoc 18 failed: %u, expected: 1", loc);
2109 delete[] bitField;
2110 return false;
2111 }
2112 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 10, loc) || (loc != 11)) {
2113 unittest::fail("GetFirstFreeBitLocN 19 failed: %u, expected: 11", loc);
2114 delete[] bitField;
2115 return false;
2116 }
2117 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 11, loc) || (loc != 11)) {
2118 unittest::fail("GetFirstFreeBitLocN 20 failed: %u, expected: 11", loc);
2119 delete[] bitField;
2120 return false;
2121 }
2122 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 52, loc) || (loc != 250)) {
2123 unittest::fail("GetFirstFreeBitLocN 21 failed: %u, expected: 250", loc);
2124 delete[] bitField;
2125 return false;
2126 }
2127 if (!GetFirstFreeBitLocN(bitField, bitFieldSize, 100, loc) || (loc != 250)) {
2128 unittest::fail("GetFirstFreeBitLocN 22 failed: %u, expected: 250", loc);
2129 delete[] bitField;
2130 return false;
2131 }
2132 if (GetFirstFreeBitLocN(bitField, bitFieldSize, 200, loc)) {
2133 unittest::fail("GetFirstFreeBitLocN 23 failed: %u, expected: false", loc);
2134 delete[] bitField;
2135 return false;
2136 }
2137 if (!GetLastOccupiedBitLoc(bitField, bitFieldSize, loc) || (loc != 249)) {
2138 unittest::fail("GetLastOccupiedBitLoc: loc %u, expected: 249", loc);
2139 delete[] bitField;
2140 return false;
2141 }
2142
2143 delete[] bitField;
2144 unittest::progress(100, "done");
2145 return true;
2146}
2147
2148
2149
2150
2151
2152
2153
2154
2155// Create named shared memory segment
2156char* CreateSharedMemorySegment(const char* name, uint64 size, bool force) {
2157
2158 char* memname = new char[MAXSHMEMNAMELEN];
2159 #ifdef WINDOWS
2160 //sprintf(memname, "Global\\Shmem_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
2161 snprintf(memname, MAXSHMEMNAMELEN, "%s\\Shmem_%s", WINSHMEMSPACE, name);
2162 HANDLE hMapFile;
2163 char* pBuf;
2164
2165 hMapFile = CreateFileMapping(
2166 INVALID_HANDLE_VALUE, // use paging file
2167 NULL, // default security
2168 PAGE_READWRITE, // read/write access
2169 (uint32)((size >> 32) & 0xffffffff), // maximum object size (high-order DWORD)
2170 (uint32)(size & 0xffffffff), // maximum object size (low-order DWORD)
2171 memname); // name of mapping object
2172
2173 if (hMapFile == NULL) {
2174 LogPrint(0,LOG_SYSTEM,0, "Could not create shared memory '%s': %s", memname, GetLastOSErrorMessage().c_str());
2175 delete [] memname;
2176 return NULL;
2177 }
2178 delete [] memname;
2179 pBuf = (char*) MapViewOfFile(hMapFile, // handle to map object
2180 FILE_MAP_ALL_ACCESS, // read/write permission
2181 0, 0, 0); // from beginning to end
2182
2183 if (pBuf == NULL) {
2184 int error = GetLastError();
2185 CloseHandle(hMapFile);
2186 return NULL;
2187 }
2188
2191 // Save the handle so we can close it later
2192 (*SharedMemoryFileHandleMap)[pBuf] = hMapFile;
2193
2194 return pBuf;
2195 #else
2196 #ifdef __APPLE__
2197 /* macOS: use file-based shared memory (shm_open is unreliable, errno 63) */
2198 snprintf(memname, MAXSHMEMNAMELEN, "/tmp/Psyclone_Shmem_%s", name);
2199 if (force)
2200 unlink(memname);
2201 int fd = open(memname, O_CREAT | O_RDWR, 0666);
2202 if (fd == -1) {
2203 LogPrint(0,LOG_SYSTEM,0,"Couldn't create shared memory: '%s' (err: %d)...", memname, errno);
2204 delete [] memname;
2205 return NULL;
2206 }
2207 if (ftruncate(fd, size) == -1) {
2208 LogPrint(0,LOG_SYSTEM,0,"Couldn't truncate shared memory: '%s' size: %u (%d) (err: %d)...", memname, size, fd, errno);
2209 delete [] memname;
2210 close(fd);
2211 return NULL;
2212 }
2213 char* pBuf = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2214 if (pBuf == MAP_FAILED) {
2215 LogPrint(0,LOG_SYSTEM,0,"Couldn't map created shared memory: '%s' (err: %d)...", memname, errno);
2216 delete [] memname;
2217 close(fd);
2218 return NULL;
2219 }
2222 (*SharedMemoryFileHandleMap)[pBuf] = std::string(memname);
2223 close(fd);
2224 delete [] memname;
2225 return pBuf;
2226 #else
2227 /* Linux: POSIX shm_open */
2228 snprintf(memname, MAXSHMEMNAMELEN, "/Shmem_%s", name);
2229 int fd = shm_open(memname, O_CREAT | O_RDWR, 0666);
2230 if (fd == -1) {
2231 LogPrint(0,LOG_SYSTEM,0,"Couldn't create shared memory: '%s' (err: %d)...", memname, errno);
2232 delete [] memname;
2233 return NULL;
2234 }
2235 if (ftruncate(fd, size) == -1) {
2236 LogPrint(0,LOG_SYSTEM,0,"Couldn't truncate shared memory: '%s' size: %u (%d) (err: %d)...", memname, size, fd, errno);
2237 delete [] memname;
2238 close(fd);
2239 return NULL;
2240 }
2241 char* pBuf = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2242 if (pBuf == MAP_FAILED) {
2243 LogPrint(0,LOG_SYSTEM,0,"Couldn't map created shared memory: '%s' (err: %d)...", memname, errno);
2244 delete [] memname;
2245 close(fd);
2246 return NULL;
2247 }
2250 (*SharedMemoryFileHandleMap)[pBuf] = memname;
2251 close(fd);
2252 delete [] memname;
2253 return pBuf;
2254 #endif
2255 #endif
2256}
2257
2258// Get named shared memory segment, size = 0 means autodetect size
2259char* OpenSharedMemorySegment(const char* name, uint64 size) {
2260
2261 char* memname = new char[MAXSHMEMNAMELEN];
2262 #ifdef WINDOWS
2263 // sprintf(memname, "Global\\Shmem_%s_%u_%s", SharedSystemName, SharedSystemInstance, name);
2264 snprintf(memname, MAXSHMEMNAMELEN, "%s\\Shmem_%s", WINSHMEMSPACE, name);
2265 HANDLE hMapFile;
2266 char* pBuf;
2267
2268 hMapFile = OpenFileMapping(
2269 FILE_MAP_ALL_ACCESS, // read/write access
2270 FALSE, // do not inherit the name
2271 memname); // name of mapping object
2272
2273 if (hMapFile == NULL) {
2274 // LogPrint(0,LOG_SYSTEM,0, "Could not open shared memory '%s': %s", memname, GetLastOSErrorMessage().c_str());
2275 delete [] memname;
2276 return NULL;
2277 }
2278
2279 pBuf = (char*) MapViewOfFile(hMapFile, // handle to map object
2280 FILE_MAP_ALL_ACCESS, // read/write permission
2281 0, 0, 0); // from beginning to end
2282
2283 if (pBuf == NULL) {
2284 LogPrint(0,LOG_SYSTEM,0, "Could not map shared memory '%s': %s", memname, GetLastOSErrorMessage().c_str());
2285 delete [] memname;
2286 GetLastError();
2287 CloseHandle(hMapFile);
2288 return NULL;
2289 }
2290 delete [] memname;
2291
2292 // Save the handle so we can close it later
2295 (*SharedMemoryFileHandleMap)[pBuf] = hMapFile;
2296
2297 return pBuf;
2298 #else
2299 #ifdef __APPLE__
2300 /* macOS: open file-based shared memory */
2301 snprintf(memname, MAXSHMEMNAMELEN, "/tmp/Psyclone_Shmem_%s", name);
2302 int fd = open(memname, O_RDWR);
2303 if (fd == -1) {
2304 delete [] memname;
2305 return NULL;
2306 }
2307 char* pBuf;
2308 uint64 memSize = size;
2309 if (!size) {
2310 /* Autodetect: the segment file was ftruncate'd to its full size at
2311 creation, so the on-disk file size IS the segment size. (Reading a
2312 size prefix from offset 0 is wrong - callers store their own header
2313 there, e.g. RequestServerHeader.) */
2314 struct stat st;
2315 if (fstat(fd, &st) == -1 || st.st_size <= 0) {
2316 delete [] memname;
2317 close(fd);
2318 return NULL;
2319 }
2320 memSize = (uint64) st.st_size;
2321 }
2322 pBuf = (char*)mmap(NULL, memSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2323 if (pBuf == MAP_FAILED) {
2324 delete [] memname;
2325 close(fd);
2326 return NULL;
2327 }
2330 (*SharedMemoryFileHandleMap)[pBuf] = std::string(memname);
2331 close(fd);
2332 delete [] memname;
2333 return pBuf;
2334 #else
2335 /* Linux: POSIX shm_open */
2336 snprintf(memname, MAXSHMEMNAMELEN, "/Shmem_%s", name);
2337 int fd = shm_open(memname, O_RDWR, 0666);
2338 if (fd == -1) {
2339 delete [] memname;
2340 return NULL;
2341 }
2342 char* pBuf;
2343 uint64 memSize = size;
2344 if (!size) {
2345 /* Autodetect from the actual segment size (ftruncate'd at creation),
2346 not from a size prefix at offset 0 - callers store their own header
2347 there. */
2348 struct stat st;
2349 if (fstat(fd, &st) == -1 || st.st_size <= 0) {
2350 LogPrint(0,LOG_SYSTEM,0,"Couldn't stat opened shared memory: '%s' (err: %d)...", memname, errno);
2351 delete [] memname;
2352 close(fd);
2353 return NULL;
2354 }
2355 memSize = (uint64) st.st_size;
2356 }
2357 pBuf = (char*)mmap(NULL, memSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2358 if (pBuf == MAP_FAILED) {
2359 delete [] memname;
2360 close(fd);
2361 return NULL;
2362 }
2365 (*SharedMemoryFileHandleMap)[pBuf] = memname;
2366 close(fd);
2367 delete [] memname;
2368 return pBuf;
2369 #endif
2370 #endif
2371}
2372
2373// Close named shared memory segment
2374bool CloseSharedMemorySegment(char* data, uint64 size) {
2375 if (!data || !size)
2376 return true;
2377 #ifdef WINDOWS
2378 UnmapViewOfFile(data);
2379 CloseHandle((*SharedMemoryFileHandleMap)[data]);
2380 SharedMemoryFileHandleMap->erase(data);
2381 return true;
2382 #else
2383 munmap(data, size);
2384 #ifdef __APPLE__
2385 unlink((*SharedMemoryFileHandleMap)[data].c_str());
2386 #else
2387 shm_unlink((*SharedMemoryFileHandleMap)[data].c_str());
2388 #endif
2389 SharedMemoryFileHandleMap->erase(data);
2390 return true;
2391 #endif
2392}
2393
2394// Destroy named shared memory segment
2395//bool DestroySharedMemorySegment(char* data, uint32 size) {
2396// #ifdef WINDOWS
2397// UnmapViewOfFile(data);
2398// CloseHandle(SharedMemoryFileHandleMap[data]);
2399// SharedMemoryFileHandleMap[data] = NULL;
2400// return true;
2401// #else
2402// munmap(data, size);
2403// close(SharedMemoryFileHandleMap[data]);
2404// SharedMemoryFileHandleMap[data] = NULL;
2405// return (shm_unlink(data) == 0);
2406// #endif
2407//}
2408
2409
2410
2411
2412
2413
2414uint64 ntoh64(const uint64 *input) {
2415 uint64 rval;
2416 uint8 *data = (uint8*)&rval;
2417 data[0] = (uint8)(*input >> 56);
2418 data[1] = (uint8)(*input >> 48);
2419 data[2] = (uint8)(*input >> 40);
2420 data[3] = (uint8)(*input >> 32);
2421 data[4] = (uint8)(*input >> 24);
2422 data[5] = (uint8)(*input >> 16);
2423 data[6] = (uint8)(*input >> 8);
2424 data[7] = (uint8)(*input >> 0);
2425 return rval;
2426}
2427
2428uint64 hton64(const uint64 *input) {
2429 return (ntoh64(input));
2430}
2431
2432
2433
2434
2435uint32 Calc32BitFieldSize(uint32 bitsize) {
2436 return ((bitsize + 31) >> 5) << 2;
2437}
2438
2439bool Reset32BitField(char* bitfield, uint32 bytesize) {
2440 memset(bitfield, 255, bytesize);
2441 return true;
2442}
2443
2444// Get first zero bit in field of size bits, starting from data loc
2445bool GetFirstFreeBitLoc(const char* bitfield, uint32 bytesize, uint32& loc) {
2446 uint32* data = (uint32*)bitfield;
2447 uint32* src = (uint32*)data;
2448 int32 index;
2449
2450 while ((*src == 0)) {
2451 src++;
2452 if (src - data > (int32)bytesize)
2453 return false;
2454 }
2455 #if defined WINDOWS
2456 _BitScanForward((DWORD*)&index, *src);
2457 #elif defined LINUX
2458 index = ffsl(*src) - 1;
2459 #elif defined OSX
2460 index = ffsl(*src) - 1;
2461 #endif
2462
2463 loc = ((uint32)(src-data)*32) + index;
2464 return true;
2465}
2466
2467// Get first block of num zero bit in field of size bits, starting from data loc
2468bool GetFirstFreeBitLocN(const char* bitfield, uint32 bytesize, uint32 num, uint32& loc) {
2469 uint32* data = (uint32*)bitfield;
2470 uint32* src = (uint32*)data;
2471 int32 index;
2472
2473 uint32 l;
2474 bit val;
2475
2476 uint32 foundBlock = 0;
2477 while (true) {
2478 while ((*src == 0)) {
2479 src++;
2480 if (src - data > (int32)bytesize)
2481 return false;
2482 }
2483 #if defined WINDOWS
2484 _BitScanForward((DWORD*)&index, *src);
2485 #elif defined LINUX
2486 index = ffsl(*src) - 1;
2487 #elif defined OSX
2488 index = ffsl(*src) - 1;
2489 #endif
2490 loc = ((uint32)(src - data) * 32) + index;
2491 l = loc + 1;
2492 foundBlock = 1;
2493 // check for num sized block until the end of the next int32 boundary (inline bit read)
2494 if ((l + 7) >> 3 > bytesize)
2495 return false;
2496 {
2497 uint32* word = (uint32*)bitfield + (l >> 5);
2498 uint32 n = l & 31;
2499 #if defined WINDOWS
2500 val = (_bittest((long*)word, n) != 0);
2501 #elif defined LINUX
2502 val = (bit)((*word & (static_cast<uint32>(1) << n)) != 0);
2503 #elif defined OSX
2504 val = (bit)((*word & (static_cast<uint32>(1) << n)) != 0);
2505 #endif
2506 }
2507 while (true) {
2508 l++;
2509 index++;
2510 if (val == BITFREE) {
2511 foundBlock++;
2512 if (foundBlock >= num)
2513 return true;
2514 if (index % 32 == 0) {
2515 while ((num - foundBlock > 31) && (*src == MAXVALUINT32)) {
2516 foundBlock += 32;
2517 l += 32;
2518 src++;
2519 }
2520 if ((num - foundBlock > 15) && (*(uint16*)src == MAXVALUINT16)) {
2521 foundBlock += 16;
2522 l += 16;
2523 index += 16;
2524 if ((num - foundBlock > 7) && (*((unsigned char*)src+2) == 255)) {
2525 foundBlock += 8;
2526 l += 8;
2527 index += 8;
2528 }
2529 }
2530 else if ((num - foundBlock > 7) && (*(unsigned char*)src == 255)) {
2531 foundBlock += 8;
2532 l += 8;
2533 index += 8;
2534 }
2535 }
2536 if (foundBlock >= num)
2537 return true;
2538 }
2539 else {
2540 foundBlock = 0;
2541 loc = l;
2542 // are we on a boundary
2543 if (index % 32 == 0)
2544 break;
2545 }
2546 if ((l + 7) >> 3 > bytesize)
2547 return false;
2548 {
2549 uint32* word = (uint32*)bitfield + (l >> 5);
2550 uint32 n = l & 31;
2551 #if defined WINDOWS
2552 val = (_bittest((long*)word, n) != 0);
2553 #elif defined LINUX
2554 val = (bit)((*word & (static_cast<uint32>(1) << n)) != 0);
2555 #elif defined OSX
2556 val = (bit)((*word & (static_cast<uint32>(1) << n)) != 0);
2557 #endif
2558 }
2559 }
2560 // we are now on a boundary, jump back and use the bitscan search
2561 src += (uint32)(index / 32);
2562 index = 0;
2563 // if we get here, the block found wasn't big enough, continue
2564 }
2565 return true;
2566}
2567
2568// Set the nth bit to value in field of size bits, starting from data loc
2569bool SetBit(uint32 loc, bit value, char* bitfield, uint32 bytesize) {
2570 if ((loc + 7) >> 3 > bytesize)
2571 return false;
2572 uint32* data = (uint32*)bitfield;
2573 uint32* src = (uint32*)data;
2574 uint32 n = loc;
2575 while (n > 31) {
2576 n -= 32;
2577 src++;
2578 }
2579
2580 #if defined WINDOWS
2581 if (value != 0)
2582 _bittestandset((long*)src, n);
2583 else
2584 _bittestandreset((long*)src, n);
2585 #elif defined LINUX
2586 if (value != 0)
2587 *src |= 1<<n;
2588 else
2589 *src &= ~(1<<n);
2590 //*src &= ((1<<n)^0xFFFFFFFF);
2591 #elif defined OSX
2592 if (value != 0)
2593 *src |= 1<<n;
2594 else
2595 *src &= ~(1<<n);
2596 #endif
2597 return true;
2598}
2599
2600// Set the block of num bits starting with nth bit to value in field of size bits, starting from data loc
2601bool SetBitN(uint32 loc, uint32 num, bit value, char* bitfield, uint32 bytesize) {
2602 if ((loc + 7) >> 3 > bytesize)
2603 return false;
2604 uint32* data = (uint32*)bitfield;
2605 uint32* src = (uint32*)data;
2606 uint32 n = loc;
2607 while (n > 31) {
2608 n -= 32;
2609 src++;
2610 }
2611
2612 for (uint32 i = 0; i < num; i++) {
2613 if (!n) {
2614 while (num - i > 31) {
2615 *src = (value ? MAXVALUINT32 : 0);
2616 i += 32;
2617 src++;
2618 }
2619 if (num - i > 15) {
2620 *(uint16*)src = (value ? MAXVALUINT16 : 0);
2621 i += 16;
2622 n += 16;
2623 if (num - i > 7) {
2624 *((unsigned char*)src + 2) = (value ? 255 : 0);
2625 i += 8;
2626 n += 8;
2627 }
2628 }
2629 else if (num - i > 7) {
2630 *(unsigned char*)src = (value ? 255 : 0);
2631 i += 8;
2632 n += 8;
2633 }
2634 if (i == num)
2635 return true;
2636 }
2637 #if defined WINDOWS
2638 if (value != 0)
2639 _bittestandset((long*)src, n);
2640 else
2641 _bittestandreset((long*)src, n);
2642 #elif defined LINUX
2643 if (value != 0)
2644 *src |= 1 << n;
2645 else
2646 *src &= ~(1 << n);
2647 //*src &= ((1<<n)^0xFFFFFFFF);
2648 #elif defined OSX
2649 if (value != 0)
2650 *src |= 1 << n;
2651 else
2652 *src &= ~(1 << n);
2653 #endif
2654 n++;
2655 if (n > 31) {
2656 n = 0;
2657 src++;
2658 }
2659 }
2660 return true;
2661}
2662
2663// Get the nth bit in field of size bits, starting from data loc
2664bool GetBit(uint32 loc, const char* bitfield, uint32 bytesize, bit& val) {
2665 if ((loc + 7) >> 3 > bytesize)
2666 return false;
2667 uint32* data = (uint32*)bitfield;
2668 uint32* src = (uint32*)data;
2669 uint32 n = loc;
2670 while (n > 31) {
2671 n -= 32;
2672 src++;
2673 }
2674
2675 #if defined WINDOWS
2676 val = (_bittest((long*)src, n) != 0);
2677 #elif defined LINUX
2678 uint32 mask = static_cast<uint32>( 1 << n ) ;
2679 val = (bit)(mask & *src);
2680 #elif defined OSX
2681 uint32 mask = static_cast<uint32>(1 << n);
2682 val = (bit)(mask & *src);
2683 #endif
2684// printf("GetBit returned %u...\n", val);
2685 return true;
2686}
2687
2688// Get location of last bit in use, starting from data loc
2689bool GetLastOccupiedBitLoc(const char* bitfield, uint32 bytesize, uint32& loc) {
2690 uint32* data = (uint32*)bitfield;
2691 uint32* src = (uint32*)(bitfield + bytesize - 4);
2692 int32 index;
2693
2694 loc = 0;
2695 while ((*src == 0xFFFFFFFF)) {
2696 if (src <= data)
2697 return false;
2698 src--;
2699 }
2700
2701 #if defined WINDOWS
2702 _BitScanReverse((DWORD*)&index, ~(*src));
2703 #elif defined LINUX
2704 index = 31 - __builtin_clz(~(*src));
2705 #elif defined OSX
2706 index = 31 - __builtin_clz(~(*src));
2707 #endif
2708 loc = ((uint32)(src - data) * 32) + index;
2709 return true;
2710}
2711
2712
2713// Return string representing the bitfield
2714std::string GetBitFieldAsString(const char* bitfield, uint32 bytesize, uint32 size) {
2715 std::string str;
2716 str.reserve(bytesize * 9);
2717
2718 uint32 i,j,n=0;
2719 for(i = 0; i < bytesize; i++) {
2720 for(j = 0; j < 8; j++) {
2721 if (++n <= size)
2722 str.push_back((bitfield[i] & (1 << j)) ? '_' : '0');
2723 else
2724 str.push_back('*');
2725 }
2726 str.push_back(' ');
2727 };
2728 return str;
2729}
2730
2731
2732// Print string representing the bitfield
2733std::string PrintBitFieldString(const char* bitfield, uint32 bytesize, uint32 size, const char* title) {
2734 std::string str = GetBitFieldAsString(bitfield, bytesize, size);
2735 uint32 strSize = (uint32)str.size();
2736 if (!strSize)
2737 return "";
2738 if (strSize < 73) {
2739 if (title != NULL)
2740 return StringFormat("%s [%u]: %s\n", title, size, str.c_str());
2741 else
2742 return StringFormat("%s\n", str.c_str());
2743 }
2744 else {
2745 std::string str2;
2746 if (title != NULL)
2747 str2 = StringFormat("%s [%u]:\n", title, size);
2748 uint32 loc = 0;
2749 while (loc < strSize-1) {
2750 str2 += str.substr(loc, 36) + "\n";
2751 loc += 36;
2752 }
2753 if (loc < strSize)
2754 str2 += str.substr(loc) + "\n";
2755 return str2;
2756 }
2757}
2758
2759
2760
2761
2762int32 AtomicIncrement32(int32 volatile &v) {
2763 #if defined WINDOWS
2764 return InterlockedIncrement((LONG*)&v);
2765 // #elif defined LINUX
2766 #else
2767 __sync_add_and_fetch(&v, 1);
2768 return v;
2769 #endif
2770};
2771
2772int64 AtomicIncrement64(int64 volatile &v) {
2773 #if defined WINDOWS
2774 return InterlockedIncrement64((LONGLONG*)&v);
2775 // #elif defined LINUX
2776 #else
2777 __sync_add_and_fetch(&v, 1);
2778 return v;
2779 #endif
2780};
2781
2782int32 AtomicDecrement32(int32 volatile &v) {
2783 #if defined WINDOWS
2784 return InterlockedDecrement((LONG*)&v);
2785 // #elif defined LINUX
2786 #else
2787 __sync_add_and_fetch(&v, -1);
2788 return v;
2789 #endif
2790};
2791
2792int64 AtomicDecrement64(int64 volatile &v) {
2793 #if defined WINDOWS
2794 return InterlockedDecrement64((LONGLONG*)&v);
2795 // #elif defined LINUX
2796 #else
2797 __sync_add_and_fetch(&v, -1);
2798 return v;
2799 #endif
2800};
2801
2802bool Sleep(uint32 ms) {
2803 #if defined WINDOWS
2804 // we are actually being passed millisecond, so multiply up
2805 ::Sleep((uint32)ms);
2806 #else
2807 usleep(ms*1000);
2808 #endif
2809 return true;
2810}
2811
2812std::string PrintProgramTrace(uint32 startLine, uint32 endLine) {
2813 std::string tracePrint;
2814 std::list<std::string> trace = GetProgramTrace();
2815
2816 std::list<std::string>::iterator i = trace.begin(), e = trace.end();
2817
2818 uint32 line = 0;
2819 while (i != e) {
2820 if ((++line > startLine) && (!endLine || (line <= endLine)))
2821 tracePrint += " -" + (*i) + "\n";
2822 i++;
2823 }
2824 return tracePrint;
2825}
2826
2827std::list<std::string> GetProgramTrace() {
2828 std::list<std::string> trace;
2829 #ifdef WINDOWS
2830 // this needs Dbghelp.h included and link with Dbghelp.lib
2831 //unsigned int i;
2832 //void * stack[ 100 ];
2833 //unsigned short frames;
2834 //SYMBOL_INFO * symbol;
2835 //HANDLE process;
2836
2837 //process = GetCurrentProcess();
2838
2839 //SymInitialize( process, NULL, TRUE );
2840
2841 //frames = CaptureStackBackTrace( 0, 100, stack, NULL );
2842 //symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
2843 //symbol->MaxNameLen = 255;
2844 //symbol->SizeOfStruct = sizeof( SYMBOL_INFO );
2845
2846 //for( i = 0; i < frames; i++ ) {
2847 // SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol );
2848 // trace.push_back(StringFormat("%i: %s (0x%0X)", frames - i - 1, symbol->Name, symbol->Address));
2849 //}
2850 //free( symbol );
2851 #else
2852 #ifdef _DEBUG
2853 void *array[200];
2854 size_t size;
2855 char **strings;
2856 size_t i;
2857 size = backtrace(array, 200);
2858 strings = backtrace_symbols(array, size);
2859 for (i = 0; i < size; i++)
2860 trace.push_back(strings[i]);
2861 free (strings);
2862 #endif // _DEBUG
2863 #endif
2864 return trace;
2865}
2866
2867
2868bool CreateThread(THREAD_FUNCTION func, void* args, ThreadHandle& thread, uint32 &osID) {
2869
2870 #if defined WINDOWS
2871 DWORD dwThreadId;
2872 thread = ::CreateThread(
2873 NULL, // no security attributes
2874 0, // use default stack size
2875 (LPTHREAD_START_ROUTINE) func, // thread function
2876 args, // argument to thread function
2877 0, // use default creation flags
2878 &dwThreadId); // returns the thread identifier
2879
2880 if (thread != NULL) {
2881 osID = ::GetThreadId(thread);
2882 Sleep(0);
2883 return true;
2884 }
2885 else
2886 return false;
2887 #else
2888 pthread_attr_t attr;
2889 pthread_attr_init(&attr); /* initialize attr with default attributes */
2890 // pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
2891 pthread_attr_setschedpolicy(&attr, SCHED_RR);
2892 pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
2893 // pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
2894
2895 int res;
2896 if ((res=pthread_create(&thread, &attr, func, args)) != 0)
2897 return false;
2898 int oldstate;
2899 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
2900 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldstate);
2901 #ifdef __APPLE__
2902 uint64 tid;
2903 pthread_threadid_np(thread, &tid);
2904 osID = (uint32)tid;
2905 #else
2906 osID = (uint32) thread;
2907 #endif
2908 // printf("create hThread: %u\n", thread);
2909 Sleep(0);
2910 return true;
2911 #endif
2912}
2913
2915 #if defined WINDOWS
2916 int res = WaitForSingleObject(hThread, 0);
2917 if (res != WAIT_OBJECT_0)
2918 return false;
2919 return true;
2920 //return (CloseHandle(hThread) != 0);
2921 #else
2922 #ifdef __APPLE__
2923 // Non-destructive probe -- see IsThreadRunning. Must not pthread_join here,
2924 // or the later authoritative join double-joins a reaped thread and corrupts
2925 // the heap. pthread_kill(h, 0): ESRCH (non-zero) => thread has finished.
2926 // A null handle (empty slot) is "finished"; guard it since pthread_kill,
2927 // unlike pthread_join, dereferences the handle and would crash on null.
2928 if (!hThread)
2929 return true;
2930 return (pthread_kill(hThread, 0) != 0);
2931 #else
2932 // printf("Trying ID: %llu...\n", (uint64)hThread);
2933 int res = pthread_tryjoin_np(hThread, NULL);
2934 // printf("--%d--\n", res);
2935 if (res != 0)
2936 return false;
2937 else
2938 return true;
2939 #endif
2940 #endif
2941}
2942
2943bool WaitForThreadToFinish(ThreadHandle hThread, uint32 timeoutMS) {
2944 // Sadly, the Linux implementation of join doesn't allow a timeout, so to be compatible
2945 // we cannot allow the Windows to have this either, although it could (and should) have
2946 #if defined WINDOWS
2947 int res = WaitForSingleObject(hThread, timeoutMS ? timeoutMS : INFINITE);
2948 if(res != WAIT_OBJECT_0)
2949 return false;
2950 return true;
2951 //return (CloseHandle(hThread) != 0);
2952 #else
2953 #ifdef __APPLE__
2954 if (!hThread)
2955 return true; // nothing to wait for
2956 // macOS has no pthread_timedjoin_np. A timeout==0 means "block until done".
2957 if (timeoutMS == 0)
2958 return (pthread_join(hThread, NULL) == 0);
2959 // For a bounded wait, poll liveness non-destructively (pthread_kill, no
2960 // signal) until the thread exits or the deadline passes, then perform a
2961 // single authoritative join to reap it. This avoids spawning a detached
2962 // joiner thread that would race a later join on the same handle (the
2963 // previous approach could leave two pthread_join calls on one target --
2964 // undefined behaviour that corrupted the heap).
2965 uint32 waited = 0;
2966 while (pthread_kill(hThread, 0) == 0) {
2967 if (waited >= timeoutMS)
2968 return false; // still running at deadline; do NOT reap
2969 Sleep(2);
2970 waited += 2;
2971 }
2972 // Thread has exited but is still joinable; reap it exactly once.
2973 pthread_join(hThread, NULL);
2974 return true;
2975 #else
2976 struct timespec ts;
2977 CalcTimeout(ts, timeoutMS);
2978 if (timeoutMS) {
2979 if (pthread_timedjoin_np(hThread, NULL, &ts) != 0)
2980 return false;
2981 else
2982 return true;
2983 }
2984 else {
2985 if (pthread_join(hThread, NULL) != 0)
2986 return false;
2987 }
2988 return true;
2989 #endif
2990 #endif
2991}
2992
2994 if (!hThread)
2995 return true;
2996 #if defined WINDOWS
2997 // printf("cancel hThread: %u\n", hThread);
2998 bool res = false;
2999 try {
3000 res = (::TerminateThread(hThread, 0) != 0);
3001 if (!res) {
3002 char* msg = new char[2048];
3003 int length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
3004 NULL, GetLastError(), 0, msg, sizeof(msg), NULL);
3005 msg[length] = '\0';
3006 LogPrint(0, LOG_SYSTEM, 0, "Error terminating thread: %s", msg);
3007 delete[] msg;
3008 }
3009 else
3010 CloseHandle(hThread);
3011 }
3012 catch (...) {}
3013 return res;
3014 #else
3015 // printf("cancel hThread: %u\n", hThread);
3016 pthread_cancel(hThread);
3017 if (pthread_join(hThread, NULL) != 0)
3018 return false;
3019 return true;
3020 #endif
3021}
3022
3024 #if defined WINDOWS
3025 return (SuspendThread(hThread) >= 0);
3026 #else
3027 return (pthread_kill(hThread, SIGSTOP) == 0);
3028 #endif
3029 return false;
3030}
3031
3033 #if defined WINDOWS
3034 DWORD count;
3035 while ( (count = ResumeThread(hThread)) > 1);
3036 return (count == 1);
3037 #else
3038 return (pthread_kill(hThread, SIGCONT) == 0);
3039 #endif
3040 return false;
3041}
3042
3043bool GetCurrentThreadUniqueID(uint32 &tid) {
3044 // This function returns an ID unique to the thread on a given OS
3045 // On Windows this is the Thread OS ID
3046 // On Linux we cannot read other thread OS IDs so it has to be the
3047 // thread handle converted to a 32bit uint.
3048 #if defined WINDOWS
3049 tid = ::GetCurrentThreadId();
3050 return true;
3051 #else
3052 #ifdef __APPLE__
3053 uint64 id;
3054 pthread_threadid_np(pthread_self(), &id);
3055 tid = (uint32)id;
3056 #else
3057 tid = (uint32) pthread_self();
3058 #endif
3059 return true;
3060 #endif
3061}
3062
3063bool GetCurrentThreadOSID(uint32 &tid) {
3064 #if defined WINDOWS
3065 tid = ::GetCurrentThreadId();
3066 return true;
3067 #else
3068 #ifdef __APPLE__
3069 uint64 id;
3070 if (pthread_threadid_np(pthread_self(), &id) != 0)
3071 return false;
3072 tid = (uint32)id;
3073 #else
3074 int id = syscall(SYS_gettid);
3075 if (id <= 0)
3076 return false;
3077 tid = (uint32)id;
3078 #endif
3079 return true;
3080 #endif
3081}
3082
3084 #if defined WINDOWS
3085 thread = ::GetCurrentThread();
3086 return true;
3087 #else
3088 thread = pthread_self();
3089 return true;
3090 #endif
3091}
3092
3094 #if defined WINDOWS
3095 DWORD code;
3096 if (!GetExitCodeThread(hThread, &code))
3097 return false;
3098 return (code == STILL_ACTIVE);
3099 #else
3100 #ifdef __APPLE__
3101 // Non-destructive liveness probe. macOS has no pthread_tryjoin_np, and we
3102 // must NOT use pthread_join here: this is polled repeatedly (e.g. by the
3103 // ThreadManager monitoring loop) and a join reaps the thread, after which
3104 // the authoritative TerminateThread/WaitForThreadToFinish join would operate
3105 // on an already-joined pthread_t -- undefined behaviour that corrupts the
3106 // heap. pthread_kill(h, 0) sends no signal and just reports existence:
3107 // 0 => still alive, ESRCH => already terminated. Unlike pthread_join, it
3108 // dereferences the handle, so a null handle (empty slot) must be guarded.
3109 if (!hThread)
3110 return false;
3111 return (pthread_kill(hThread, 0) == 0);
3112 #else
3113 // printf("*** IsThreadRunning: %llu\n", (uint64)hThread);
3114 return (pthread_tryjoin_np(hThread, NULL) != 0);
3115 #endif
3116 #endif
3117}
3118
3120 #if defined WINDOWS
3121 return THREAD_STATS_AUTO;
3122 #else
3123 #if defined RUSAGE_THREAD
3124 return THREAD_STATS_ADHOC;
3125 #else
3126 return THREAD_STATS_OFF;
3127 #endif
3128 #endif
3129}
3130
3131bool GetCPUTicks(ThreadHandle hThread, uint64& ticks) {
3132 ticks = 0;
3133
3134 #if defined WINDOWS
3135 // if (!QueryThreadCycleTime(hThread, &ticks))
3136 // return false;
3137 uint64 cpuTicks = 0;
3138 LARGE_INTEGER perfFreq;
3139 if (!QueryPerformanceFrequency(&perfFreq) || !perfFreq.QuadPart)
3140 return false;
3141 if (!QueryThreadCycleTime(hThread, &cpuTicks))
3142 return false;
3143 ticks = cpuTicks / (perfFreq.QuadPart / 1000000); // cpu ticks / (number of ticks per us)
3144 //FILETIME creationTime;
3145 //FILETIME exitTime;
3146 //FILETIME kernelTime;
3147 //FILETIME userTime;
3148 //if (!GetThreadTimes(hThread, &creationTime, &exitTime, &kernelTime, &userTime))
3149 // return false;
3150 //userCPU = ((uint64)userTime.dwLowDateTime | (((uint64)userTime.dwHighDateTime) << 32)) / 10;
3151 //kernelCPU = ((uint64)kernelTime.dwLowDateTime | (((uint64)kernelTime.dwHighDateTime) << 32)) / 10;
3152 return true;
3153 #else
3154 #ifdef __APPLE__
3155 // macOS: use Mach thread_info to get per-thread CPU time
3156 mach_port_t machThread = pthread_mach_thread_np(hThread);
3157 if (machThread == MACH_PORT_NULL)
3158 return false;
3159 thread_basic_info_data_t info;
3160 mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
3161 if (thread_info(machThread, THREAD_BASIC_INFO, (thread_info_t)&info, &infoCount) != KERN_SUCCESS)
3162 return false;
3163 ticks = (uint64)info.user_time.seconds * 1000000 + info.user_time.microseconds
3164 + (uint64)info.system_time.seconds * 1000000 + info.system_time.microseconds;
3165 return true;
3166 #else
3167 clockid_t cid;
3168 if (pthread_getcpuclockid(hThread, &cid) != 0)
3169 return false;
3170 timespec ts;
3171 if (clock_gettime(cid, &ts) != -1 ) {
3172 ticks = ((uint64)ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
3173 return true;
3174 }
3175 else
3176 return false;
3177 #endif
3178 #endif
3179 return true;
3180}
3181
3182bool GetCPUTicks(uint64& ticks) {
3183 ticks = 0;
3184
3185 #if defined WINDOWS
3186 // #### QueryPerformanceFrequency
3187 uint64 cpuTicks = 0;
3188 LARGE_INTEGER perfFreq;
3189 if (!QueryPerformanceFrequency(&perfFreq) || !perfFreq.QuadPart)
3190 return false;
3191 if (!QueryThreadCycleTime(::GetCurrentThread(), &cpuTicks))
3192 return false;
3193 ticks = cpuTicks / (perfFreq.QuadPart / 1000000); // cpu ticks / (number of ticks per us)
3194 //FILETIME creationTime;
3195 //FILETIME exitTime;
3196 //FILETIME kernelTime;
3197 //FILETIME userTime;
3198 //if (!GetThreadTimes(::GetCurrentThread(), &creationTime, &exitTime, &kernelTime, &userTime))
3199 // return false;
3200 //userCPU = ((uint64)userTime.dwLowDateTime | (((uint64)userTime.dwHighDateTime) << 32)) / 10;
3201 //kernelCPU = ((uint64)kernelTime.dwLowDateTime | (((uint64)kernelTime.dwHighDateTime) << 32)) / 10;
3202 return true;
3203 #else
3204 timespec ts;
3205 if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != -1 ) {
3206 ticks = ((uint64)ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
3207 return true;
3208 }
3209 else
3210 return false;
3211 //#if defined RUSAGE_THREAD
3212 // struct rusage us;
3213 // if (getrusage(RUSAGE_THREAD, &us) == 0) { // RUSAGE_THREAD // accumulate_thread_rusage
3214 // userCPU = (us.ru_utime.tv_sec * 1000000) + us.ru_utime.tv_usec;
3215 // kernelCPU = (us.ru_stime.tv_sec * 1000000) + us.ru_stime.tv_usec;
3216 // }
3217 // else
3218 // return false;
3219 //#else
3220 // return false;
3221 //#endif
3222 #endif
3223}
3224
3225bool GetProcessCPUTicks(uint32 osProcID, uint64& ticks) {
3226 ticks = 0;
3227
3228 #if defined WINDOWS
3229 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, osProcID);
3230 if (!hProcess)
3231 return false;
3232 // if (!QueryProcessCycleTime(hProcess, &ticks))
3233 // return false;
3234
3235 uint64 cpuTicks = 0;
3236 LARGE_INTEGER perfFreq;
3237 if (!QueryPerformanceFrequency(&perfFreq) || !perfFreq.QuadPart)
3238 return false;
3239 if (!QueryProcessCycleTime(hProcess, &cpuTicks))
3240 return false;
3241 ticks = cpuTicks / (perfFreq.QuadPart / 1000000); // cpu ticks / (number of ticks per us)
3242
3243 //FILETIME creationTime;
3244 //FILETIME exitTime;
3245 //FILETIME kernelTime;
3246 //FILETIME userTime;
3247 //if (!GetProcessTimes(::GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime))
3248 // return false;
3249 //userCPU = ((uint64)userTime.dwLowDateTime | (((uint64)userTime.dwHighDateTime) << 32)) / 10;
3250 //kernelCPU = ((uint64)kernelTime.dwLowDateTime | (((uint64)kernelTime.dwHighDateTime) << 32)) / 10;
3251 return true;
3252 #else
3253 #ifdef __APPLE__
3254 if ((pid_t)osProcID != getpid())
3255 return false;
3256 struct rusage ru;
3257 if (getrusage(RUSAGE_SELF, &ru) != 0)
3258 return false;
3259 ticks = ((uint64)ru.ru_utime.tv_sec * 1000000) + (uint64)ru.ru_utime.tv_usec
3260 + ((uint64)ru.ru_stime.tv_sec * 1000000) + (uint64)ru.ru_stime.tv_usec;
3261 return true;
3262 #else
3263 clockid_t clockid;
3264 if (clock_getcpuclockid(osProcID, &clockid) != 0)
3265 return false;
3266 timespec ts;
3267 if (clock_gettime(clockid, &ts) != -1 ) {
3268 ticks = ((uint64)ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
3269 return true;
3270 }
3271 else
3272 return false;
3273 //#if defined RUSAGE_THREAD
3274 // struct rusage us;
3275 // if (getrusage(RUSAGE_SELF, &us) == 0) { // RUSAGE_THREAD // accumulate_thread_rusage
3276 // userCPU = (us.ru_utime.tv_sec * 1000000) + us.ru_utime.tv_usec;
3277 // kernelCPU = (us.ru_stime.tv_sec * 1000000) + us.ru_stime.tv_usec;
3278 // }
3279 // else
3280 // return false;
3281 //#else
3282 // return false;
3283 //#endif
3284 #endif
3285 #endif
3286 return true;
3287}
3288
3289bool GetProcessCPUTicks(uint64& ticks) {
3290 ticks = 0;
3291
3292 #if defined WINDOWS
3293 // if (!QueryProcessCycleTime(::GetCurrentProcess(), &ticks))
3294 // return false;
3295
3296 uint64 cpuTicks = 0;
3297 LARGE_INTEGER perfFreq;
3298 if (!QueryPerformanceFrequency(&perfFreq) || !perfFreq.QuadPart)
3299 return false;
3300 if (!QueryProcessCycleTime(::GetCurrentProcess(), &cpuTicks))
3301 return false;
3302 ticks = cpuTicks / (perfFreq.QuadPart / 1000000); // cpu ticks / (number of ticks per us)
3303
3304 //FILETIME creationTime;
3305 //FILETIME exitTime;
3306 //FILETIME kernelTime;
3307 //FILETIME userTime;
3308 //if (!GetProcessTimes(::GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime))
3309 // return false;
3310 //userCPU = ((uint64)userTime.dwLowDateTime | (((uint64)userTime.dwHighDateTime) << 32)) / 10;
3311 //kernelCPU = ((uint64)kernelTime.dwLowDateTime | (((uint64)kernelTime.dwHighDateTime) << 32)) / 10;
3312 return true;
3313 #else
3314 timespec ts;
3315 if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) != -1 ) {
3316 ticks = ((uint64)ts.tv_sec * 1000000) + (ts.tv_nsec/1000);
3317 return true;
3318 }
3319 else
3320 return false;
3321 //#if defined RUSAGE_THREAD
3322 // struct rusage us;
3323 // if (getrusage(RUSAGE_SELF, &us) == 0) { // RUSAGE_THREAD // accumulate_thread_rusage
3324 // userCPU = (us.ru_utime.tv_sec * 1000000) + us.ru_utime.tv_usec;
3325 // kernelCPU = (us.ru_stime.tv_sec * 1000000) + us.ru_stime.tv_usec;
3326 // }
3327 // else
3328 // return false;
3329 //#else
3330 // return false;
3331 //#endif
3332 #endif
3333 return true;
3334}
3335
3336bool GetProcAndOSCPUUsage(double& procPercentUse, double& osPercentUse, uint64 &prevOSTicks, uint64 &prevOSIdleTicks, uint64 &prevProcTicks) {
3337 #if defined WINDOWS
3338 return GetProcAndOSCPUUsage(0, procPercentUse, osPercentUse, prevOSTicks, prevOSIdleTicks, prevProcTicks);
3339 #else
3340 return GetProcAndOSCPUUsage(getpid(), procPercentUse, osPercentUse, prevOSTicks, prevOSIdleTicks, prevProcTicks);
3341 #endif
3342 return true;
3343}
3344
3345bool GetProcAndOSCPUUsage(uint32 osProcID, double& procPercentUse, double& osPercentUse, uint64 &prevOSTicks, uint64 &prevOSIdleTicks, uint64 &prevProcTicks) {
3346 procPercentUse = osPercentUse = 0;
3347
3348 uint64 totalTicks, kernelTicks, userTicks, idleTicks, procTotalTicks, procUserTicks, procKernelTicks;
3349
3350 #if defined WINDOWS
3351 FILETIME idleTime, kernelTime, userTime;
3352 if (!GetSystemTimes(&idleTime, &kernelTime, &userTime))
3353 return false;
3354
3355 idleTicks = FileTimeToUint64(idleTime);
3356 kernelTicks = FileTimeToUint64(kernelTime);
3357 userTicks = FileTimeToUint64(userTime);
3358 totalTicks = kernelTicks + userTicks;
3359
3360 FILETIME procCreationTime, procExitTime, procKernelTime, procUserTime;
3361
3362 if (!osProcID) {
3363 if (!GetProcessTimes(GetCurrentProcess(), &procCreationTime, &procExitTime, &procKernelTime, &procUserTime))
3364 return false;
3365 }
3366 else {
3367 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, osProcID);
3368 if (!hProcess)
3369 return false;
3370
3371 if (!GetProcessTimes(hProcess, &procCreationTime, &procExitTime, &procKernelTime, &procUserTime))
3372 return false;
3373 }
3374
3375 procKernelTicks = FileTimeToUint64(procKernelTime);
3376 procUserTicks = FileTimeToUint64(procUserTime);
3377 procTotalTicks = procKernelTicks + procUserTicks;
3378
3379 // printf("Proc User: %llu Kernel: %llu\n", procUserTicks, procKernelTicks);
3380
3381 #elif defined OSX
3382 host_cpu_load_info_data_t cpuInfo;
3383 mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
3384 if (host_statistics64(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info64_t)&cpuInfo, &count) != KERN_SUCCESS)
3385 return false;
3386 // cpu_ticks are in Mach clock ticks (typically 100/s via CLK_TCK)
3387 // Convert to microseconds to match procTotalTicks units
3388 long ticksPerSec = sysconf(_SC_CLK_TCK);
3389 uint64 usPerTick = (ticksPerSec > 0) ? (1000000 / ticksPerSec) : 10000;
3390 totalTicks = ((uint64)cpuInfo.cpu_ticks[CPU_STATE_USER] + cpuInfo.cpu_ticks[CPU_STATE_SYSTEM] + cpuInfo.cpu_ticks[CPU_STATE_IDLE] + cpuInfo.cpu_ticks[CPU_STATE_NICE]) * usPerTick;
3391 idleTicks = (uint64)cpuInfo.cpu_ticks[CPU_STATE_IDLE] * usPerTick;
3392 if (osProcID == 0 || osProcID == (uint32)getpid()) {
3393 task_thread_times_info_data_t threadTimes;
3394 count = TASK_THREAD_TIMES_INFO_COUNT;
3395 if (task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&threadTimes, &count) == KERN_SUCCESS)
3396 procTotalTicks = (uint64)threadTimes.user_time.seconds * 1000000 + threadTimes.user_time.microseconds + (uint64)threadTimes.system_time.seconds * 1000000 + threadTimes.system_time.microseconds;
3397 else
3398 procTotalTicks = 0;
3399 } else {
3400 return false;
3401 }
3402
3403 #else
3404 std::string statLine, procStatLine;
3405 std::ifstream statFile ("/proc/stat");
3406 std::ifstream procStatFile (StringFormat("/proc/%d/stat", osProcID).c_str());
3407 if (statFile.is_open())
3408 getline (statFile, statLine);
3409 else
3410 return false;
3411
3412 if (procStatFile.is_open())
3413 getline (procStatFile, procStatLine);
3414 else
3415 return false;
3416
3417 if (!statLine.length() || !procStatLine.length())
3418 return false;
3419
3420 //cpu 56344 20038 65629 5095979 55549 9083 10717 0 0 0
3421 uint64 fields[10];
3422 int retval = sscanf(statLine.c_str(), "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
3423 &fields[0], &fields[1], &fields[2], &fields[3], &fields[4],
3424 &fields[5], &fields[6], &fields[7], &fields[8], &fields[9]);
3425 totalTicks = 0;
3426 for (int i=0; i<10; i++)
3427 totalTicks += fields[i];
3428 idleTicks = fields[3];
3429
3430 uint64 utime_ticks, stime_ticks, cutime_ticks, cstime_ticks;
3431 retval = sscanf(procStatLine.c_str(), "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu %llu %llu",
3432 &utime_ticks, &stime_ticks, &cutime_ticks, &cstime_ticks);
3433
3434 procTotalTicks = utime_ticks + stime_ticks + cutime_ticks + cstime_ticks;
3435 #endif
3436
3437 uint64 totalTicksSinceLastTime = totalTicks - prevOSTicks;
3438 uint64 idleTicksSinceLastTime = idleTicks - prevOSIdleTicks;
3439 uint64 procTicksSinceLastTime = procTotalTicks - prevProcTicks;
3440
3441 osPercentUse = 1.0f-((totalTicksSinceLastTime > 0) ? ((double)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
3442 procPercentUse = ((totalTicksSinceLastTime > 0) ? ((double)procTicksSinceLastTime)/totalTicksSinceLastTime : 0);
3443
3444// printf("Idle: %llu Total: %llu %.2f%%\n",
3445// idleTicksSinceLastTime, totalTicksSinceLastTime, percentUse*100);
3446
3447 prevOSTicks = totalTicks;
3448 prevOSIdleTicks = idleTicks;
3449 prevProcTicks = procTotalTicks;
3450
3451 return true;
3452}
3453
3454bool GetOSCPUUsage(double& percentUse) {
3455 percentUse = 0;
3456
3457 static uint64 PreviousTotalTicks = 0;
3458 static uint64 PreviousIdleTicks = 0;
3459
3460 uint64 totalTicks, kernelTicks, userTicks, idleTicks;
3461
3462 #if defined WINDOWS
3463
3464 FILETIME idleTime, kernelTime, userTime;
3465 if (!GetSystemTimes(&idleTime, &kernelTime, &userTime))
3466 return false;
3467
3468 idleTicks = FileTimeToUint64(idleTime);
3469 kernelTicks = FileTimeToUint64(kernelTime);
3470 userTicks = FileTimeToUint64(userTime);
3471 totalTicks = kernelTicks + userTicks;
3472
3473 #elif defined OSX
3474 host_cpu_load_info_data_t cpuInfo;
3475 mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
3476 if (host_statistics64(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info64_t)&cpuInfo, &count) != KERN_SUCCESS)
3477 return false;
3478 totalTicks = (uint64)cpuInfo.cpu_ticks[CPU_STATE_USER] + cpuInfo.cpu_ticks[CPU_STATE_SYSTEM] + cpuInfo.cpu_ticks[CPU_STATE_IDLE] + cpuInfo.cpu_ticks[CPU_STATE_NICE];
3479 idleTicks = (uint64)cpuInfo.cpu_ticks[CPU_STATE_IDLE];
3480 #else
3481 std::string statLine;
3482 std::ifstream statFile("/proc/stat");
3483 if (!statFile.is_open() || !getline(statFile, statLine) || !statLine.length())
3484 return false;
3485
3486 uint64 fields[10];
3487 if (sscanf(statLine.c_str(), "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
3488 &fields[0], &fields[1], &fields[2], &fields[3], &fields[4],
3489 &fields[5], &fields[6], &fields[7], &fields[8], &fields[9]) < 10)
3490 return false;
3491 totalTicks = 0;
3492 for (int i = 0; i < 10; i++)
3493 totalTicks += fields[i];
3494 idleTicks = fields[3];
3495 #endif
3496
3497 uint64 totalTicksSinceLastTime = totalTicks - PreviousTotalTicks;
3498 uint64 idleTicksSinceLastTime = idleTicks - PreviousIdleTicks;
3499
3500 percentUse = 1.0f-((totalTicksSinceLastTime > 0) ? ((double)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
3501
3502// printf("Idle: %llu Total: %llu %.2f%%\n",
3503// idleTicksSinceLastTime, totalTicksSinceLastTime, percentUse*100);
3504
3505 PreviousTotalTicks = totalTicks;
3506 PreviousIdleTicks = idleTicks;
3507
3508 return true;
3509}
3510
3511bool GetThreadPriority(ThreadHandle hThread, uint16 priority) {
3512
3513 #if defined WINDOWS
3514 uint16 prio = ::GetThreadPriority(hThread);
3515 priority = FromOSPriority(prio);
3516 #else
3517 struct sched_param sched;
3518 int policy;
3519 #ifdef __APPLE__
3520 policy = SCHED_OTHER;
3521 #else
3522 policy = sched_getscheduler(0);
3523 if(policy < 0)
3524 return false;
3525 #endif
3526 if (pthread_getschedparam(hThread, &policy, &sched) != 0)
3527 return false;
3528
3529 priority = FromOSPriority(sched.sched_priority);
3530 #endif
3531 return true;
3532}
3533
3534bool SetThreadPriority(ThreadHandle hThread, uint16 priority) {
3535 #if defined WINDOWS
3536 return (::SetThreadPriority(hThread, ToOSPriority(priority)) != 0);
3537 #else
3538 int policy;
3539 struct sched_param sched;
3540 memset(&sched, 0, sizeof(struct sched_param));
3541
3542 policy = SCHED_FIFO;
3543 // policy = SCHED_RR;
3544 sched.sched_priority = ToOSPriority(priority);
3545
3546 int res = pthread_setschedparam(hThread, policy, &sched);
3547 if (res != 0)
3548 return false;
3549 #endif
3550 return true;
3551}
3552
3553int ToOSPriority(int pri) {
3554 int val;
3555
3556 #if defined WINDOWS
3557 if (pri == 0)
3558 val = THREAD_PRIORITY_NORMAL;
3559 else if (pri >= 90)
3560 val = THREAD_PRIORITY_TIME_CRITICAL;
3561 else if (pri >= 80)
3562 val = THREAD_PRIORITY_HIGHEST;
3563 else if (pri >= 70)
3564 val = THREAD_PRIORITY_ABOVE_NORMAL;
3565 else if (pri >= 60)
3566 val = THREAD_PRIORITY_NORMAL;
3567 else if (pri >= 50)
3568 val = THREAD_PRIORITY_BELOW_NORMAL;
3569 else if (pri >= 40)
3570 val = THREAD_PRIORITY_LOWEST;
3571 else
3572 val = THREAD_PRIORITY_IDLE;
3573 #else
3574 if (pri == 0)
3575 val = 40;
3576 else if (pri >= 90)
3577 val = 60;
3578 else if (pri >= 80)
3579 val = 55;
3580 else if (pri >= 70)
3581 val = 40;
3582 else if (pri >= 60)
3583 val = 35;
3584 else if (pri >= 50)
3585 val = 30;
3586 else if (pri >= 40)
3587 val = 25;
3588 else if (pri >= 30)
3589 val = 20;
3590 else if (pri >= 20)
3591 val = 15;
3592 else if (pri >= 10)
3593 val = 10;
3594 else
3595 val = 5;
3596 #endif
3597
3598 return val;
3599}
3600
3601int FromOSPriority(int pri) {
3602
3603 #if defined WINDOWS
3604 switch (pri) {
3605 case THREAD_PRIORITY_TIME_CRITICAL:
3606 return 80;
3607 case THREAD_PRIORITY_HIGHEST:
3608 return 60;
3609 case THREAD_PRIORITY_ABOVE_NORMAL:
3610 return 55;
3611 case THREAD_PRIORITY_NORMAL:
3612 return 50;
3613 case THREAD_PRIORITY_BELOW_NORMAL:
3614 return 40;
3615 case THREAD_PRIORITY_LOWEST:
3616 return 30;
3617 default:
3618 return 20;
3619 }
3620 #else
3621 return pri;
3622 #endif
3623}
3624
3625bool SignalThread(ThreadHandle hThread, int32 signal) {
3626 #if defined WINDOWS
3627 // ######################################
3628 #else
3629 // ######################################
3630 #endif
3631 return false;
3632}
3633
3634
3635
3636
3638// Desktop //
3640
3641bool GetDesktopSize(uint32& width, uint32& height) {
3642 width = height = 0;
3643 #if defined WINDOWS
3644 RECT desktop;
3645 // Get a handle to the desktop window
3646 const HWND hDesktop = GetDesktopWindow();
3647 // Get the size of screen to the variable desktop
3648 if (!GetWindowRect(hDesktop, &desktop))
3649 return false;
3650 // The top left corner will have coordinates (0,0)
3651 // and the bottom right corner will have coordinates
3652 // (horizontal, vertical)
3653 width = (uint32)desktop.right;
3654 height = (uint32)desktop.bottom;
3655 return true;
3656 #else
3657 return false;
3658 #endif
3659}
3660
3661bool RenameConsoleWindow(const char* name, bool prepend) {
3662 #if defined WINDOWS
3663 if (prepend) {
3664 uint32 size;
3665 char* oldName = new char[1024];
3666 if (!GetConsoleTitle(oldName, 1024)) {
3667 delete [] oldName;
3668 return false;
3669 }
3670 char* newName = StringFormat(size, "%s - %s", name, oldName);
3671 bool res = (SetConsoleTitle(name) != 0);
3672 delete [] newName;
3673 delete [] oldName;
3674 return res;
3675 }
3676 else
3677 return (SetConsoleTitle(name) != 0);
3678 #else
3679 return false;
3680 #endif
3681}
3682
3683bool MoveConsoleWindow(int32 x, int32 y, int32 w, int32 h) {
3684 #if defined WINDOWS
3685 char* consoleName = new char[1024];
3686 if (!GetConsoleTitle(consoleName, 1024)) {
3687 delete [] consoleName;
3688 return false;
3689 }
3690 HWND handle = FindWindow(NULL, consoleName);
3691 if (!handle) {
3692 delete [] consoleName;
3693 return false;
3694 }
3695 RECT wRect;
3696 if (!GetWindowRect(handle, &wRect)) {
3697 delete [] consoleName;
3698 return false;
3699 }
3700
3701 int conX = (x<0) ? wRect.left : x;
3702 int conY = (y<0) ? wRect.top : y;
3703 int conW = (w<0) ? wRect.right - wRect.left : w;
3704 int conH = (h<0) ? wRect.bottom - wRect.top : h;
3705
3706 bool res = (MoveWindow(handle, conX, conY, conW, conH, true) != 0);
3707 delete [] consoleName;
3708 return res;
3709
3710 #else
3711 return false;
3712 #endif
3713}
3714
3715
3717// Processes //
3719
3721 #if defined WINDOWS
3722 return (uint32)GetCurrentProcessId();
3723 #else
3724 return (uint32)getpid();
3725 #endif
3726}
3727
3728
3729int RunOSCommand(const char* cmdline, const char* initdir, uint32 timeout, std::string& stdoutString, std::string& stderrString) {
3730 if (!cmdline || !strlen(cmdline))
3731 return -1;
3732
3733 #if defined WINDOWS
3734 HANDLE g_hChildStd_OUT_Rd = NULL;
3735 HANDLE g_hChildStd_OUT_Wr = NULL;
3736 HANDLE g_hChildStd_ERR_Rd = NULL;
3737 HANDLE g_hChildStd_ERR_Wr = NULL;
3738
3739 SECURITY_ATTRIBUTES sa;
3740 // Set the bInheritHandle flag so pipe handles are inherited.
3741 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
3742 sa.bInheritHandle = TRUE;
3743 sa.lpSecurityDescriptor = NULL;
3744 // Create a pipe for the child process's STDERR.
3745 if ( ! CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &sa, 0) ) {
3746 return -1;
3747 }
3748 // Ensure the read handle to the pipe for STDERR is not inherited.
3749 if ( ! SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0) ){
3750 return -1;
3751 }
3752 // Create a pipe for the child process's STDOUT.
3753 if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0) ) {
3754 return -1;
3755 }
3756 // Ensure the read handle to the pipe for STDOUT is not inherited
3757 if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ){
3758 return -1;
3759 }
3760 PROCESS_INFORMATION piProcInfo;
3761 STARTUPINFO siStartInfo;
3762 bool bSuccess = FALSE;
3763
3764 // Set up members of the PROCESS_INFORMATION structure.
3765 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
3766
3767 // Set up members of the STARTUPINFO structure.
3768 // This structure specifies the STDERR and STDOUT handles for redirection.
3769 ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
3770 siStartInfo.cb = sizeof(STARTUPINFO);
3771 siStartInfo.hStdError = g_hChildStd_ERR_Wr;
3772 siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
3773 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
3774
3775 uint32 size = 0;
3776 char* cmd = utils::StringFormat(size, cmdline);
3777
3778 // Create the child process.
3779 bSuccess = (CreateProcess(NULL,
3780 cmd, // command line
3781 NULL, // process security attributes
3782 NULL, // primary thread security attributes
3783 TRUE, // handles are inherited
3784 0, // creation flags
3785 NULL, // use parent's environment
3786 initdir, // use parent's current directory
3787 &siStartInfo, // STARTUPINFO pointer
3788 &piProcInfo) != 0); // receives PROCESS_INFORMATION
3789 CloseHandle(g_hChildStd_ERR_Wr);
3790 CloseHandle(g_hChildStd_OUT_Wr);
3791 // If an error occurs, exit the application.
3792 if ( ! bSuccess ) {
3793 return -1;
3794 }
3795
3796 uint64 startTime = GetTimeNow();
3797
3798 DWORD dwRead;
3799 char* chBuf = new char[PROCBUFSIZE];
3800 bSuccess = FALSE;
3801 for (;;) {
3802 bSuccess=(ReadFile( g_hChildStd_OUT_Rd, chBuf, PROCBUFSIZE, &dwRead, NULL) != 0);
3803 if( ! bSuccess || dwRead == 0 ) break;
3804 std::string s(chBuf, dwRead);
3805 stdoutString += s;
3806 if(GetTimeAgeMS(startTime) > (int32)timeout) break;
3807 }
3808 dwRead = 0;
3809 for (;;) {
3810 bSuccess=(ReadFile( g_hChildStd_ERR_Rd, chBuf, PROCBUFSIZE, &dwRead, NULL) != 0);
3811 if( ! bSuccess || dwRead == 0 ) break;
3812 std::string s(chBuf, dwRead);
3813 stderrString += s;
3814 if(GetTimeAgeMS(startTime) > (int32)timeout) break;
3815 }
3816 delete [] chBuf;
3817
3818 DWORD exitcode;
3819 if (GetExitCodeProcess(piProcInfo.hProcess, &exitcode) == STILL_ACTIVE) {
3820 TerminateProcess(piProcInfo.hProcess, 1);
3821 }
3822 CloseHandle(g_hChildStd_ERR_Rd);
3823 CloseHandle(g_hChildStd_OUT_Rd);
3824 CloseHandle(piProcInfo.hProcess);
3825 CloseHandle(piProcInfo.hThread);
3826 return exitcode;
3827 #else
3828 fflush(stdin);
3829 fflush(stdout);
3830 FILE* runfile = popen(cmdline, "r");
3831 if (runfile == NULL)
3832 return -1;
3833
3834 int exitcode = -1;
3835 int status;
3836 int res;
3837 int size = 4096;
3838 char* buffer = new char[size+1];
3839
3840 res = fread(buffer, 1, size, runfile);
3841 if (res <= 0) {
3842 status = pclose(runfile);
3843 exitcode = WEXITSTATUS(status);
3844 delete [] buffer;
3845 return exitcode;
3846 }
3847 do {
3848 buffer[res] = 0;
3849 stdoutString += buffer;
3850 } while (res = fread(buffer, 1, size, runfile));
3851
3852 status = pclose(runfile);
3853 exitcode = WEXITSTATUS(status);
3854 delete [] buffer;
3855 return exitcode;
3856
3857 //
3858 //int size = 1024;
3859 // char name[1024];
3860 // if (!RunOSTextCommand("uname -n", name, size))
3861 // return "";
3862 //
3863 //
3864 //int argc = 0;
3865 // char **argv=SplitCommandline(cmdline, argc);
3866 // if (!argc || !argv)
3867 // return -1;
3868
3869 // /* since pipes are unidirectional, we need two pipes.
3870 // one for data to flow from parent's stdout to child's
3871 // stdin and the other for child's stdout to flow to
3872 // parent's stdin */
3873
3874 // int* pipes = new int[NUM_PIPES][2];
3875 // int outfd[2];
3876 // int infd[2];
3877
3878 // // pipes for parent to write and read
3879 // pipe((*pipes)[PARENT_READ_PIPE]);
3880 // pipe((*pipes)[PARENT_WRITE_PIPE]);
3881
3882 // if(!fork()) {
3883
3884 // dup2(CHILD_READ_FD, STDIN_FILENO);
3885 // dup2(CHILD_WRITE_FD, STDOUT_FILENO);
3886
3887 // /* Close fds not required by child. Also, we don't
3888 // want the exec'ed program to know these existed */
3889 // close(CHILD_READ_FD);
3890 // close(CHILD_WRITE_FD);
3891 // close(PARENT_READ_FD);
3892 // close(PARENT_WRITE_FD);
3893
3894 // execv(argv[0], argv);
3895 // } else {
3896 // char buffer[100];
3897 // int count;
3898
3899 // /* close fds not required by parent */
3900 // close(CHILD_READ_FD);
3901 // close(CHILD_WRITE_FD);
3902
3903 // // Write to child�s stdin
3904 // //write(PARENT_WRITE_FD, "2^32\n", 5);
3905
3906 // // Read from child�s stdout
3907 // count = read(PARENT_READ_FD, buffer, sizeof(buffer)-1);
3908 // if (count >= 0) {
3909 // buffer[count] = 0;
3910 // printf("%s", buffer);
3911 // } else {
3912 // printf("IO Error\n");
3913 // }
3914 // // ################
3915 // // Not yet complete!!!
3916 // }
3917 #endif
3918
3919}
3920
3921
3922uint32 NewProcess(const char* cmdline, const char* initdir, const char* title, int16 x, int16 y, int16 w, int16 h) {
3923
3924 if (!cmdline || !strlen(cmdline))
3925 return 0;
3926
3927 #if defined WINDOWS
3928
3929 if (!ProcessInformationMap) {
3930 ProcessInformationMap = new std::map<uint32, ProcessData*>;
3931 ghJob = CreateJobObject(NULL, NULL); // GLOBAL
3932 if (ghJob) {
3933 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
3934 // Configure all child processes associated with the job to terminate when the
3935 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
3936 SetInformationJobObject(ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
3937 }
3938 }
3939
3940 ProcessData* pData = new ProcessData;
3941
3942 ZeroMemory(&(pData->procInfo), sizeof(pData->procInfo));
3943 ZeroMemory(&(pData->si), sizeof(pData->si));
3944 pData->si.cb = sizeof(pData->si);
3945 pData->si.wShowWindow = SW_SHOWNOACTIVATE; //SW_SHOW; // SW_HIDE;
3946
3947 if ( (x>=0) && (y>=0) && (w>=0) && (h>=0) ) {
3948 pData->si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USEPOSITION | STARTF_USESIZE;
3949 pData->si.dwX = x;
3950 pData->si.dwY = y;
3951 pData->si.dwXSize = w;
3952 pData->si.dwYSize = h;
3953 }
3954 else {
3955 pData->si.dwFlags = STARTF_USESHOWWINDOW;
3956 }
3957
3958 uint32 size = 0;
3959 char* titleCopy = NULL;
3960 if (title) {
3961 titleCopy = utils::StringFormat(size, title);
3962 pData->si.lpTitle = titleCopy;
3963 }
3964
3965 char* cmd = utils::StringFormat(size, cmdline);
3966 //utils::strcpyavail(cmd, cmdline, (uint32)strlen(cmdline)+1, true);
3967
3968 // DETACHED_PROCESS
3969 int res = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, initdir, &pData->si, &pData->procInfo);
3970 delete [] titleCopy;
3971 delete [] cmd;
3972 if (res == 0) {
3973 char* msg = new char[2048];
3974 int length = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
3975 NULL, GetLastError(), 0, msg, sizeof(msg), NULL);
3976 msg[length] = '\0';
3977 LogPrint(0, LOG_SYSTEM, 0, "Error creating new process: %s\n%s", msg, cmd);
3978 delete [] msg;
3979 delete pData;
3980 return 0;
3981 }
3982
3983 if (ghJob)
3984 AssignProcessToJobObject(ghJob, pData->procInfo.hProcess);
3985
3986 ProcessInformationMap->insert(Proc_Pair((uint32)pData->procInfo.dwProcessId, pData));
3987 return pData->procInfo.dwProcessId;
3988
3989 #else
3990
3991 //std::vector<std::string> args = utils::TextListSplit(cmdline, " ");
3992 //int argc = args.size();
3994 //char** argv = new char*[argc+1];
3995 //int len;
3996 //for (int n=0; n<argc; n++) {
3997 // argv[n] = new char[args[n].size() + 1];
3998 // utils::strcpyavail(argv[n], args[n].c_str(), args[n].size()+1, true);
3999 //}
4000 //argv[argc] = NULL;
4001
4002 int argc = 0;
4003 char** argv = SplitCommandline(cmdline, argc);
4004 if (!argc)
4005 return -1;
4006
4007 pid_t ppid_before_fork = getpid();
4008 int pid = fork();
4009
4010 if (pid < 0) {
4011 DeleteCommandline(argv, argc);
4012 return 0;
4013 }
4014 // We are the child process
4015 else if (pid == 0) {
4016
4017 if ( initdir && (chdir(initdir) != 0) ) {
4018 LogPrint(0,LOG_SYSTEM,0,"Could not run process '%s' from starup dir '%s'\n", cmdline, initdir);
4019 exit(0);
4020 }
4021
4022 #ifndef __APPLE__
4023 int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
4024 if (r == -1) { perror(0); exit(1); }
4025 // test in case the original parent exited just
4026 // before the prctl() call
4027 if (getppid() != ppid_before_fork)
4028 exit(1);
4029 #endif
4030
4031 execvp(argv[0],argv);
4032 // here we exit the program, if we continue the call failed...
4033
4034 int res = errno;
4035 // If program didn't take over the exec call failed.
4036 LogPrint(0,LOG_SYSTEM,0,"Could not create new process: %s (%d)!\n", cmdline, res);
4037 exit(0);
4038
4039 }
4040 // we are in the calling process
4041 else {
4042 DeleteCommandline(argv, argc);
4043 return pid;
4044 }
4045
4046 #endif
4047}
4048
4049uint8 GetProcessStatus(uint32 proc, int &returncode) {
4050 returncode = 0;
4051 #if defined WINDOWS
4052 DWORD exitcode;
4053 std::map<uint32, ProcessData*>::iterator i = ProcessInformationMap->find(proc);
4054 if (i != ProcessInformationMap->end()) {
4055 ProcessData* pData = i->second;
4056 if (GetExitCodeProcess(pData->procInfo.hProcess, &exitcode) == STILL_ACTIVE) {
4057 return PROC_RUNNING;
4058 }
4059 else {
4060 ProcessInformationMap->erase(i);
4061 CloseHandle(pData->procInfo.hProcess);
4062 CloseHandle(pData->procInfo.hThread);
4063 delete pData;
4064 returncode = exitcode;
4065 return PROC_TERMINATED;
4066 }
4067 }
4068 else {
4069 // We didn't create this process, look it up by id
4070 HANDLE hproc = OpenProcess(NULL, false, (DWORD)proc);
4071 if (!hproc)
4072 return PROC_ERROR;
4073 if (GetExitCodeProcess(hproc, &exitcode) == STILL_ACTIVE) {
4074 CloseHandle(hproc);
4075 return PROC_RUNNING;
4076 }
4077 else {
4078 CloseHandle(hproc);
4079 return PROC_TERMINATED;
4080 }
4081 }
4082 #else
4083 int status;
4084 int res = waitpid(proc, &status, WNOHANG);
4085
4086 if (res == proc) {
4087 //if (WIFEXITED(status)) {
4088 // printf("exited, status=%d\n", WEXITSTATUS(status));
4089 // } else if (WIFSIGNALED(status)) {
4090 // printf("killed by signal %d\n", WTERMSIG(status));
4091 // } else if (WIFSTOPPED(status)) {
4092 // printf("stopped by signal %d\n", WSTOPSIG(status));
4093 // } else if (WIFCONTINUED(status)) {
4094 // printf("continued\n");
4095 // }
4096 returncode = WEXITSTATUS(status);
4097 //printf("Return code: %d\n", returncode);
4098 return PROC_TERMINATED;
4099 }
4100 else if (res == 0) {
4101 return PROC_RUNNING;
4102 }
4103 return PROC_TERMINATED;
4104 #endif
4105}
4106
4107bool EndProcess(uint32 proc) {
4108 #if defined WINDOWS
4109 if (!ProcessInformationMap)
4110 return true;
4111 std::map<uint32, ProcessData*>::iterator i = ProcessInformationMap->find(proc);
4112 if (i != ProcessInformationMap->end()) {
4113 ProcessData* pData = i->second;
4114 TerminateProcess(pData->procInfo.hProcess, 1);
4115 CloseHandle(pData->procInfo.hProcess);
4116 CloseHandle(pData->procInfo.hThread);
4117 ProcessInformationMap->erase(i);
4118 delete pData;
4119 return true;
4120 }
4121 else {
4122 HANDLE hproc = OpenProcess(NULL, NULL, (DWORD)proc);
4123 if (!hproc)
4124 return true;
4125 if (TerminateProcess(hproc, 1) == 0) {
4126 CloseHandle(hproc);
4127 return false;
4128 }
4129 else {
4130 CloseHandle(hproc);
4131 return true;
4132 }
4133 }
4134 #else
4135 return (kill(proc, SIGKILL) == 0);
4136 #endif
4137}
4138
4139uint8 WaitForProcess(uint32 proc, uint32 timeout, int &returncode) {
4140 #if defined WINDOWS
4141 DWORD exitcode;
4142 std::map<uint32, ProcessData*>::iterator i = ProcessInformationMap->find(proc);
4143 if (i != ProcessInformationMap->end()) {
4144 ProcessData* pData = i->second;
4145 if (WaitForSingleObject(pData->procInfo.hProcess, timeout) == WAIT_OBJECT_0) {
4146 if (GetExitCodeProcess(pData->procInfo.hProcess, &exitcode) == STILL_ACTIVE) {
4147 return PROC_RUNNING;
4148 }
4149 else {
4150 returncode = exitcode;
4151 CloseHandle(pData->procInfo.hProcess);
4152 CloseHandle(pData->procInfo.hThread);
4153 ProcessInformationMap->erase(i);
4154 delete pData;
4155 return PROC_TERMINATED;
4156 }
4157 }
4158 return PROC_TIMEOUT;
4159 }
4160 else {
4161 HANDLE hproc = OpenProcess(NULL, NULL, (DWORD)proc);
4162 if (!hproc) {
4163 return PROC_ERROR;
4164 }
4165 if (WaitForSingleObject(hproc, timeout) == WAIT_OBJECT_0) {
4166 if (GetExitCodeProcess(hproc, &exitcode) == STILL_ACTIVE) {
4167 CloseHandle(hproc);
4168 return PROC_RUNNING;
4169 }
4170 else {
4171 returncode = exitcode;
4172 CloseHandle(hproc);
4173 return PROC_TERMINATED;
4174 }
4175 }
4176 else {
4177 CloseHandle(hproc);
4178 return PROC_RUNNING;
4179 }
4180 }
4181 #else
4182 uint64 start = GetTimeNow();
4183 do {
4184 if (GetProcessStatus(proc, returncode) < PROC_RUNNING)
4185 return PROC_TERMINATED;
4186 utils::Sleep(10);
4187 } while (GetTimeAgeMS(start) < timeout);
4188 return PROC_RUNNING;
4189
4190 #endif
4191}
4192
4193
4194
4195
4196
4197
4198
4199
4200
4202// DLL Libraries //
4204
4205bool SetCommandLine(int argc, char* argv[]) {
4206
4209
4210 std::string key;
4211 const char* val;
4212 int32 n;
4213 CommandLineInfo::CommandLineInfoSingleton->CommandLineString = CommandLineInfo::CommandLineInfoSingleton->CommandLineExec = argv[0];
4214 CommandLineInfo::CommandLineInfoSingleton->CommandLineItems.push_back(argv[0]);
4215 for (n=1; n<argc; n++) {
4216 CommandLineInfo::CommandLineInfoSingleton->CommandLineItems.push_back(argv[n]);
4217 key = argv[n];
4218 val = strchr(argv[n], '=');
4219 if (val)
4220 CommandLineInfo::CommandLineInfoSingleton->CommandLineArgs[key.substr(0, val-argv[n])] = val+1;
4221 CommandLineInfo::CommandLineInfoSingleton->CommandLineString += ' ';
4222 CommandLineInfo::CommandLineInfoSingleton->CommandLineString += argv[n];
4223 }
4224
4225 //printf("Full: '%s'\n", CommandLineString.c_str());
4226 //printf("Base: '%s'\n", CommandLineExec.c_str());
4227
4228 //n = 0;
4229 //std::vector<std::string>::iterator it = CommandLineItems.begin(), itEnd = CommandLineItems.end();
4230 //while (it != itEnd) {
4231 // printf("[%u] '%s'\n", n++, (*it).c_str());
4232 // it++;
4233 //}
4234
4235 //n = 0;
4236 //std::map<std::string, std::string>::iterator mit = CommandLineArgs.begin(), mitEnd = CommandLineArgs.end();
4237 //while (mit != mitEnd) {
4238 // printf("[%u] '%s' = '%s'\n", n++, mit->first.c_str(), mit->second.c_str());
4239 // mit++;
4240 //}
4241
4242 //printf("Executable: '%s' '%s'\n", GetCommandLinePath().c_str(), GetCommandLineExecutableOnly().c_str());
4243 return true;
4244}
4245
4246std::string GetCommandLine() {
4248 return "";
4249 return CommandLineInfo::CommandLineInfoSingleton->CommandLineString;
4250}
4251
4252std::string GetCommandLinePath() {
4254 return "";
4255 std::string::size_type p1 = CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.find_last_of('/');
4256 std::string::size_type p2 = CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.find_last_of('\\');
4257 if (p1 == std::string::npos) {
4258 if (p2 == std::string::npos)
4259 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec;
4260 else
4261 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr(0, p2+1);
4262 }
4263 else if (p2 == std::string::npos)
4264 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr(0, p1+1);
4265 else
4266 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr(0, (p1 > p2) ? p1+1 : p2+1);
4267}
4268
4271 return "";
4272 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec;
4273}
4274
4277 return "";
4278 std::string::size_type p1 = CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.find_last_of('/');
4279 std::string::size_type p2 = CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.find_last_of('\\');
4280 if (p1 == std::string::npos) {
4281 if (p2 == std::string::npos)
4282 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec;
4283 else
4284 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr(p2+1);
4285 }
4286 else if (p2 == std::string::npos)
4287 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr(p1+1);
4288 else
4289 return CommandLineInfo::CommandLineInfoSingleton->CommandLineExec.substr((p1 > p2) ? p1+1 : p2+1);
4290}
4291
4294 return 0;
4295 return (uint32)CommandLineInfo::CommandLineInfoSingleton->CommandLineItems.size();
4296}
4297
4298std::string GetCommandLineArg(uint16 n) {
4300 return "";
4301 return CommandLineInfo::CommandLineInfoSingleton->CommandLineItems[n];
4302}
4303
4304std::string GetCommandLineArg(const char* key) {
4306 return "";
4307 return CommandLineInfo::CommandLineInfoSingleton->CommandLineArgs[key];
4308}
4309
4310bool HasCommandLineArg(const char* key, std::string& value) {
4312 return false;
4313 std::map<std::string, std::string>::const_iterator it =
4314 CommandLineInfo::CommandLineInfoSingleton->CommandLineArgs.find(key);
4315 if (it == CommandLineInfo::CommandLineInfoSingleton->CommandLineArgs.end())
4316 return false;
4317 value = it->second;
4318 return true;
4319}
4320
4321
4322
4324 handle = NULL;
4325}
4327 if (handle) {
4328 #ifdef WINDOWS
4329 FreeLibrary(handle);
4330 #else // WINDOWS
4331 // dlclose() bug: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=28625
4332 // __dso_handle unreferenced
4333 // if there are any globally desclared objects in the library!!!
4334 dlclose(handle);
4335 #endif // WINDOWS
4336 }
4337}
4338
4339std::string Library::patchLibraryFilename(const char* filename, const char* path) {
4340 #ifdef WINDOWS
4341 return filename;
4342 #else
4343 std::string realLibName;
4344 if (utils::TextEndsWith(filename, ".so"))
4345 realLibName = filename;
4346 else
4347 realLibName = utils::StringFormat("%s.so", filename);
4348
4349 int32 filenameStart;
4350 if ( (filenameStart = realLibName.find_last_of('/') == std::string::npos ))
4351 filenameStart = 0;
4352 else
4353 filenameStart++;
4354
4355 if (!utils::TextStartsWith(filename + filenameStart, "lib", true))
4356 realLibName.insert(filenameStart, "lib");
4357
4358 if (!filenameStart) {
4359 if (!path)
4360 realLibName.insert(0, "./");
4361 else
4362 realLibName.insert(0, path);
4363 }
4364
4365 return realLibName;
4366 #endif
4367}
4368
4369bool Library::load(const char* filename) {
4370 if (!filename)
4371 return false;
4372 std::string errorText;
4373 //printf("Trying to find library: '%s'...\n", filename);
4374
4375 #ifdef WINDOWS
4376 LPVOID lpMsgBuf; //Message Buffer
4377 #ifdef _DEBUG
4378 handle = LoadLibrary(utils::StringFormat("%sDebug", filename).c_str());
4379 if (handle == NULL) {
4380 FormatMessage(
4381 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
4382 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
4383 (LPTSTR)&lpMsgBuf, 0, NULL);
4384 LogPrint(0, LOG_SYSTEM, 0, "Could not find or load debug library '%sDebug': %s", filename, lpMsgBuf);
4385 LocalFree(lpMsgBuf);
4386 return false;
4387 }
4388 #else
4389 handle = LoadLibrary(filename);
4390 if (handle == NULL) {
4391 FormatMessage(
4392 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
4393 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
4394 (LPTSTR) &lpMsgBuf, 0, NULL);
4395 LogPrint(0, LOG_SYSTEM, 0, "Could not find or load library '%s': %s", filename, lpMsgBuf);
4396 LocalFree(lpMsgBuf);
4397 return false;
4398 }
4399 #endif
4400 #else // WINDOWS
4401 handle = 0;
4402 const char* dlErrorText;
4403 std::string realLibName = patchLibraryFilename(filename);
4404 //printf("Trying patched library: '%s'...\n", realLibName.c_str());
4405
4406 // clear errors
4407 dlerror();
4408 #ifdef _DEBUG
4409 std::string debugName = realLibName;
4410 utils::StringSingleReplace(debugName, ".so", "Debug.so", true);
4411 // printf("Trying debug library: '%s'...\n", debugName.c_str());
4412 handle = dlopen(debugName.c_str(), RTLD_NOW | RTLD_GLOBAL);
4413 if (!handle) {
4414 dlErrorText = dlerror();
4415 // printf("Error 1: '%s'...\n", dlErrorText);
4416 if (dlErrorText && strlen(dlErrorText) &&
4417 !(strstr(dlErrorText, "No such file") && strstr(dlErrorText, debugName.c_str())))
4418 errorText = dlErrorText;
4419 }
4420 #endif
4421
4422 if (!handle && !errorText.size()) {
4423 // handle = dlopen(realLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
4424 if (!handle) {
4425 dlErrorText = dlerror();
4426 // printf("Error 2: '%s'...\n", dlErrorText);
4427 if (dlErrorText && strlen(dlErrorText) &&
4428 !(strstr(dlErrorText, "No such file") && strstr(dlErrorText, realLibName.c_str())))
4429 errorText = dlErrorText;
4430 }
4431 }
4432
4433 if (!handle && !errorText.size() && !strchr(filename, '/')) {
4434 realLibName = patchLibraryFilename(filename, utils::GetCommandLinePath().c_str());
4435 // printf("Trying library: '%s'...\n", realLibName.c_str());
4436 handle = dlopen(realLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
4437 if (!handle) {
4438 dlErrorText = dlerror();
4439 // printf("Error 3: '%s'...\n", dlErrorText);
4440 if (dlErrorText && strlen(dlErrorText) &&
4441 !(strstr(dlErrorText, "No such file") && strstr(dlErrorText, realLibName.c_str())))
4442 errorText = dlErrorText;
4443 }
4444 }
4445
4446 if (handle == NULL) {
4447 if (errorText.size())
4448 LogPrint(0, LOG_SYSTEM, 0, "Could not load library file '%s': %s", realLibName.c_str(), errorText.c_str());
4449 else
4450 LogPrint(0, LOG_SYSTEM, 0, "Could not find library file '%s'", filename);
4451 return false;
4452 }
4453 #endif // WINDOWS
4454 return true;
4455}
4456
4458 if (handle == NULL)
4459 return NULL;
4460 if (!strlen(funcName))
4461 return NULL;
4462
4463 LibraryFunction func;
4464
4465 #ifdef WINDOWS
4466 func = (LibraryFunction)GetProcAddress(handle, funcName);
4467 if (func == NULL) {
4468 LPVOID lpMsgBuf; //Message Buffer
4469 //Generate Error Message from GetLastError
4470 FormatMessage(
4471 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
4472 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
4473 (LPTSTR) &lpMsgBuf, 0, NULL);
4474 LogPrint(0, LOG_SYSTEM, 0, "Could not find library function: %s: %s", funcName, lpMsgBuf);
4475 // Free the buffer.
4476 LocalFree(lpMsgBuf);
4477 return NULL;
4478 }
4479 #else // WINDOWS
4480 const char* errmsg;
4481 dlerror();
4482 func = (LibraryFunction)dlsym(handle, funcName);
4483 errmsg = dlerror();
4484 if (errmsg != NULL) {
4485 LogPrint(0, LOG_SYSTEM, 0, "Could not find library function: %s: %s", (char*) funcName, (char*) errmsg);
4486 return NULL;
4487 }
4488 #endif // WINDOWS
4489 return func;
4490}
4491
4492Library* OpenLibrary(const char* libName) {
4493 Library* lib = new Library();
4494 if (!lib->load(libName)) {
4495 delete(lib);
4496 return NULL;
4497 }
4498 return lib;
4499}
4500
4501
4503// OS System //
4505
4506char OSLocalHostName[1024] = {0};
4507char OSArchitectureName[1024] = {0};
4508char OSName[1024] = {0};
4509
4510const char* GetComputerName() {
4511 //char name[1024];
4512 char* name = new char[1024];
4513 if (strlen(OSLocalHostName) == 0) {
4514 #ifdef WINDOWS
4515
4516 DWORD size = 1024;
4517 #ifdef POCKETPC
4518 delete [] name;
4519 return "PocketPC";
4520 #else
4521 if (::GetComputerName(name, &size) == 0) {
4522 delete [] name;
4523 return "";
4524 }
4525 else
4526 utils::strcpyavail(OSLocalHostName, name, 1024, true);
4527 #endif
4528
4529 //if (gethostname(name, 1024) == 0)
4530 // strcpy(OSLocalHostName, name);
4531 //else {
4532 // int er = WSAGetLastError();
4533 // if (er == WSANOTINITIALISED) {
4534 // WSADATA info;
4535 // if (WSAStartup(MAKEWORD(1,1), &info) == 0) {
4536 // // Now we can retry the socket() function
4537 // if (gethostname(hname, 1000) == 0)
4538 // strcpy(OSLocalHostName, name);
4539 // }
4540 // }
4541 //}
4542 #else
4543 std::string outString, errString;
4544 if (!RunOSCommand("uname -n", NULL, 1000, outString, errString)) {
4545 //if (!RunOSTextCommand("uname -n", name, size))
4546 delete [] name;
4547 return "";
4548 }
4549 else
4550 utils::strcpyavail(OSLocalHostName, outString.c_str(), 1024, true);
4551 #endif // WINDOWS
4552 }
4553 delete [] name;
4554 return OSLocalHostName;
4555}
4556
4558
4559 #if defined WINDOWS
4560 HANDLE hProcess = GetCurrentProcess();
4561 PROCESS_MEMORY_COUNTERS pmc;
4562 if (hProcess == NULL)
4563 return 0;
4564 if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) != 0)
4565 return (uint64)pmc.WorkingSetSize;
4566 else
4567 return 0;
4568 #elif defined OSX
4569 struct task_basic_info_64 info;
4570 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
4571 if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t)&info, &count) == KERN_SUCCESS)
4572 return (uint64)info.resident_size;
4573 return 0;
4574 #else
4575 /* Linux ---------------------------------------------------- */
4576 long rss = 0L;
4577 FILE* fp = NULL;
4578 if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
4579 return (uint64)0L; /* Can't open? */
4580 if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) {
4581 fclose( fp );
4582 return (uint64)0L; /* Can't read? */
4583 }
4584 fclose( fp );
4585 return (uint64)rss * (uint64)sysconf( _SC_PAGESIZE);
4586 #endif
4587}
4588
4590
4591 #if defined WINDOWS
4592 HANDLE hProcess = GetCurrentProcess();
4593 PROCESS_MEMORY_COUNTERS pmc;
4594 if (hProcess == NULL)
4595 return 0;
4596 if ( GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)) != 0)
4597 return (uint64)pmc.PeakWorkingSetSize;
4598 else
4599 return 0;
4600 #elif defined OSX
4601 // macOS/BSD: ru_maxrss is in bytes (Linux uses KB)
4602 struct rusage usage;
4603 getrusage(RUSAGE_SELF, &usage);
4604 return (uint64)usage.ru_maxrss;
4605 #else
4606 // Linux: ru_maxrss is in KB
4607 struct rusage usage;
4608 getrusage( RUSAGE_SELF, &usage );
4609 return ((uint64)usage.ru_maxrss) * 1024L;
4610
4611
4613 //struct psinfo psinfo;
4614 //int fd = -1;
4615 //if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
4616 // return (size_t)0L; /* Can't open? */
4617 //if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
4618 //{
4619 // close( fd );
4620 // return (size_t)0L; /* Can't read? */
4621 //}
4622 //close( fd );
4623 //return (size_t)(psinfo.pr_rssize * 1024L);
4624
4625 #endif
4626}
4627
4628
4629uint16 GetCPUCount() {
4630 #if defined WINDOWS
4631 SYSTEM_INFO siSysInfo;
4632 GetSystemInfo(&siSysInfo);
4633 return (uint16) siSysInfo.dwNumberOfProcessors;
4634 #elif defined OSX
4635 int ncpu = 0;
4636 size_t len = sizeof(ncpu);
4637 if (sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0) == 0 && ncpu > 0)
4638 return (uint16)(ncpu > 65535 ? 65535 : ncpu);
4639 return 0;
4640 #else
4641 long n = sysconf(_SC_NPROCESSORS_ONLN);
4642 if (n > 0)
4643 return (uint16)(n > 65535 ? 65535 : (uint16)n);
4644 return 0;
4645 #endif
4646}
4647
4649 #if defined WINDOWS
4650 SYSTEM_INFO siSysInfo;
4651 GetSystemInfo(&siSysInfo);
4652 switch(siSysInfo.wProcessorArchitecture) {
4653 case PROCESSOR_ARCHITECTURE_AMD64:
4654 return OSCPU_AMD64;
4655 case PROCESSOR_ARCHITECTURE_IA64:
4656 return OSCPU_IA64;
4657 case PROCESSOR_ARCHITECTURE_INTEL:
4658 return OSCPU_X86;
4659 default:
4660 return OSCPU_UNKNOWN;
4661 }
4662 #elif defined OSX
4663 #if defined(__x86_64__)
4664 return OSCPU_AMD64;
4665 #elif defined(__i386__)
4666 return OSCPU_X86;
4667 #elif defined(__aarch64__)
4668 return OSCPU_UNKNOWN;
4669 #else
4670 return OSCPU_UNKNOWN;
4671 #endif
4672 #else
4673 #if defined(__x86_64__)
4674 return OSCPU_AMD64;
4675 #elif defined(__i386__)
4676 return OSCPU_X86;
4677 #elif defined(__aarch64__)
4678 return OSCPU_UNKNOWN;
4679 #else
4680 return OSCPU_UNKNOWN;
4681 #endif
4682 #endif
4683}
4684
4685uint64 GetCPUSpeed() {
4686 #if defined WINDOWS
4687 //HKEY hKey;
4688 //LONG lRet;
4689
4690 // Test for SP6 versus SP6a.
4691 //JString key = "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0";
4692 //lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hKey );
4693 //if( lRet == ERROR_SUCCESS ) {
4694 // DWORD len = sizeof(int);
4695 // BYTE data[sizeof(int)];
4696 // key = "~MHz";
4697 // lRet = RegQueryValueEx(hKey, key, NULL, NULL, data, &len);
4698 // if (lRet == ERROR_SUCCESS) {
4699 // RegCloseKey(hKey);
4700 // return (uint64) (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + (data[0] << 0);
4701 // }
4702 // else {
4703 // RegCloseKey(hKey);
4704 // return 0;
4705 // }
4706 //}
4707 #elif defined OSX
4708 uint64 freq = 0;
4709 size_t len = sizeof(freq);
4710 if (sysctlbyname("hw.cpufrequency", &freq, &len, NULL, 0) == 0)
4711 return freq;
4712 return 0;
4713 #else
4714 // Linux: optional /proc/cpuinfo cpu MHz
4715 std::ifstream cpuinfo("/proc/cpuinfo");
4716 std::string line;
4717 while (cpuinfo && getline(cpuinfo, line)) {
4718 if (line.compare(0, 7, "cpu MHz") == 0) {
4719 size_t colon = line.find(':');
4720 if (colon != std::string::npos) {
4721 double mhz = 0;
4722 if (sscanf(line.c_str() + colon + 1, "%lf", &mhz) == 1 && mhz > 0)
4723 return (uint64)(mhz * 1000000.0);
4724 }
4725 break;
4726 }
4727 }
4728 #endif
4729 return 0;
4730}
4731
4733 #if defined WINDOWS
4734 MEMORYSTATUS memstat;
4735 GlobalMemoryStatus(&memstat);
4736 return (uint64)memstat.dwTotalPhys;
4737 #else
4738 #ifdef __APPLE__
4739 uint64 memsize = 0;
4740 size_t len = sizeof(memsize);
4741 if (sysctlbyname("hw.memsize", &memsize, &len, NULL, 0) == 0)
4742 return memsize;
4743 return 0;
4744 #else
4745 struct sysinfo info;
4746 if (sysinfo(&info) == 0)
4747 return info.totalram;
4748 else
4749 return 0;
4750 #endif
4751 #endif
4752 return 0;
4753}
4754
4755bool GetSystemMemoryUsage(uint64 &totalRAM, uint64 &freeRAM) {
4756 #if defined WINDOWS
4757 MEMORYSTATUSEX memstat;
4758 memset(&memstat, 0, sizeof(MEMORYSTATUSEX));
4759 memstat.dwLength = sizeof(MEMORYSTATUSEX);
4760 if (!GlobalMemoryStatusEx(&memstat)) {
4761 int a = GetLastError();
4762 return false;
4763 }
4764 totalRAM = (uint64)memstat.ullTotalPhys;
4765 freeRAM = (uint64)memstat.ullAvailPhys;
4766 return true;
4767 #else
4768 #ifdef __APPLE__
4769 uint64 memsize = 0;
4770 size_t len = sizeof(memsize);
4771 if (sysctlbyname("hw.memsize", &memsize, &len, NULL, 0) != 0)
4772 return false;
4773 totalRAM = memsize;
4774 vm_statistics64_data_t vm_stat;
4775 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
4776 if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) != KERN_SUCCESS)
4777 return false;
4778 vm_size_t page_size;
4779 if (host_page_size(mach_host_self(), &page_size) != KERN_SUCCESS)
4780 return false;
4781 freeRAM = (uint64)vm_stat.free_count * (uint64)page_size;
4782 return true;
4783 #else
4784 struct sysinfo info;
4785 if (sysinfo(&info) == 0) {
4786 totalRAM = info.totalram;
4787 freeRAM = info.freeram;
4788 return true;
4789 }
4790 else
4791 return false;
4792 #endif
4793 #endif
4794}
4795
4797 if (strlen(OSArchitectureName) == 0) {
4798 #if defined WINDOWS
4799 SYSTEM_INFO siSysInfo;
4800 GetSystemInfo(&siSysInfo);
4801
4802 switch(siSysInfo.wProcessorArchitecture) {
4803 case PROCESSOR_ARCHITECTURE_UNKNOWN:
4804 utils::strcpyavail(OSArchitectureName, "i386", 1024, true);
4805 case PROCESSOR_ARCHITECTURE_INTEL:
4806 switch(siSysInfo.wProcessorLevel) {
4807 case 3:
4808 utils::strcpyavail(OSArchitectureName, "i386", 1024, true);
4809 break;
4810 case 4:
4811 utils::strcpyavail(OSArchitectureName, "i486", 1024, true);
4812 break;
4813 case 5:
4814 utils::strcpyavail(OSArchitectureName, "i586", 1024, true);
4815 break;
4816 case 6:
4817 utils::strcpyavail(OSArchitectureName, "i686", 1024, true);
4818 break;
4819 case 7:
4820 utils::strcpyavail(OSArchitectureName, "i786", 1024, true);
4821 break;
4822 case 8:
4823 utils::strcpyavail(OSArchitectureName, "i886", 1024, true);
4824 break;
4825 case 9:
4826 utils::strcpyavail(OSArchitectureName, "i986", 1024, true);
4827 break;
4828 default:
4829 utils::strcpyavail(OSArchitectureName, "i686", 1024, true);
4830 break;
4831 }
4832 case PROCESSOR_ARCHITECTURE_MIPS:
4833 utils::strcpyavail(OSArchitectureName, "mips", 1024, true);
4834 break;
4835 case PROCESSOR_ARCHITECTURE_ALPHA:
4836 utils::strcpyavail(OSArchitectureName, "alpha", 1024, true);
4837 break;
4838 case PROCESSOR_ARCHITECTURE_PPC:
4839 utils::strcpyavail(OSArchitectureName, "ppc", 1024, true);
4840 break;
4841 case PROCESSOR_ARCHITECTURE_IA64:
4842 utils::strcpyavail(OSArchitectureName, "ia64", 1024, true);
4843 break;
4844 case PROCESSOR_ARCHITECTURE_AMD64:
4845 utils::strcpyavail(OSArchitectureName, "amd64", 1024, true);
4846 break;
4847 default:
4848 break;
4849 }
4850 #else
4851 // ######################################
4852 #endif
4853 }
4854 return OSArchitectureName;
4855}
4856
4857const char* GetSystemOSName() {
4858 if (strlen(OSName) == 0) {
4859 #if defined WINDOWS
4860 #ifdef POCKETPC
4861 utils::strcpyavail(OSName, "Microsoft PocketPC", 1024, true);
4862 #else
4863 switch(GetCPUArchitecture()) {
4864 case OSCPU_AMD64:
4865 utils::strcpyavail(OSName, "Microsoft Windows X64", 1024, true);
4866 break;
4867 case OSCPU_IA64:
4868 utils::strcpyavail(OSName, "Microsoft Windows IA64", 1024, true);
4869 break;
4870 case OSCPU_X86:
4871 utils::strcpyavail(OSName, "Microsoft Windows X86", 1024, true);
4872 break;
4873 default:
4874 utils::strcpyavail(OSName, "Microsoft Windows", 1024, true);
4875 break;
4876 }
4877 #endif
4878 #else
4879 // ######################################
4880 #endif
4881 }
4882 return OSName;
4883}
4884
4885bool GetSystemOSVersion(uint16& major, uint16& minor, uint16& build, char* text, uint16 textSize) {
4886 major = 0;
4887 minor = 0;
4888 build = 0;
4889 text[0] = 0;
4890 #if defined WINDOWS
4891 #ifdef POCKETPC
4892
4893 OSVERSIONINFO osvi;
4894 BOOL bOsVersionInfoEx;
4895
4896 // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
4897 // If that fails, try using the OSVERSIONINFO structure.
4898
4899 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
4900 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
4901
4902 if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
4903 {
4904 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
4905 if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
4906 return false;
4907 }
4908
4909 major = osvi.dwMajorVersion;
4910 minor = osvi.dwMinorVersion;
4911 if (strlen((char*)osvi.szCSDVersion) < textSize)
4912 utils::strcpyavail(text, (char*)osvi.szCSDVersion, textSize, true);
4913 #else
4914
4915 OSVERSIONINFOEX osvi;
4916 BOOL bOsVersionInfoEx;
4917
4918 // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
4919 // If that fails, try using the OSVERSIONINFO structure.
4920
4921 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
4922 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
4923
4924 if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
4925 {
4926 osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
4927 if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
4928 return false;
4929 }
4930
4931 switch (osvi.dwPlatformId)
4932 {
4933 // Test for the Windows NT product family.
4934 case VER_PLATFORM_WIN32_NT:
4935
4936 // Display service pack (if any) and build number.
4937
4938 if( osvi.dwMajorVersion == 4 &&
4939 lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 )
4940 {
4941 HKEY hKey;
4942 LONG lRet;
4943
4944 // Test for SP6 versus SP6a.
4945 lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
4946 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009",
4947 0, KEY_QUERY_VALUE, &hKey );
4948 if( lRet == ERROR_SUCCESS ) {
4949 if (textSize > 16)
4950 utils::strcpyavail(text, "Service Pack 6a", textSize, true);
4951 build = osvi.dwBuildNumber & 0xFFFF;
4952 }
4953 else // Windows NT 4.0 prior to SP6a
4954 {
4955 major = (uint16)osvi.dwMajorVersion;
4956 minor = (uint16)osvi.dwMinorVersion;
4957 build = (uint16)osvi.dwBuildNumber & 0xFFFF;
4958 if (strlen((char*)osvi.szCSDVersion) < textSize)
4959 utils::strcpyavail(text, (char*)osvi.szCSDVersion, textSize, true);
4960 }
4961 RegCloseKey( hKey );
4962 }
4963 else // Windows NT 3.51 and earlier or Windows 2000 and later
4964 {
4965 major = (uint16)osvi.dwMajorVersion;
4966 minor = (uint16)osvi.dwMinorVersion;
4967 build = (uint16)osvi.dwBuildNumber & 0xFFFF;
4968
4969 if (strlen((char*)osvi.szCSDVersion) < textSize)
4970 utils::strcpyavail(text, (char*)osvi.szCSDVersion, textSize, true);
4971 }
4972 break;
4973 }
4974
4975 #endif
4976 #else
4977 // ######################################
4978 #endif
4979 return true;
4980}
4981
4982//bool RunOSTextCommand(const char* cmd, char** result, uint32 size) {
4983//
4984// #ifdef WINDOWS
4985// // Use RunOSCommand instead
4986// return false;
4987// #else
4988// fflush(stdin);
4989// fflush(stdout);
4990// FILE* runfile = popen(cmd, "r");
4991// if (runfile == NULL)
4992// return false;
4993//
4994// int res;
4995// int size = 4096;
4996// char buffer[size+1];
4997// std::string output;
4998//
4999// res = fread(buffer, 1, size, runfile);
5000// if (res <= 0) {
5001// pclose(runfile);
5002// return false;
5003// }
5004// do {
5005// buffer[res] = 0;
5006// output += buffer;
5007// } while (res = fread(buffer, 1, size, runfile));
5008//
5009// pclose(runfile);
5010// delete [] buffer;
5011// *result = new char[output.length()+1];
5012// memcpy(*result, output.c_str(), output.length());
5013// result[output.length()] = 0;
5014// return true;
5015// #endif
5016//}
5017
5018//bool GetSystemName(uint32 id, const char* title, char* name, uint32 size) {
5019// if ( (name == NULL) || (size < 64) )
5020// return false;
5021// memset(name, 0, 64);
5022// uint32 pos = 0;
5023// #ifdef WINDOWS
5024// strcpy_s(name, size, "Global\\");
5025// strcpy_s(name+(pos = (uint32)strlen(name)), size-pos, title);
5026// // _itoa_s(id, name+(pos = (uint32)strlen(name)), size-pos, 16);
5027// #else
5028// strncpy(name, "/", size);
5029// pos = (uint32)strlen(name);
5030// strncpy(name+pos, title, size-pos);
5031// #endif
5032// Int2Ascii((int32)id, name+(pos = (uint32)strlen(name)), size-pos, 16);
5033// return true;
5034//}
5035
5036char* Int2Ascii(int64 value, char* result, uint16 size, uint8 base) {
5037 if (base < 2 || base > 36) {
5038 result[0] = 0;
5039 return result;
5040 }
5041
5042 char* ptr = result, *ptr1 = result, tmp_char;
5043 int64 tmp_value;
5044
5045 do {
5046 tmp_value = value;
5047 value /= base;
5048 *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
5049 } while ( value );
5050
5051 // Apply negative sign
5052 if (tmp_value < 0)
5053 *ptr++ = '-';
5054 *ptr-- = '\0';
5055 while(ptr1 < ptr) {
5056 tmp_char = *ptr;
5057 *ptr--= *ptr1;
5058 *ptr1++ = tmp_char;
5059 }
5060 return result;
5061}
5062
5063char* Uint2Ascii(uint64 value, char* result, uint16 size, uint8 base) {
5064 if (base < 2 || base > 36) {
5065 result[0] = 0;
5066 return result;
5067 }
5068
5069 char* ptr = result, *ptr1 = result, tmp_char;
5070 int64 tmp_value;
5071
5072 do {
5073 tmp_value = value;
5074 value /= base;
5075 *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
5076 } while ( value );
5077
5078 *ptr-- = '\0';
5079 while(ptr1 < ptr) {
5080 tmp_char = *ptr;
5081 *ptr--= *ptr1;
5082 *ptr1++ = tmp_char;
5083 }
5084 return result;
5085}
5086
5087unsigned char* Ascii2UTF16LE(const char* ascii, uint32 len, uint32& size) {
5088 size = (len * 2) + 4;
5089 unsigned char* result = new unsigned char[size];
5090 result[0] = 0xff;
5091 result[1] = 0xfe;
5092 uint32 i = 2;
5093 const char* src = ascii;
5094 for (uint32 n = 0; n < len; n++) {
5095 result[i++] = *src;
5096 result[i++] = 0;
5097 src++;
5098 }
5099 result[i++] = 0;
5100 result[i++] = 0;
5101 size = (len * 2) + 2;
5102 return result;
5103}
5104
5105
5106bool GetSocketError(int error, char* errorString, uint16 errorStringMaxSize, bool* isRecoverable) {
5107
5108 if (errorStringMaxSize < 128)
5109 return false;
5110
5111 #ifdef WINDOWS
5112
5113 if (error == WSANOTINITIALISED) {
5114 utils::strcpyavail(errorString, "Cannot initialize WinSock!", errorStringMaxSize, true);
5115 *isRecoverable = false;
5116 }
5117 else if (error == WSAENETDOWN) {
5118 utils::strcpyavail(errorString, "The network subsystem or the associated service provider has failed", errorStringMaxSize, true);
5119 *isRecoverable = false;
5120 }
5121 else if (error == WSAEAFNOSUPPORT) {
5122 utils::strcpyavail(errorString, "The specified address family is not supported", errorStringMaxSize, true);
5123 *isRecoverable = false;
5124 }
5125 else if (error == WSAEINPROGRESS) {
5126 utils::strcpyavail(errorString, "A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function", errorStringMaxSize, true);
5127 *isRecoverable = true;
5128 }
5129 else if (error == WSAEMFILE) {
5130 utils::strcpyavail(errorString, "No more socket descriptors are available", errorStringMaxSize, true);
5131 *isRecoverable = false;
5132 }
5133 else if (error == WSAENOBUFS) {
5134 utils::strcpyavail(errorString, "No buffer space is available. The socket cannot be created", errorStringMaxSize, true);
5135 *isRecoverable = false;
5136 }
5137 else if (error == WSAEPROTONOSUPPORT) {
5138 utils::strcpyavail(errorString, "The specified protocol is not supported", errorStringMaxSize, true);
5139 *isRecoverable = false;
5140 }
5141 else if (error == WSAEPROTOTYPE) {
5142 utils::strcpyavail(errorString, "The specified protocol is the wrong type for this socket", errorStringMaxSize, true);
5143 *isRecoverable = false;
5144 }
5145 else if (error == WSAESOCKTNOSUPPORT) {
5146 utils::strcpyavail(errorString, "The specified socket type is not supported in this address family", errorStringMaxSize, true);
5147 *isRecoverable = false;
5148 }
5149 else if (error == WSAEADDRINUSE) {
5150 utils::strcpyavail(errorString, "The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs during execution of the bind function, but could be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function", errorStringMaxSize, true);
5151 *isRecoverable = false;
5152 }
5153 else if (error == WSAEINVAL) {
5154 utils::strcpyavail(errorString, "The socket has not been bound with bind", errorStringMaxSize, true);
5155 *isRecoverable = false;
5156 }
5157 else if (error == WSAEISCONN) {
5158 utils::strcpyavail(errorString, "The socket is already connected", errorStringMaxSize, true);
5159 *isRecoverable = false;
5160 }
5161 else if (error == WSAENOTSOCK) {
5162 utils::strcpyavail(errorString, "The descriptor is not a socket", errorStringMaxSize, true);
5163 *isRecoverable = false;
5164 }
5165 else if (error == WSAEOPNOTSUPP) {
5166 utils::strcpyavail(errorString, "The referenced socket is not of a type that supports the listen operation", errorStringMaxSize, true);
5167 *isRecoverable = false;
5168 }
5169 else if (error == WSAEADDRNOTAVAIL) {
5170 utils::strcpyavail(errorString, "The specified address is not a valid address for this machine", errorStringMaxSize, true);
5171 *isRecoverable = false;
5172 }
5173 else if (error == WSAEFAULT) {
5174 utils::strcpyavail(errorString, "The name or namelen parameter is not a valid part of the user address space", errorStringMaxSize, true);
5175 *isRecoverable = false;
5176 }
5177 else if (error == WSAEMFILE) {
5178 utils::strcpyavail(errorString, "The queue is nonempty upon entry to accept and there are no descriptors available", errorStringMaxSize, true);
5179 *isRecoverable = false;
5180 }
5181 else if (error == WSAEWOULDBLOCK) {
5182 utils::strcpyavail(errorString, "The socket is marked as nonblocking and no connections are present to be accepted", errorStringMaxSize, true);
5183 *isRecoverable = false;
5184 }
5185 else if (error == WSAETIMEDOUT) {
5186 utils::strcpyavail(errorString, "Attempt to connect timed out without establishing a connection", errorStringMaxSize, true);
5187 *isRecoverable = false;
5188 }
5189 else if (error == WSAENETUNREACH) {
5190 utils::strcpyavail(errorString, "The network cannot be reached from this host at this time", errorStringMaxSize, true);
5191 *isRecoverable = false;
5192 }
5193 else if (error == WSAEISCONN) {
5194 utils::strcpyavail(errorString, "The socket is already connected (connection-oriented sockets only)", errorStringMaxSize, true);
5195 *isRecoverable = false;
5196 }
5197 else if (error == WSAECONNREFUSED) {
5198 utils::strcpyavail(errorString, "The attempt to connect was forcefully rejected", errorStringMaxSize, true);
5199 *isRecoverable = false;
5200 }
5201 else if (error == WSAEAFNOSUPPORT) {
5202 utils::strcpyavail(errorString, "Addresses in the specified family cannot be used with this socket", errorStringMaxSize, true);
5203 *isRecoverable = false;
5204 }
5205 else if (error == WSAEADDRNOTAVAIL) {
5206 utils::strcpyavail(errorString, "The remote address is not a valid address (such as ADDR_ANY)", errorStringMaxSize, true);
5207 *isRecoverable = false;
5208 }
5209 else if (error == WSAEALREADY) {
5210 utils::strcpyavail(errorString, "A nonblocking connect call is in progress on the specified socket", errorStringMaxSize, true);
5211 *isRecoverable = false;
5212 }
5213 else if (error == WSAECONNRESET) {
5214 utils::strcpyavail(errorString, "Connection was reset", errorStringMaxSize, true);
5215 *isRecoverable = false;
5216 }
5217 else if (error == WSAECONNABORTED) {
5218 utils::strcpyavail(errorString, "Software caused connection abort", errorStringMaxSize, true);
5219 *isRecoverable = false;
5220 }
5221 else {
5222 snprintf(errorString, errorStringMaxSize, "TCP error with no description: %d", error);
5223 *isRecoverable = false;
5224 }
5225
5226 return true;
5227 #else
5228 if (error == 100) {
5229 utils::strcpyavail(errorString, "Cannot initialise socket", errorStringMaxSize, true);
5230 *isRecoverable = false;
5231 }
5232 else {
5233 utils::strcpyavail(errorString, strerror(error), errorStringMaxSize, true);
5234 *isRecoverable = false;
5235 }
5236
5237 return true;
5238 #endif
5239}
5240
5241
5243 #ifdef WINDOWS
5244 int err = WSAGetLastError();
5245 WSASetLastError(0);
5246 return err;
5247 #else
5248 return errno;
5249 #endif
5250}
5251
5253 #ifdef WINDOWS
5254 LPVOID lpMsgBuf; //Message Buffer
5255 DWORD error = GetLastError();
5256 uint32 len = FormatMessage(
5257 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
5258 NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
5259 (LPTSTR) &lpMsgBuf, 0, NULL);
5260 std::string str = (char*)lpMsgBuf;
5261 LocalFree(lpMsgBuf);
5262 return str;
5263 #else
5264 return utils::StringFormat("Error number: %u", errno);
5265 #endif
5266}
5267
5268bool WaitForSocketWriteability(SOCKET s, int32 timeout) {
5269
5270 int maxfd = 0;
5271
5272 // If socket is not valid return true so the next read will report the error
5273 if (s == INVALID_SOCKET) return true;
5274
5275 struct timeval tv;
5276 tv.tv_sec = 0;
5277 tv.tv_usec = 0;
5278
5279 fd_set wds;
5280 // create a list of sockets to check for activity
5281 FD_ZERO(&wds);
5282 // specify mySocket
5283 FD_SET(s, &wds);
5284
5285 #ifdef WINDOWS
5286 #else
5287 maxfd = s + 1;
5288 #endif
5289
5290 if (timeout > 0) {
5291 ldiv_t d = ldiv(timeout*1000, 1000000);
5292 tv.tv_sec = d.quot;
5293 tv.tv_usec = d.rem;
5294 }
5295
5296 // Check for readability
5297 return( select(maxfd, NULL, &wds, NULL, &tv) > 0);
5298}
5299
5300bool WaitForSocketReadability(SOCKET s, int32 timeout) {
5301
5302 int maxfd = 0;
5303
5304 // If socket is not valid return true so the next read will report the error
5305 if (s == INVALID_SOCKET) return true;
5306
5307 struct timeval tv;
5308 tv.tv_sec = 0;
5309 tv.tv_usec = 0;
5310
5311 fd_set rdds;
5312 // create a list of sockets to check for activity
5313 FD_ZERO(&rdds);
5314 // specify mySocket
5315 FD_SET(s, &rdds);
5316
5317 #ifdef WINDOWS
5318 #else
5319 maxfd = s + 1;
5320 #endif
5321
5322 if (timeout > 0) {
5323 ldiv_t d = ldiv(timeout*1000, 1000000);
5324 tv.tv_sec = d.quot;
5325 tv.tv_usec = d.rem;
5326 }
5327
5328 // Check for readability
5329// uint64 t2 = GetTimeNow();
5330 int ret = select(maxfd, &rdds, NULL, NULL, &tv);
5331 //if (GetTimeAge(t2) > 1000) {
5332// LogPrint(0,LOG_NETWORK,0,"************** WaitForSocketReadability(%d) took %s ******************", s, PrintTimeDifString(GetTimeAge(t2)).c_str());
5333 //}
5334 return(ret > 0);
5335}
5336
5338 #if defined(WINDOWS)
5339 unsigned long parm = 1; // 1 = Non-blocking, 0 = Blocking
5340 ioctlsocket(s, FIONBIO, &parm);
5341 #else
5342 long parm = fcntl(s, F_GETFL);
5343 parm |= O_NONBLOCK;
5344 fcntl(s, F_SETFL, parm);
5345 #endif
5346 return true;
5347}
5348
5350 #if defined(WINDOWS)
5351 unsigned long parm = 0; // 1 = Non-blocking, 0 = Blocking
5352 ioctlsocket(s, FIONBIO, &parm);
5353 #else
5354 long parm = fcntl(s, F_GETFL);
5355 parm &= ~O_NONBLOCK;
5356 fcntl(s, F_SETFL, parm);
5357 #endif
5358 return true;
5359}
5360
5361bool LookupIPAddress(const char* name, uint32& address) {
5363 if ( (name == NULL) || (strlen(name) == 0) )
5364 return false;
5365
5366 struct hostent* hent;
5367
5368 #ifdef WINDOWS
5369 //hent = gethostbyname(name);
5370 //if (hent == NULL)
5371 // return false;
5372 //else {
5373 // memcpy(&address, hent->h_addr_list[0], sizeof(address));
5374 // printf("IP1 of %s = %u.%u.%u.%u (%u)\n", name, GETIPADDRESSQUAD(address), address);
5375 // //return true;
5376 //}
5377
5378 //uint32 address2 = 0;
5379 struct addrinfo hints, *res;
5380 int error = -1;
5381 const char *cause = NULL;
5382
5383 memset(&hints, 0, sizeof(hints));
5384 //do not set to AI_NUMERICHOST, causes issues with connections...
5385 //hints.ai_flags = AI_NUMERICHOST; // AI_PASSIVE
5386 hints.ai_family = AF_INET;
5387 hints.ai_socktype = SOCK_STREAM;
5388 hints.ai_protocol = IPPROTO_TCP;
5389 __try {
5390 error = getaddrinfo(name, NULL, &hints, &res);
5391 }
5392 __except (EXCEPTION_CONTINUE_EXECUTION) {
5393 error = -1;
5394 }
5395
5396 if (!error) {
5397 memcpy(&address, res->ai_addr->sa_data + 2, sizeof(address));
5398 //printf("IP2 of %s = %u.%u.%u.%u (%u)\n", name, GETIPADDRESSQUAD(address), address);
5399 freeaddrinfo(res);
5400 return true;
5401 }
5402 else
5403 return false;
5404
5405
5406 #else
5407 struct addrinfo hints, *res;
5408 int error;
5409 const char *cause = NULL;
5410
5411 memset(&hints, 0, sizeof(hints));
5412 // hints.ai_flags = AI_NUMERICHOST; // AI_PASSIVE
5413 hints.ai_family = PF_UNSPEC;
5414 hints.ai_socktype = SOCK_STREAM;
5415 error = getaddrinfo(name, NULL, &hints, &res);
5416 if (!error) {
5417 memcpy(&address, res->ai_addr->sa_data+2, 4);
5418 freeaddrinfo(res);
5419 return true;
5420 }
5421 else
5422 return false;
5423 #endif // WINDOWS
5424}
5425
5426#ifdef WINDOWS
5427 bool IsNetworkInitialised = false;
5428 bool CheckNetworkInit() {
5429 if (IsNetworkInitialised) return true;
5430 WSADATA info;
5431 if (WSAStartup(MAKEWORD(1,1), &info) != 0) {
5432 LogPrint(0, LOG_NETWORK, 0, "Could not start Windows Networking...");
5433 return false;
5434 }
5435 IsNetworkInitialised = true;
5436 return true;
5437 }
5438#endif
5439
5440bool LookupHostname(uint32 address, char* name, uint32 maxSize) {
5442 struct hostent *pHost;
5443
5444 unsigned char* addrChars = (unsigned char*)&address;
5445 //char addrString[20];
5446 char* addrString = new char[20];
5447 snprintf(addrString, 20, "%u.%u.%u.%u", addrChars[0], addrChars[1], addrChars[2], addrChars[3]);
5448
5449 #ifdef WINDOWS
5450 pHost = gethostbyname(addrString);
5451 delete [] addrString;
5452 if (pHost == NULL) {
5453 return false;
5454 }
5455 if (strlen(pHost->h_name) > maxSize-1) {
5456 return false;
5457 }
5458 utils::strcpyavail(name, pHost->h_name, maxSize, true);
5459 return true;
5460 #else // WINDOWS
5461
5462 #ifdef Darwin
5463 pHost = gethostbyname(addrString);
5464 delete [] addrString;
5465 if (pHost == NULL)
5466 return false;
5467 else {
5468 if (strlen(pHost->h_name) > maxSize-1)
5469 return false;
5470 utils::strcpyavail(name, pHost->h_name, maxSize, true);
5471 return true;
5472 }
5473 #else // Darwin
5474
5475 pHost = new struct hostent;
5476 char bf[2000];
5477 int er;
5478 gethostbyname_r(addrString, pHost, bf, 2000, &pHost, &er);
5479 delete [] addrString;
5480 if (er != 0) {
5481 delete pHost;
5482 return false;
5483 }
5484 else {
5485 if (strlen(pHost->h_name) > maxSize-1)
5486 return false;
5487 utils::strcpyavail(name, pHost->h_name, maxSize, true);
5488 delete pHost;
5489 return true;
5490 }
5491
5492 #endif // Darwin
5493 #endif // WINDOWS
5494}
5495
5497 char* name = new char[256];
5498 if (!GetLocalHostname(name, 255)) {
5499 delete [] name;
5500 return "";
5501 }
5502
5503 std::string sname = name;
5504 delete [] name;
5505 return sname;
5506}
5507
5508bool GetLocalHostname(char* name, uint32 maxSize) {
5510
5511 if (gethostname(name, maxSize) == 0)
5512 return true;
5513 else
5514 return false;
5515
5516 //JString ipaddress = GetLocalIPAddress();
5517 //JString hostname = ipaddress;
5518 //struct hostent* hent;
5519 //if ( (ipaddress.equals("127.0.0.1")) || (ipaddress.equals("localhost")) ) {
5520 // localhostName = "127.0.0.1";
5521 // return localhostName;
5522 //}
5523
5524 //#ifdef WINDOWS
5525
5526 // hent = gethostbyname((char*) ipaddress);
5527 // if (hent != NULL)
5528 // localhostName = JString(hent->h_name);
5529 // else {
5530 // int err = WSAGetLastError();
5531 // if (DEBUGLEVEL(KITCHENSINK)) {
5532 // printf("getLocalHostname(): gethostbyaddr error %d...\n", err);
5533 // }
5534 // localhostName = ipaddress;
5535 // return ipaddress;
5536 // }
5537
5538 //#else // WINDOWS
5539
5540 // struct addrinfo hints, *res;
5541 // int error;
5542 // const char *cause = NULL;
5543
5544 // memset(&hints, 0, sizeof(hints));
5545 // hints.ai_flags = AI_NUMERICHOST;
5546 // hints.ai_family = PF_UNSPEC;
5547 // hints.ai_socktype = SOCK_STREAM;
5548 // error = getaddrinfo(ipaddress, NULL, &hints, &res);
5549 // if (error != 0) {
5550 // localhostName = ipaddress;
5551 // return ipaddress;
5552 // }
5553 // else {
5554 // if (res->ai_canonname != NULL) {
5555 // localhostName = res->ai_canonname;
5556 // }
5557 // else
5558 // localhostName = ipaddress;
5559 // }
5560 // freeaddrinfo(res);
5561
5562 //#endif // WINDOWS
5563
5564 //return localhostName;
5565
5566}
5567
5568bool GetLocalMACAddress(uint64& address) {
5569 address = 0;
5570 uint32 c;
5571 NetworkInterfaces* interfaces = GetLocalInterfaces(c);
5572 for (uint32 i=0; i<c; i++) {
5573 if ( (interfaces[i].address != 0) && (interfaces[i].address != LOCALHOSTIP) )
5574 address = interfaces[i].mac;
5575 }
5576 delete [] interfaces;
5577 return (address != 0);
5578}
5579
5580uint64* GetLocalMACAddresses(uint32& count) {
5581 uint32 c;
5582 NetworkInterfaces* interfaces = GetLocalInterfaces(c);
5583 if (!c)
5584 return NULL;
5585 uint64* addresses = new uint64[c];
5586 uint32 p=0;
5587 for (uint32 i=0; i<c; i++) {
5588 if ( (interfaces[i].address != 0) && (interfaces[i].address != LOCALHOSTIP) )
5589 addresses[p++] = interfaces[i].mac;
5590 }
5591 count = p;
5592 return addresses;
5593}
5594
5595bool IsLocalIPAddress(const char* addr) {
5596 uint32 address;
5597 if (!LookupIPAddress(addr, address))
5598 return false;
5599 return IsLocalIPAddress(address);
5600}
5601
5602bool IsLocalIPAddress(uint32& address) {
5604 uint32 count;
5605 uint32* addresses = GetLocalIPAddresses(count);
5606 if ((addresses == NULL) || (count == 0)) {
5607 delete [] addresses;
5608 return false;
5609 }
5610
5611 unsigned int n;
5612 for (n=0; n<count; n++) {
5613 if (addresses[n] == address) {
5614 delete [] addresses;
5615 return true;
5616 }
5617 }
5618 delete [] addresses;
5619 return false;
5620}
5621
5622bool GetLocalIPAddress(uint32& address) {
5624 uint32 count;
5625 uint32* addresses = GetLocalIPAddresses(count);
5626 if ((addresses == NULL) || (count == 0)) {
5627 delete [] addresses;
5628 return false;
5629 }
5630 // First find first non-localhost address
5631 unsigned int n;
5632 bool localhostPresent = false;
5633 for (n=0; n<count; n++) {
5634 if (addresses[n] != LOCALHOSTIP) {
5635 if (addresses[n] != 0) {
5636 address = addresses[n];
5637 delete [] addresses;
5638 return true;
5639 }
5640 }
5641 else
5642 localhostPresent = true;
5643 }
5644 delete [] addresses;
5645 // OK, then accept localhost, if present
5646 if (localhostPresent) {
5647 address = LOCALHOSTIP;
5648 return true;
5649 }
5650 else
5651 return false;
5652}
5653
5654uint32* GetLocalIPAddresses(uint32& count) {
5656
5657 uint32 maxSize = 128;
5658 uint32* addresses = new uint32[maxSize];
5659
5660 addresses[0] = LOCALHOSTIP;
5661 count = 1;
5662
5663 char* szHostName = new char[255];
5664
5665 bool canAskHost = true;
5666 if( gethostname(szHostName, 255) != 0 ) {
5667 #ifdef WINDOWS
5668 int err = GetLastOSErrorNumber();
5669 if (err == WSANOTINITIALISED) {
5670 WSADATA info;
5671 if (WSAStartup(MAKEWORD(1,1), &info) != 0) {
5672 delete [] szHostName;
5673 return addresses;
5674 }
5675 else {
5676 if( gethostname(szHostName, 255) != 0 )
5677 canAskHost = false;
5678 }
5679 }
5680 else
5681 canAskHost = false;
5682 #else // WINDOWS
5683 canAskHost = false;
5684 #endif // WINDOWS
5685 }
5686
5687 struct hostent * pHost;
5688 uint32 addr, j, i;
5689 bool exists;
5690
5691 if (canAskHost) {
5692 // Get host addresses
5693
5694 #ifdef WINDOWS
5695 pHost = gethostbyname(szHostName);
5696 #else // WINDOWS
5697
5698 #ifdef Darwin
5699 pHost = gethostbyname(szHostName);
5700 //if (pHost == NULL)
5701 // return addresses;
5702 #else // Darwin
5703
5704 pHost = new struct hostent;
5705 char* bf = new char[2000];
5706 int er;
5707 int res = gethostbyname_r(szHostName, pHost, bf, 2000, &pHost, &er);
5708 // LogPrint(0, LOG_NETWORK, 0, "gethostbyname_r '%s' [%d] [%d]...\n", szHostName, res, er);
5709 if ((er != 0) && (res == 0)) {
5710 delete pHost;
5711 pHost = NULL;
5712 // return addresses;
5713 }
5714 delete [] bf;
5715 #endif // Darwin
5716 #endif // WINDOWS
5717
5718 for( i = 0; pHost!= NULL && pHost->h_addr_list[i]!= NULL; i++ )
5719 {
5720 exists = false;
5721 memcpy(&addr, ((unsigned char*)pHost->h_addr_list[i]), sizeof(uint32));
5722 if ( (addr != 0) && (addr != LOCALHOSTIP) ) {
5723 for (j=0; j<count; j++) {
5724 if (addresses[j] == addr) {
5725 exists = true;
5726 break;
5727 }
5728 }
5729 if (!exists)
5730 addresses[count++] = addr;
5731 }
5732 }
5733
5734 #ifdef WINDOWS
5735 #else // WINDOWS
5736 #ifdef Darwin
5737 endhostent();
5738 #else
5739 delete pHost;
5740 #endif // Darwin
5741 #endif // WINDOWS
5742 }
5743
5744 uint32 c;
5745 NetworkInterfaces* interfaces = GetLocalInterfaces(c);
5746 for (i=0; i<c; i++) {
5747 exists = false;
5748 if ( (interfaces[i].address != 0) && (interfaces[i].address != LOCALHOSTIP) ) {
5749 for (j=0; j<count; j++) {
5750 if (addresses[j] == interfaces[i].address) {
5751 exists = true;
5752 break;
5753 }
5754 }
5755 if (!exists)
5756 addresses[count++] = interfaces[i].address;
5757 }
5758 }
5759 delete [] interfaces;
5760 delete [] szHostName;
5761 return addresses;
5762}
5763
5766
5767 uint32 maxSize = 128;
5768 uint32 addr;
5769 NetworkInterfaces* interfaces = new NetworkInterfaces[maxSize];
5770 count = 0;
5771
5772 #ifdef WINDOWS
5773
5774 DWORD dwSize = 0;
5775 DWORD dwRetVal = 0;
5776
5777 unsigned int i = 0;
5778
5779 // Set the flags to pass to GetAdaptersAddresses
5780 ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
5781
5782 // default to unspecified address family (both)
5783 ULONG family = AF_INET;
5784
5785 LPVOID lpMsgBuf = NULL;
5786
5787 PIP_ADAPTER_ADDRESSES pAddresses = NULL;
5788 ULONG outBufLen = 0;
5789 ULONG Iterations = 0;
5790
5791 PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
5792 PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
5793 PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
5794 PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
5795 IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
5796 IP_ADAPTER_PREFIX *pPrefix = NULL;
5797
5798 // Allocate a 15 KB buffer to start with.
5799 outBufLen = 15000;
5800
5801 do {
5802
5803 pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
5804 if (pAddresses == NULL)
5805 return interfaces;
5806
5807 dwRetVal =
5808 GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
5809
5810 if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
5811 FREE(pAddresses);
5812 pAddresses = NULL;
5813 }
5814 else
5815 break;
5816
5817 Iterations++;
5818
5819 } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 10));
5820
5821
5822 if (dwRetVal == NO_ERROR) {
5823 // If successful, output some information from the data we received
5824 pCurrAddresses = pAddresses;
5825 while (pCurrAddresses) {
5826 if ( (pCurrAddresses->OperStatus == IfOperStatusUp) && (pCurrAddresses->IfIndex != 0)) {
5827
5828 // First check the IP address
5829 pUnicast = pCurrAddresses->FirstUnicastAddress;
5830 if (pUnicast != NULL) {
5831 for (i = 0; pUnicast != NULL; i++) {
5832 addr = *(uint32*)(((unsigned char*) ((SOCKADDR*)(pUnicast->Address.lpSockaddr))->sa_data) + 2);
5833 if ( (addr != 0) && (addr != LOCALHOSTIP) ) {
5834 interfaces[count].address = addr;
5835 interfaces[count].mac = 0;
5836 if (pCurrAddresses->PhysicalAddressLength == 6)
5837 memcpy(&(interfaces[count].mac), &(pCurrAddresses->PhysicalAddress), 6);
5838 WideCharToMultiByte( CP_ACP, 0, pCurrAddresses->Description, -1, interfaces[count].name, MAXKEYNAMELEN, NULL, NULL );
5839 WideCharToMultiByte( CP_ACP, 0, pCurrAddresses->FriendlyName, -1, interfaces[count].friendlyName, MAXKEYNAMELEN, NULL, NULL );
5840 count++;
5841 }
5842 pUnicast = pUnicast->Next;
5843 }
5844 }
5845 }
5846
5847 pCurrAddresses = pCurrAddresses->Next;
5848 }
5849 }
5850 if (pAddresses)
5851 FREE(pAddresses);
5852
5853 return interfaces;
5854
5855 #else
5856 int sock = 0;
5857 struct ifreq ifreq;
5858 struct sockaddr_in *saptr = NULL;
5859 struct if_nameindex *iflist = NULL, *listsave = NULL;
5860
5861 //need a socket for ioctl()
5862 if( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
5863 return interfaces;
5864 }
5865
5866 //returns pointer to dynamically allocated list of structs
5867 iflist = listsave = if_nameindex();
5868
5869 if (iflist == NULL) {
5870 close(sock);
5871 return interfaces;
5872 }
5873
5874 //walk thru the array returned and query for each
5875 //interface's address
5876 //for(iflist; iflist->if_index != 0; iflist++) {
5877 for(; iflist->if_index != 0; iflist++) {
5878 //copy in the interface name to look up address of
5879 strncpy(ifreq.ifr_name, iflist->if_name, IF_NAMESIZE);
5880 //get the address for this interface
5881 if(ioctl(sock, SIOCGIFADDR, &ifreq) != 0) {
5882 // ignore;
5883 continue;
5884 }
5885 //print out the address
5886 saptr = (struct sockaddr_in *)&ifreq.ifr_addr;
5887 //unsigned char* ip = (unsigned char*)&(saptr->sin_addr.s_addr);
5888 //printf("**** %u.%u.%u.%u ***\n", ip[0], ip[1], ip[2], ip[3]);
5889 memcpy(&(interfaces[count].address), &(saptr->sin_addr.s_addr), sizeof(uint32));
5890 utils::strcpyavail(interfaces[count].name, ifreq.ifr_name, MAXKEYNAMELEN, true);
5891 #ifdef __APPLE__
5892 interfaces[count].mac = 0;
5893 #else
5894 // get the MAC address (Linux only)
5895 interfaces[count].mac = 0;
5896 ioctl(sock, SIOCGIFHWADDR, &ifreq);
5897 memcpy(&(interfaces[count].mac), &(ifreq.ifr_hwaddr.sa_data), 6);
5898 #endif
5899 count++;
5900 }
5901 //free the dynamic memory kernel allocated for us
5902 if_freenameindex(listsave);
5903 close(sock);
5904
5905 #endif
5906
5907 return interfaces;
5908}
5909
5910bool GetNextAvailableLocalPort(uint16 lastPort, uint16 &nextPort) {
5912
5913 SOCKET socket;
5914 struct sockaddr_in addr;
5915 addr.sin_family= AF_INET;
5916 addr.sin_addr.s_addr=INADDR_ANY;
5917 bool result = false;
5918
5919 nextPort = lastPort + 1;
5920 while (nextPort < lastPort + 1000) {
5921 if((socket=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
5922 return false;
5923
5924 #ifdef WINDOWS
5925 // Set the exclusive address option, preventing other software binding to
5926 // non-INADDR_ANY (i.e. interface addresses such as localhost directly)
5927 int one = 1;
5928 setsockopt(socket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &one, sizeof(one));
5929 #else
5930 /*
5931 This socket option tells the kernel that even if this port is busy (in
5932 the TIME_WAIT state), go ahead and reuse it anyway. If it is busy,
5933 but with another state, you will still get an address already in use
5934 error. It is useful if your server has been shut down, and then
5935 restarted right away while sockets are still active on its port. You
5936 should be aware that if any unexpected data comes in, it may confuse
5937 your server, but while this is possible, it is not likely.
5938 */
5939 int one = 1;
5940 setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one));
5941 #endif
5942
5943 addr.sin_port=htons(nextPort);
5944
5945 result = (bind(socket,(SOCKADDR*)&addr,sizeof(struct sockaddr_in))!=SOCKET_ERROR);
5946 shutdown(socket, SD_BOTH);
5947 closesocket(socket);
5948
5949 if (result)
5950 return true;
5951
5952 nextPort++;
5953 }
5954 return false;
5955
5956}
5957
5959 printf("Testing Utils...\n\n");
5960
5961 char hostname[1024];
5962 if (!GetLocalHostname(hostname, 1023)) {
5963 printf("Error GetLocalHostname\n");
5964 return false;
5965 }
5966 printf("Local Hostname: '%s'\n\n", hostname);
5967
5968 uint32 addr;
5969 unsigned char* addrChars = (unsigned char*) &addr;
5970 if (!GetLocalIPAddress(addr)) {
5971 printf("Error GetLocalIPAddress\n");
5972 return false;
5973 }
5974 printf("Local IP Address: %u.%u.%u.%u\n\n", addrChars[0], addrChars[1], addrChars[2], addrChars[3]);
5975
5976 uint32 count;
5977 uint32* addresses = GetLocalIPAddresses(count);
5978 if (addresses == NULL) {
5979 printf("Error GetLocalIPAddresses\n");
5980 return false;
5981 }
5982 uint32 n;
5983 for (n=0; n<count; n++) {
5984 addrChars = (unsigned char*) &addresses[n];
5985 printf("Local IP Address[%u]: %u.%u.%u.%u (%u,%u)\n\n", n, addrChars[0], addrChars[1], addrChars[2], addrChars[3], addresses[n], LOCALHOSTIP);
5986 }
5987 delete [] addresses;
5988
5989 NetworkInterfaces* interfaces = GetLocalInterfaces(count);
5990 for (n=0; n<count; n++) {
5991 addrChars = (unsigned char*) &(interfaces[n]);
5992 printf("Local Interface[%u] %s: %u.%u.%u.%u (%llX)\n\n", n, interfaces[n].name,
5993 addrChars[0], addrChars[1], addrChars[2], addrChars[3], interfaces[n].mac);
5994 }
5995 delete [] interfaces;
5996
5997 return true;
5998}
5999
6000void PrintBinary(void* p, uint32 size, bool asInt, const char* title) {
6001 if (title != NULL)
6002 printf("--- %s %u ---\n", title, size);
6003 unsigned char c;
6004 for (uint32 n=0; n<size; n++) {
6005 c = *(((unsigned char*)p)+n);
6006 if (asInt)
6007 printf("[%u] ", (unsigned int)c);
6008 else
6009 printf("[%c] ", c);
6010 if ( (n > 0) && ((n+1)%10 == 0) )
6011 printf("\n");
6012 }
6013 printf("\n");
6014}
6015
6016// const char* stristr(const char *str, const char *substr, uint32 len) {
6017// if (!str || !substr) return NULL;
6018// const char *a, *b;
6019// uint32 n=0, m, sslen = (uint32)strlen(substr);
6020// for(;*str;*str++,n++) {
6021// a = str;
6022// b = substr;
6023// m = n+sslen;
6024// while((*a++ | 32) == (*b++ | 32)) {
6025// if(!*b)
6026// return str;
6027// if (len && (++m > len))
6028// return NULL;
6029// }
6030// }
6031// return NULL;
6032// }
6033
6034
6035const char* stristr(const char *str, const char *substr, uint32 len) {
6036 if (!str || !substr) return NULL;
6037 uint32 sslen = (uint32)strlen(substr);
6038 if (sslen == 0) return (const char*)str;
6039 const char *a, *b;
6040 uint32 n=0, m;
6041 for (; *str; str++, n++) {
6042 a = str;
6043 b = substr;
6044 m = n+sslen;
6045 /* Case-insensitive compare via |32 (ASCII A–Z only). */
6046 while ((*a++ | 32) == (*b++ | 32)) {
6047 if (!*b)
6048 return str;
6049 if (len && (++m > len))
6050 return NULL;
6051 }
6052 }
6053 return NULL;
6054}
6055
6056uint32 strcpyavail(char* dst, const char* src, uint32 maxlen, bool copyAvailable) {
6057 if ( !dst || ! src || !maxlen )
6058 return 0;
6059 uint32 len = (uint32)strlen(src);
6060 if (len > maxlen-1) {
6061 if (!copyAvailable)
6062 return 0;
6063 else {
6064 memcpy(dst, src, maxlen-1);
6065 dst[maxlen] = 0;
6066 return maxlen-1;
6067 }
6068 }
6069 else
6070 memcpy(dst, src, len+1);
6071 return len;
6072}
6073
6074bool GetNextLineEnd(const char *str, uint32 size, uint32& len, uint32& crSize) {
6075 if (!str || !size)
6076 return false;
6077
6078 for (len = 0; len < size; len++) {
6079 // Checking for CR and CRLF
6080 if (str[len] == 13) {
6081 crSize = ( (len < size-1) && (str[len+1] == 10 ) ) ? 2 : 1;
6082 return true;
6083 }
6084 // Checking for LF only without CR
6085 if (str[len] == 10) {
6086 crSize = 1;
6087 return true;
6088 }
6089 }
6090 return false;
6091}
6092
6093std::string TextCapitalise(const char* text) {
6094 if (!text)
6095 return "";
6096 std::string str = text;
6097 if (!str.length())
6098 return "";
6099 std::string::iterator i = str.begin(), e = str.end();
6100 *i = ::toupper(*i);
6101 i++;
6102 if (i != e)
6103 std::transform(i, e, i, ::tolower);
6104 return str;
6105}
6106
6107std::string TextUppercase(const char* text) {
6108 std::string str = text;
6109 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
6110 return str;
6111}
6112
6113std::string TextLowercase(const char* text) {
6114 std::string str = text;
6115 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
6116 return str;
6117}
6118
6119std::string TextIndent(const char* text, const char* indent) {
6120 std::vector<std::string> lines = utils::TextListSplitLines(text, true, false);
6121 std::vector<std::string>::iterator i = lines.begin(), e = lines.end();
6122 std::string output;
6123 while (i != e) {
6124 output += utils::StringFormat("%s%s\n", indent, (*i).c_str());
6125 i++;
6126 }
6127 return output;
6128}
6129
6130std::string TextUnindent(const char* text) {
6131 uint32 len = (uint32)strlen(text);
6132 if (!len) return "";
6133 if (text[0] > 32)
6134 return text;
6135
6136 // Find initial spacing char sequence
6137 uint32 s = 0, p = 0;
6138 // Find initial line endings
6139 while ( ((text[s] == '\n') || (text[s] == '\r')) && (s < len))
6140 s++;
6141 p = s;
6142 while ((text[p] <= 32) && (p < len))
6143 p++;
6144 std::string indentString = std::string(text+s, p-s);
6145 std::string str = text;
6146 StringSingleReplace(str, indentString, "", false);
6147 return str;
6148}
6149
6150
6151std::string TextTrimQuotes(const char* text) {
6152 if (text) {
6153 uint32 begin = 0, end = (uint32)strlen(text);
6154 if (begin == end)
6155 return "";
6156 while ((begin < end) && (text[begin] <= 32) || (text[begin] == '\"') || (text[begin] == '\''))
6157 begin++;
6158 if (begin == end)
6159 return "";
6160 while ((end > begin) && (text[end-1] <= 32) || (text[end-1] == '\"') || (text[end-1] == '\''))
6161 end--;
6162 return std::string(text+begin, end-begin);
6163 }
6164 else
6165 return "";
6166}
6167
6168
6169std::string TextTrim(const char* text) {
6170 if (text) {
6171 uint32 begin = 0, end = (uint32)strlen(text);
6172 if (begin == end)
6173 return "";
6174 while ((text[begin] <= 32) && (begin < end))
6175 begin++;
6176 while ((end > begin) && (text[end-1] <= 32))
6177 end--;
6178 return std::string(text+begin, end-begin);
6179 }
6180 else
6181 return "";
6182}
6183
6184std::multimap<std::string, std::string> TextMultiMapSplit(const char* text, const char* outersplit, const char* innersplit) {
6185 std::multimap<std::string, std::string> result;
6186 typedef std::pair <std::string, std::string> Map_String_Pair;
6187
6188 if (!text || !outersplit || !innersplit)
6189 return result;
6190
6191 const char* pstr = text, *lstr = text;
6192 const char* src = text;
6193
6194 while (pstr = strstr(src, outersplit)) {
6195 if ((lstr = strstr(src, innersplit)) && (lstr < pstr)) {
6196 // result[TextTrim(std::string(src, lstr-src).c_str())] = TextTrim(std::string(lstr+1, pstr-lstr-1).c_str());
6197 result.insert(Map_String_Pair(TextTrim(std::string(src, lstr-src).c_str()), TextTrim(std::string(lstr+1, pstr-lstr-1).c_str())));
6198 }
6199 src = pstr + 1;
6200 }
6201 pstr = src + strlen(src);
6202 if ((lstr = strstr(src, innersplit)) && (lstr < pstr)) {
6203 // result[TextTrim(std::string(src, lstr-src).c_str())] = TextTrim(std::string(lstr+1, pstr-lstr-1).c_str());
6204 result.insert(Map_String_Pair(TextTrim(std::string(src, lstr-src).c_str()), TextTrim(std::string(lstr+1, pstr-lstr-1).c_str())));
6205 }
6206
6207 return result;
6208}
6209
6210
6211std::map<std::string, std::string> TextMapSplit(const char* text, const char* outersplit, const char* innersplit) {
6212 std::map<std::string, std::string> result;
6213 typedef std::pair <std::string, std::string> Map_String_Pair;
6214
6215 if (!text || !outersplit || !innersplit)
6216 return result;
6217
6218 const char* pstr = text, *lstr = text;
6219 const char* src = text;
6220
6221 while (pstr = strstr(src, outersplit)) {
6222 if ((lstr = strstr(src, innersplit)) && (lstr < pstr)) {
6223 // result[TextTrim(std::string(src, lstr-src).c_str())] = TextTrim(std::string(lstr+1, pstr-lstr-1).c_str());
6224 result.insert(Map_String_Pair(TextTrim(std::string(src, lstr - src).c_str()), TextTrim(std::string(lstr + 1, pstr - lstr - 1).c_str())));
6225 }
6226 src = pstr + 1;
6227 }
6228 pstr = src + strlen(src);
6229 if ((lstr = strstr(src, innersplit)) && (lstr < pstr)) {
6230 // result[TextTrim(std::string(src, lstr-src).c_str())] = TextTrim(std::string(lstr+1, pstr-lstr-1).c_str());
6231 result.insert(Map_String_Pair(TextTrim(std::string(src, lstr - src).c_str()), TextTrim(std::string(lstr + 1, pstr - lstr - 1).c_str())));
6232 }
6233
6234 return result;
6235}
6236
6237char** SplitCommandline(const char* cmdline, int& argc) {
6238 std::vector<std::string> args = TextCommandlineSplit(cmdline);
6239 uint32 size = (uint32)args.size();
6240 if (!size)
6241 return NULL;
6242
6243 char** argv = new char*[size+1];
6244 uint32 c = 0;
6245 std::vector<std::string>::iterator i = args.begin(), e = args.end();
6246 while (i != e) {
6247 argv[c] = new char[(*i).length()+1];
6248 strcpy(argv[c], (*i).c_str());
6249 c++;
6250 i++;
6251 }
6252 argv[c] = NULL;
6253 argc = (int)c;
6254 return argv;
6255}
6256
6257wchar_t** SplitCommandlineW(const char* cmdline, int& argc) {
6258 std::vector<std::string> args = TextCommandlineSplit(cmdline);
6259 uint32 size = (uint32)args.size();
6260 if (!size)
6261 return NULL;
6262
6263 wchar_t** argv = new wchar_t*[size+1];
6264 uint32 c = 0;
6265 std::vector<std::string>::iterator i = args.begin(), e = args.end();
6266 while (i != e) {
6267 argv[c] = new wchar_t[(*i).length()+1];
6268 mbstowcs(argv[c], (*i).c_str(), (*i).length() + 1);
6269 c++;
6270 i++;
6271 }
6272 argv[c] = NULL;
6273 argc = (int)c;
6274 return argv;
6275}
6276
6277bool DeleteCommandline(char** argv, int argc) {
6278 for (uint32 n=0; n<(uint32)argc; n++)
6279 delete [] argv[n];
6280 delete [] argv;
6281 return true;
6282}
6283
6284std::vector<std::string> TextCommandlineSplit(const char* cmdline) {
6285
6286 bool insideQuotes = false;
6287 bool lastWasWhiteSpace = false;
6288 std::vector<std::string> vect;
6289 std::string arg, val, str;
6290 unsigned char ch;
6291
6292 uint32 len = (uint32)strlen(cmdline);
6293
6294 bool keepQuotes = false;
6295
6296 for (uint32 n=0; n<len; n++) {
6297 ch = cmdline[n];
6298 if (ch <= 32) {
6299 if (!insideQuotes) {
6300 if (!lastWasWhiteSpace) {
6301 // An arg is ended, parse it...
6302 vect.push_back(str);
6303 str = "";
6304 }
6305 else {
6306 // Ignore this whitespace then...
6307 }
6308 lastWasWhiteSpace = true;
6309 }
6310 else {
6311 str += ch;
6312 }
6313 }
6314 else if (ch == '"') {
6315 insideQuotes = !insideQuotes;
6316 if (keepQuotes)
6317 str += ch;
6318 lastWasWhiteSpace = false;
6319 }
6320 else {
6321 str += ch;
6322 lastWasWhiteSpace = false;
6323 }
6324 }
6325
6326 if (str.length() > 0) {
6327 vect.push_back(str);
6328 str = "";
6329 }
6330
6331 return vect;
6332}
6333
6334std::vector<std::string> TextListSplitLines(const char* text, bool keepEmpty, bool autoTrim) {
6335 if (!text || !strlen(text))
6336 return std::vector<std::string>();
6337
6338 if (strstr(text, "\r\n"))
6339 return TextListSplit(text, "\r\n", keepEmpty, autoTrim);
6340 else if (strstr(text, "\n\r"))
6341 return TextListSplit(text, "\n\r", keepEmpty, autoTrim);
6342 else if (strstr(text, "\n"))
6343 return TextListSplit(text, "\n", keepEmpty, autoTrim);
6344 else if (strstr(text, "\r"))
6345 return TextListSplit(text, "\n", keepEmpty, autoTrim);
6346
6347 std::vector<std::string> result;
6348 result.push_back(text);
6349 return result;
6350}
6351
6352std::vector<std::string> TextListBreakLines(const char* text, uint32 maxLineLength) {
6353 if (!text || !strlen(text))
6354 return std::vector<std::string>();
6355
6356 std::string str;
6357 std::vector<std::string> result;
6358 uint32 s = 0, n = 0, len = (uint32)strlen(text);
6359 int p = -1;
6360 while (n < len) {
6361 if (text[n] == 13) {
6362 if (n == s)
6363 result.push_back("");
6364 else {
6365 str = std::string(text + s, n - s);
6366 result.push_back(TextTrim(str.c_str()));
6367 }
6368 if ((n < len - 1) && (text[n + 1] == 10))
6369 s = n + 2;
6370 else
6371 s = n + 1;
6372 p = -1;
6373 }
6374 else if (text[n] == 10) {
6375 if (n == s)
6376 result.push_back("");
6377 else {
6378 str = std::string(text + s, n - s);
6379 result.push_back(TextTrim(str.c_str()));
6380 }
6381 if ((n < len - 1) && (text[n + 1] == 13))
6382 s = n + 2;
6383 else
6384 s = n + 1;
6385 p = -1;
6386 }
6387 else if ((n-s < maxLineLength) && (text[n] == 32)) {
6388 p = n - s;
6389 }
6390 else if (n - s >= maxLineLength) {
6391 if (p == 0) {
6392 result.push_back("");
6393 s += p + 1;
6394 p = -1;
6395 n = s - 1;
6396 }
6397 else if (p > 0) {
6398 str = std::string(text + s, p);
6399 result.push_back(TextTrim(str.c_str()));
6400 s += p + 1;
6401 p = -1;
6402 n = s - 1;
6403 }
6404 else {
6405 str = std::string(text + s, maxLineLength);
6406 result.push_back(TextTrim(str.c_str()));
6407 s += maxLineLength;
6408 p = -1;
6409 n = s;
6410 }
6411 }
6412 n++;
6413 }
6414 if (s < n) {
6415 str = std::string(text + s, n - s);
6416 result.push_back(TextTrim(str.c_str()));
6417 }
6418
6419 return result;
6420}
6421
6422std::string TextListBreakLines(const char* text, uint32 maxLineLength, const char* breakstr) {
6423 std::vector<std::string> lines = TextListBreakLines(text, maxLineLength);
6424 if (!breakstr)
6425 return TextJoin(lines, "\n");
6426 else
6427 return TextJoin(lines, breakstr);
6428}
6429
6430std::string TextJoin(std::vector<std::string> &list, const char* split, uint32 start, uint32 count) {
6431 std::ostringstream o;
6432 std::vector<std::string>::iterator i = list.begin(), e = list.end();
6433 uint32 l = 0, c = 0;
6434 while (i != e) {
6435 if (!count || ((l >= start) && (c < count))) {
6436 if (c++) o << split;
6437 o << *i;
6438 }
6439 l++;
6440 i++;
6441 }
6442 return o.str();
6443}
6444
6445std::string TextJoin(std::list<std::string> &list, const char* split, uint32 start, uint32 count) {
6446 std::ostringstream o;
6447 std::list<std::string>::iterator i = list.begin(), e = list.end();
6448 uint32 l = 0, c = 0;
6449 while (i != e) {
6450 if (!count || ((l >= start) && (c < count))) {
6451 if (c++) o << split;
6452 o << *i;
6453 }
6454 l++;
6455 i++;
6456 }
6457 return o.str();
6458}
6459
6460std::string TextJoin(std::map<std::string, std::string> &map, const char* innersplit, const char* outersplit, bool keyquotes, bool valquotes) {
6461 std::ostringstream o;
6462 std::map<std::string, std::string>::iterator i = map.begin(), e = map.end();
6463 uint32 c = 0;
6464 while (i != e) {
6465 if (c++) o << outersplit;
6466 if (keyquotes && valquotes)
6467 o << "\"" << i->first << "\"" << innersplit << "\"" << i->second << "\"";
6468 else if (valquotes)
6469 o << i->first << innersplit << "\"" << i->second << "\"";
6470 else
6471 o << i->first << innersplit << i->second;
6472 i++;
6473 }
6474 return o.str();
6475}
6476
6477std::string TextJoinJSON(std::map<std::string, std::string> &map) {
6478 std::ostringstream o;
6479 std::map<std::string, std::string>::iterator i = map.begin(), e = map.end();
6480 uint32 c = 0;
6481 o << "{ ";
6482 while (i != e) {
6483 if (c++)
6484 o << ", \"" << utils::EncodeJSON(i->first) << "\": \"" << utils::EncodeJSON(i->second) << "\"";
6485 else
6486 o << " \"" << utils::EncodeJSON(i->first) << "\": \"" << utils::EncodeJSON(i->second) << "\"";
6487 i++;
6488 }
6489 o << " }";
6490 return o.str();
6491}
6492
6493std::string TextJoinXML(std::map<std::string, std::string> &map, const char* innernodeName, const char* outernodeName) {
6494 if (!innernodeName || !strlen(innernodeName))
6495 return "";
6496 std::ostringstream o;
6497 std::map<std::string, std::string>::iterator i = map.begin(), e = map.end();
6498 if (outernodeName && strlen(outernodeName))
6499 o << "<" << outernodeName << ">\n";
6500 while (i != e) {
6501 o << "<" << innernodeName << " " << html::EncodeHTML(i->first) << "=\"" << html::EncodeHTML(i->second) << "\" />\n";
6502 i++;
6503 }
6504 if (outernodeName && strlen(outernodeName))
6505 o << "</" << outernodeName << ">\n";
6506 return o.str();
6507}
6508
6509
6510
6511std::vector<std::string> TextListSplit(const char* text, const char* split, bool keepEmpty, bool autoTrim) {
6512 std::vector<std::string> result;
6513 if (!text || !split)
6514 return result;
6515
6516 uint32 splitLen = (uint32)strlen(split);
6517 const char* pstr = text;
6518 const char* src = text;
6519
6520 while (pstr = strstr(src, split)) {
6521 if (pstr - src || keepEmpty) {
6522 if (autoTrim)
6523 result.push_back(TextTrim(std::string(src, pstr - src).c_str()));
6524 else
6525 result.push_back(std::string(src, pstr - src).c_str());
6526 }
6527 src = pstr + splitLen;
6528 }
6529 pstr = src + strlen(src);
6530 if (pstr - src) {
6531 if (autoTrim)
6532 result.push_back(TextTrim(std::string(src, pstr - src).c_str()));
6533 else
6534 result.push_back(std::string(src, pstr - src).c_str());
6535 }
6536 return result;
6537}
6538
6539std::string TextVectorConcat(std::vector<std::string> vect, const char* sep, bool allowEmpty) {
6540 std::string result;
6541 std::vector<std::string>::iterator i, e;
6542 for (i=vect.begin(), e=vect.end(); i!=e; i++) {
6543 if (allowEmpty || (*i).size()) {
6544 if (result.size())
6545 result += sep;
6546 result += *i;
6547 }
6548 }
6549 return result;
6550}
6551
6552char* StringFormat(uint32& size, const char *format, ...) {
6553 if (strlen(format) == 0) {
6554 size = 0;
6555 return 0;
6556 }
6557
6558 va_list args;
6559 va_start(args, format);
6560 char* res = StringFormatVA(size, format, args);
6561 va_end(args);
6562 return res;
6563}
6564
6565
6566char* StringFormatVA(uint32& size, const char *format, va_list orig_args) {
6567 char* str = NULL;
6568
6569 #ifdef WINDOWS
6570 int len = _vscprintf(format, orig_args) + 10;
6571 str = (char*)malloc(len+1);
6572 #ifdef CYGWIN
6573 len = vsnprintf(str, len, format, orig_args);
6574 #else
6575 len = _vsnprintf_s(str, len, len+1, format, orig_args);
6576 #endif
6577
6578 if (len)
6579 size = (uint32)strlen(str);
6580 else {
6581 size = 0;
6582 free((char*)str);
6583 str = NULL;
6584 }
6585 #else // WINDOWS
6586 int len = vasprintf(&str, format, orig_args);
6587 if(len >= 0)
6588 size = strlen(str);
6589 else
6590 size = 0;
6591 #endif //HAVE_VASPRINTF
6592
6593 return str;
6594}
6595
6596bool StringFormatInto(char* dst, uint32 maxsize, const char *format, ...) {
6597 if (!dst || !maxsize)
6598 return false;
6599 if (strlen(format) == 0) {
6600 dst[0] = 0;
6601 return true;
6602 }
6603
6604 uint32 len = 0;
6605 va_list args;
6606 va_start(args, format);
6607 char* str = StringFormatVA(len, format, args);
6608 va_end(args);
6609 if (str && len) {
6610 if (len > maxsize) {
6611 free(str);
6612 return false;
6613 }
6614 else {
6615 utils::strcpyavail(dst, str, maxsize, true);
6616 free(str);
6617 return true;
6618 }
6619 }
6620 else {
6621 free(str);
6622 return false;
6623 }
6624}
6625
6626std::string StringFormat(const char *format, ...) {
6627 if (strlen(format) == 0)
6628 return "";
6629
6630 std::string res;
6631 uint32 len = 0;
6632 va_list args;
6633 va_start(args, format);
6634 char* str = StringFormatVA(len, format, args);
6635 va_end(args);
6636 if (str && len)
6637 res = str;
6638 else
6639 res = "";
6640 free(str);
6641 return res;
6642}
6643
6644uint32 StringSingleReplace(std::string& text, std::string key, std::string value, bool onlyFirst) {
6645 if (!text.size() || !key.size())
6646 return 0;
6647
6648 uint32 c = 0;
6649 size_t p = 0;
6650 uint32 keylen = (uint32)key.size();
6651
6652 while ( (p = text.find(key, p)) != std::string::npos) {
6653 text.replace(p, keylen, value);
6654 p++;
6655 c++;
6656 if (onlyFirst)
6657 break;
6658 }
6659 return c;
6660}
6661
6662uint32 StringMultiReplace(std::string& text, std::map<std::string, std::string>& map, bool onlyFirst) {
6663 if (!text.size() || !map.size())
6664 return 0;
6665
6666 uint32 c = 0;
6667
6668 std::map<std::string, std::string>::iterator it, itEnd;
6669 for (it = map.begin(), itEnd = map.end(); it != itEnd; ++it)
6670 c += StringSingleReplace(text, it->first, it->second, onlyFirst);
6671
6672 return c;
6673}
6674
6675
6676// Example use
6677 //uint32 len;
6678 //char* file = utils::ReadAFile("test.html", len);
6679 //std::string sfile = file;
6680
6681 //std::list<std::map<std::string, std::string> > list;
6682
6683 //char tmp[64];
6684 //std::map<std::string, std::string> map;
6685 //for (uint32 n=0; n<10; n++) {
6686 // map["%1%"] = utils::Int2Ascii(n, tmp, 64, 10);
6687 // map["%2%"] = "Hello2";
6688 // map["%3%"] = "Hello3";
6689 // map["%4%"] = "Hello4";
6690 // map["%5%"] = "Hello5";
6691 // list.push_back(map);
6692 //}
6693
6694 //utils::ScriptReplace(sfile, "test", list);
6695
6696uint32 StringScriptReplace(std::string& text, std::string name, std::list<std::map<std::string, std::string> >& list) {
6697 if (!text.size() || !name.size())
6698 return 0;
6699
6700 uint32 c = 0;
6701
6702 char* start = new char[name.size() + 50];
6703 snprintf(start, name.size()+50, "<!-- start:%s -->", name.c_str());
6704 char* end = new char[name.size() + 50];
6705 snprintf(end, name.size()+50, "<!-- end:%s -->", name.c_str());
6706
6707 // Find the section boundaries
6708 size_t a1 = text.find(start);
6709 if (a1 == std::string::npos) {
6710 delete [] start;
6711 delete [] end;
6712 return 0;
6713 }
6714 size_t b1 = text.find(end);
6715 if (b1 == std::string::npos) {
6716 delete [] start;
6717 delete [] end;
6718 return 0;
6719 }
6720
6721 uint32 a2 = (uint32)(a1 + strlen(start));
6722 uint32 b2 = (uint32)(b1 + strlen(end));
6723
6724 // Copy it
6725 std::string section = text.substr(a2, b1-a2);
6726 std::string tmp;
6727 std::string result;
6728
6729 std::list<std::map<std::string, std::string> >::iterator it, itEnd;
6730 for (it = list.begin(), itEnd = list.end(); it != itEnd; ++it) {
6731 tmp = section;
6732 c += StringMultiReplace(tmp, *it, false);
6733 result += tmp;
6734 }
6735
6736 text.replace(a1, b2-a1, result);
6737 delete [] start;
6738 delete [] end;
6739 return c;
6740}
6741
6742
6743
6744unsigned char Hex2Char(const char* str) {
6745 unsigned char c = (unsigned char) strtol(str, NULL, 16);
6746 if (c == 0)
6747 return ' ';
6748 else
6749 return c;
6750}
6751
6752unsigned char Dec2Char(const char* str) {
6753 unsigned char c = (unsigned char) strtol(str, NULL, 10);
6754 if (c == 0)
6755 return ' ';
6756 else
6757 return c;
6758}
6759
6760int8 CompareFloats(float64 a, float64 b) {
6761 float64 diff = a - b;
6762 if ((diff < std::numeric_limits<float64>::epsilon()) && (-diff < std::numeric_limits<float64>::epsilon()))
6763 return 0;
6764 else if (diff > 0)
6765 return 1;
6766 else
6767 return -1;
6768}
6769
6770
6771#define poly 0xEDB88320
6772/* Some compilers need
6773 #define poly 0xEDB88320uL
6774 */
6775
6776/* On entry, addr=>start of data
6777 num = length of data
6778 crc = incoming CRC */
6779int CRC32(const char *addr, uint32 length, int32 crc) {
6780 uint32 i;
6781 for (; length>0; length--) { /* Step through bytes in memory */
6782 crc = crc ^ *addr++; /* Fetch byte from memory, XOR into CRC */
6783 for (i=0; i<8; i++) { /* Prepare to rotate 8 bits */
6784 if (crc & 1) /* b0 is set... */
6785 crc = (crc >> 1) ^ poly; /* rotate and XOR with ZIP polynomic */
6786 else /* b0 is clear... */
6787 crc >>= 1; /* just rotate */
6788 /* Some compilers need:
6789 crc &= 0xFFFFFFFF;
6790 */
6791 } /* Loop for 8 bits */
6792 } /* Loop until num=0 */
6793 return(crc); /* Return updated CRC */
6794}
6795
6796
6797std::string ReadAFileString(std::string filename) {
6798 uint32 length;
6799 char* data = ReadAFile(filename.c_str(), length, false);
6800 if (!data || !length)
6801 return "";
6802 std::string dataString = data;
6803 delete [] data;
6804 return dataString;
6805}
6806
6807char* ReadAFile(const char* dir, const char* filename, uint32& length, bool binary) {
6808 if (!dir || !filename || strlen(filename) == 0)
6809 return NULL;
6810
6811 char* fullname = new char[strlen(dir) + strlen(filename) + 5];
6812 snprintf(fullname, strlen(dir) + strlen(filename) + 5, "%s/%s", dir, filename);
6813 char* res = ReadAFile(fullname, length, binary);
6814 delete [] fullname;
6815 return res;
6816}
6817
6818char* ReadAFile(const char* filename, uint32& length, bool binary) {
6819 if (!filename || strlen(filename) == 0)
6820 return NULL;
6821
6822 length = 0;
6823
6824 FILE* file;
6825 if (binary)
6826 file = fopen(filename, "rb");
6827 else
6828 file = fopen(filename, "r");
6829 if (file == NULL) {
6830 //LogPrint(0,0,0,"Couldn't open file %s", filename);
6831 return NULL;
6832 }
6833
6834 fseek(file, 0, SEEK_END);
6835 length = ftell(file);
6836 fseek(file, 0, SEEK_SET);
6837
6838 if (length <= 0) {
6839 fclose(file);
6840 //LogPrint(0,0,0,"File %s has no size", filename);
6841 return NULL;
6842 }
6843
6844 char* data = new char[length+1];
6845
6846 int res = (int)fread(data, 1, length, file);
6847
6848 if ((res <= 0) || (res != length)) {
6849 int error = ferror(file);
6850 int eof = feof(file);
6851 if (eof == 0) {
6852 delete [] data;
6853 fclose(file);
6854 LogPrint(0,0,0,"File %s has no data", filename);
6855 return NULL;
6856 }
6857 }
6858
6859 fclose(file);
6860
6861 length = (uint32)res;
6862 data[length] = 0;
6863 return data;
6864}
6865
6866bool WriteAFile(const char* dir, const char* filename, const char* data, uint32 length, bool binary) {
6867 if (!dir || !filename || strlen(filename) == 0)
6868 return false;
6869
6870 char* fullname = new char[strlen(dir) + strlen(filename) + 5];
6871 snprintf(fullname, strlen(dir) + strlen(filename) + 5, "%s/%s", dir, filename);
6872 bool res = WriteAFile(fullname, data, length, binary);
6873 delete [] fullname;
6874 return res;
6875}
6876
6877bool WriteAFile(const char* filename, const char* data, uint32 length, bool binary) {
6878 if (!filename || strlen(filename) == 0)
6879 return false;
6880
6881 FILE* file;
6882 if (binary)
6883 file = fopen(filename, "wb");
6884 else
6885 file = fopen(filename, "w");
6886 if (file == NULL)
6887 return false;
6888
6889 int res = (int)fwrite(data, 1, length, file);
6890 fclose(file);
6891 return (res == length);
6892}
6893
6894bool AppendToAFile(const char* dir, const char* filename, const char* data, uint32 length, bool binary) {
6895 if (!dir || !filename || strlen(filename) == 0)
6896 return false;
6897
6898 char* fullname = new char[strlen(dir) + strlen(filename) + 5];
6899 snprintf(fullname, strlen(dir) + strlen(filename) + 5, "%s/%s", dir, filename);
6900 bool res = AppendToAFile(fullname, data, length, binary);
6901 delete [] fullname;
6902 return res;
6903}
6904
6905bool AppendToAFile(const char* filename, const char* data, uint32 length, bool binary) {
6906 if (!filename || strlen(filename) == 0)
6907 return false;
6908
6909 FILE* file;
6910 if (binary)
6911 file = fopen(filename, "ab");
6912 else
6913 file = fopen(filename, "a");
6914 if (file == NULL)
6915 return false;
6916
6917 int res = (int)fwrite(data, 1, length, file);
6918 fclose(file);
6919 return (res == length);
6920}
6921
6922bool DeleteAFile(const char* dir, const char* filename, bool force) {
6923 if (!dir || !filename || strlen(filename) == 0)
6924 return false;
6925
6926 char* fullname = new char[strlen(dir) + strlen(filename) + 5];
6927 snprintf(fullname, strlen(dir) + strlen(filename) + 5, "%s/%s", dir, filename);
6928 bool res = DeleteADir(fullname, force);
6929 delete [] fullname;
6930 return res;
6931}
6932
6933bool DeleteAFile(const char* filename, bool force) {
6934 return DeleteADir(filename, force);
6935}
6936
6937bool ChangeAFileAttr(const char* filename, bool read, bool write) {
6938 if (!filename || strlen(filename) == 0)
6939 return false;
6940 #ifdef WINDOWS
6941 if (!write)
6942 return (SetFileAttributes(filename, FILE_ATTRIBUTE_READONLY) != 0);
6943 else
6944 return (SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL) != 0);
6945 #else
6946 if (read && write)
6947 return (chmod(filename,S_IREAD | S_IWRITE) != 0);
6948 else if (read)
6949 return (chmod(filename,S_IREAD) == 0);
6950 else if (write)
6951 return (chmod(filename,S_IWRITE) == 0);
6952 else
6953 return (chmod(filename,0) == 0);
6954 #endif
6955}
6956
6957bool MoveAFile(const char* oldfilename, const char* newfilename, bool force) {
6958 #ifdef WINDOWS
6959 bool result;
6960 if (force)
6961 result = (MoveFileEx(oldfilename, newfilename, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0);
6962 else
6963 result = (MoveFileEx(oldfilename, newfilename, MOVEFILE_COPY_ALLOWED) != 0);
6964 if (result)
6965 return true;
6966 LogPrint(0,LOG_SYSTEM,0,"MoveAFile '%s' to '%s' failed with: %s", oldfilename, newfilename, GetLastOSErrorMessage().c_str());
6967 return false;
6968 #else
6969 if (rename(oldfilename, newfilename) == 0)
6970 return true;
6971 int error = errno;
6972 if (force) {
6973 FileDetails info = GetFileDetails(newfilename);
6974 if (info.doesExist) {
6975 delete(newfilename);
6976 if (rename(oldfilename, newfilename) == 0)
6977 return true;
6978 }
6979 }
6980 if (error == EXDEV) {
6981 if (CopyAFile(newfilename, oldfilename)) {
6982 DeleteAFile(oldfilename, true);
6983 return true;
6984 }
6985 }
6986 return false;
6987 #endif
6988}
6989
6990bool MoveAFile(const char* olddir, const char* oldfilename, const char* newdir, const char* newfilename, bool force) {
6991 if (!newdir || !newfilename || !strlen(newfilename) ||
6992 !olddir || !oldfilename || !strlen(oldfilename) )
6993 return false;
6994
6995 char* oldname = new char[strlen(olddir) + strlen(oldfilename) + 5];
6996 snprintf(oldname, strlen(olddir) + strlen(oldfilename) + 5, "%s/%s", olddir, oldfilename);
6997 char* newname = new char[strlen(newdir) + strlen(newfilename) + 5];
6998 snprintf(newname, strlen(newdir) + strlen(newfilename) + 5, "%s/%s", newdir, newfilename);
6999 bool res = MoveAFile(newname, oldname, force);
7000 delete [] oldname;
7001 delete [] newname;
7002 return res;
7003}
7004
7005bool CopyAFile(const char* oldfilename, const char* newfilename, bool force) {
7006 #ifdef WINDOWS
7007 if (force)
7008 return (CopyFile(oldfilename, newfilename, FALSE) != 0);
7009 else
7010 return (CopyFile(oldfilename, newfilename, TRUE) != 0);
7011 #else
7012 FileDetails target = GetFileDetails(newfilename);
7013 if (target.doesExist && !force)
7014 return false;
7015 if (target.isDirectory)
7016 return false;
7017 uint32 size;
7018 char* data = ReadAFile(oldfilename, size, true);
7019 if (!data || !size) {
7020 delete [] data;
7021 return false;
7022 }
7023
7024 if ((target.doesExist) && !DeleteAFile(newfilename, true)) {
7025 delete [] data;
7026 return false;
7027 }
7028
7029 if (!WriteAFile(newfilename, data, size, true)) {
7030 delete [] data;
7031 return false;
7032 }
7033 delete [] data;
7034 return true;
7035 #endif
7036}
7037
7038bool CopyAFile(const char* olddir, const char* oldfilename, const char* newdir, const char* newfilename, bool force) {
7039 if (!newdir || !newfilename || !strlen(newfilename) ||
7040 !olddir || !oldfilename || !strlen(oldfilename) )
7041 return false;
7042
7043 char* oldname = new char[strlen(olddir) + strlen(oldfilename) + 5];
7044 snprintf(oldname, strlen(olddir) + strlen(oldfilename) + 5, "%s/%s", olddir, oldfilename);
7045 char* newname = new char[strlen(newdir) + strlen(newfilename) + 5];
7046 snprintf(newname, strlen(newdir) + strlen(newfilename) + 5, "%s/%s", newdir, newfilename);
7047 bool res = CopyAFile(newname, oldname, force);
7048 delete [] oldname;
7049 delete [] newname;
7050 return res;
7051}
7052
7053bool CreateADir(const char* dirname) {
7054 if (!dirname || strlen(dirname) == 0)
7055 return false;
7056
7057 FileDetails info = GetFileDetails(dirname);
7058
7059 if (info.doesExist) {
7060 if (info.isDirectory)
7061 return true;
7062 else
7063 return false;
7064 }
7065
7066 #ifdef WINDOWS
7067 if (CreateDirectory(dirname, NULL) != 0)
7068 return true;
7069 else
7070 return false;
7071 #else
7072 if (mkdir(dirname, S_IRWXU | S_IRWXG | S_IRWXO) == 0)
7073 return true;
7074 else
7075 return false;
7076 #endif
7077}
7078
7079bool DeleteADir(const char* dirname, bool force) {
7080 if (!dirname || strlen(dirname) == 0)
7081 return false;
7082
7083 FileDetails info = GetFileDetails(dirname);
7084
7085 if (!info.doesExist)
7086 return true;
7087
7088 // If it is a file
7089 if (!info.isDirectory) {
7090 #ifdef WINDOWS
7091 if (DeleteFile(dirname) != 0)
7092 return true;
7093 else if (!force)
7094 return false;
7095 else {
7096 ChangeAFileAttr(dirname, true, true);
7097 if (DeleteFile(dirname) != 0)
7098 return true;
7099 else
7100 return false;
7101 }
7102 #else
7103 if (unlink(dirname) == 0)
7104 return true;
7105 else if (!force)
7106 return false;
7107 else {
7108 ChangeAFileAttr(dirname, true, true);
7109 if (unlink(dirname) == 0)
7110 return true;
7111 else
7112 return false;
7113 }
7114 #endif
7115 }
7116
7117 // Now we know it is a dir
7118 #ifdef WINDOWS
7119 if (RemoveDirectory(dirname) != 0)
7120 return true;
7121 else if (!force)
7122 return false;
7123 else {
7124 DeleteFilesInADir(dirname, true);
7125 if (RemoveDirectory(dirname) != 0)
7126 return true;
7127 else
7128 return false;
7129 }
7130 #else
7131 if (rmdir(dirname) == 0)
7132 return true;
7133 else if (!force)
7134 return false;
7135 else {
7136 DeleteFilesInADir(dirname, true);
7137 if (rmdir(dirname) == 0)
7138 return true;
7139 else
7140 return false;
7141 }
7142 #endif
7143
7144}
7145
7146bool DeleteFilesInADir(const char* dirname, bool force) {
7147 if (!dirname || strlen(dirname) == 0)
7148 return false;
7149
7150 uint32 count;
7151 char* files = utils::GetFileList(dirname, NULL, count, true);
7152 if (!files)
7153 return true;
7154
7155 const char* name;
7156 for (uint32 n = 0; n<count; n++) {
7157 name = files + (n*(MAXFILENAMELEN+1));
7158 if (!DeleteADir(name, force)) {
7159 delete[] files;
7160 return false;
7161 }
7162 }
7163
7164 delete [] files;
7165 return true;
7166}
7167
7168
7169
7170
7171
7172uint32 TextReplaceCharsInPlace(char* str, uint32 size, char find, char replace) {
7173 uint32 c = 0;
7174 for (uint32 n=0; n<size; n++) {
7175 if (str[n] == find) {
7176 str[n] = replace;
7177 c++;
7178 }
7179 }
7180 return c;
7181}
7182
7183const char* laststrstr(const char* str1, const char* str2) {
7184 const char* strp;
7185 int len1, len2;
7186
7187 len2 = (int)strlen(str2);
7188 if(len2==0)
7189 return (char*)str1;
7190
7191 len1 = (int)strlen(str1);
7192 if (len1 == len2)
7193 return (strcmp(str1, str2) == 0) ? str1 : 0;
7194 else if (len1 - len2 < 0)
7195 return 0;
7196
7197 strp = (char*)(str1 + len1 - len2);
7198 while(strp != str1) {
7199 if(*strp == *str2) {
7200 if(strncmp(strp,str2,len2)==0)
7201 return strp;
7202 }
7203 strp--;
7204 }
7205 return 0;
7206}
7207
7208const char* laststristr(const char* str1, const char* str2) {
7209 const char* strp;
7210 int len1, len2;
7211
7212 len2 = (int)strlen(str2);
7213 if(len2==0)
7214 return (char*)str1;
7215
7216 len1 = (int)strlen(str1);
7217 if (len1 == len2)
7218 return (stricmp(str1, str2) == 0) ? str1 : 0;
7219 else if (len1 - len2 < 0)
7220 return 0;
7221
7222 strp = (char*)(str1 + len1 - len2);
7223 while(strp != str1) {
7224 if(*strp == *str2) {
7225 if(strnicmp(strp,str2,len2)==0)
7226 return strp;
7227 }
7228 strp--;
7229 }
7230 return 0;
7231}
7232
7233bool TextEndsWith(const char* str, const char* end, bool caseSensitive) {
7234 if (!caseSensitive)
7235 return (laststristr(str, end) == str + strlen(str) - strlen(end));
7236 else
7237 return (laststrstr(str, end) == str + strlen(str) - strlen(end));
7238}
7239
7240bool TextStartsWith(const char* str, const char* start, bool caseSensitive) {
7241 if (!caseSensitive)
7242 return (stristr(str, start) == str);
7243 else
7244 return (strstr(str, start) == str);
7245}
7246
7247
7248std::string GetFilePath(const char* filename) {
7249 std::string name = filename;
7250 std::string::size_type p1 = name.find_last_of('/');
7251 std::string::size_type p2 = name.find_last_of('\\');
7252 if (p1 == std::string::npos) {
7253 if (p2 == std::string::npos)
7254 return "";
7255 else
7256 return name.substr(0, p2 + 1);
7257 }
7258 else if (p2 == std::string::npos)
7259 return name.substr(0, p1 + 1);
7260 else
7261 return name.substr(0, (p1 > p2) ? p1 + 1 : p2 + 1);
7262}
7263
7264const char* GetFileBasename(const char* filename) {
7265 std::string name = filename;
7266 std::string::size_type p1 = name.find_last_of('/');
7267 std::string::size_type p2 = name.find_last_of('\\');
7268 if (p1 == std::string::npos) {
7269 if (p2 == std::string::npos)
7270 return filename;
7271 else
7272 return filename + p2 + 1;
7273 }
7274 else if (p2 == std::string::npos)
7275 return filename + p1 + 1;
7276 else
7277 return (p1 > p2) ? filename + p1 + 1 : filename + p2 + 1;
7278}
7279
7280std::string GetCurrentDir() {
7281
7282 char cCurrentPath[FILENAME_MAX];
7283
7284 if (!GetCurrentDirEx(cCurrentPath, sizeof(cCurrentPath)))
7285 {
7286 return "";
7287 }
7288 cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
7289 //printf("The current working directory is %s\n", cCurrentPath);
7290 return cCurrentPath;
7291}
7292
7293char* GetFileList(const char* dirname, const char* ext, uint32& count, bool fullpath, uint32 maxNameLen) {
7294 DIR* dir = opendir(dirname);
7295 if (dir == NULL)
7296 return NULL;
7297
7298 uint32 extlen = (ext == NULL) ? 0 : (uint32)strlen(ext);
7299 struct dirent* direntry = NULL;
7300
7301 uint32 tempMaxCount = 50;
7302 uint32 len = (maxNameLen+1)*tempMaxCount;
7303 char* result = new char[len];
7304 char* dst = result;
7305 char* tmp;
7306 uint32 dirnamelen = (uint32)strlen(dirname);
7307 bool dirslash = (*(dirname + dirnamelen - 1) == '/') || (*(dirname + dirnamelen - 1) == '\\');
7308
7309 count = 0;
7310 direntry = readdir(dir);
7311 while (direntry) {
7312 #ifdef WINDOWS
7313 if (direntry->d_name && direntry->d_name[0] != '\0') {
7314 #else
7315 if (direntry->d_name[0] != '\0') {
7316 #endif
7317 if ( !strcmp(direntry->d_name, ".") || !strcmp(direntry->d_name, "..") ) {
7318 direntry = readdir(dir);
7319 continue;
7320 }
7321 if (ext && extlen && !TextEndsWith(direntry->d_name, ext)) {
7322 direntry = readdir(dir);
7323 continue;
7324 }
7325 if (fullpath) {
7326 utils::strcpyavail(dst, dirname, maxNameLen, true);
7327 if (!dirslash) {
7328 memset(dst+dirnamelen, '/', 1);
7329 utils::strcpyavail(dst+dirnamelen+1, direntry->d_name, maxNameLen, true);
7330 }
7331 else
7332 utils::strcpyavail(dst+dirnamelen, direntry->d_name, maxNameLen, true);
7333 }
7334 else
7335 utils::strcpyavail(dst, direntry->d_name, maxNameLen, true);
7336 dst+= maxNameLen+1;
7337 count++;
7338 if (count >= tempMaxCount) {
7339 tempMaxCount *= 2;
7340 tmp = new char[len*2];
7341 memcpy(tmp, result, len);
7342 delete [] result;
7343 result = tmp;
7344 dst = result + len;
7345 len *= 2;
7346 }
7347 }
7348 direntry = readdir(dir);
7349 }
7350 closedir(dir);
7351 return result;
7352}
7353
7354bool DoesADirExist(const char* dirname) {
7355 FileDetails details = GetFileDetails(dirname);
7356 return (details.doesExist && details.isDirectory);
7357}
7358
7359bool DoesAFileExist(const char* filename) {
7360 FileDetails details = GetFileDetails(filename);
7361 return (details.doesExist && !details.isDirectory);
7362}
7363
7364FileDetails GetFileDetails(const char* filename) {
7365 struct stat statbuf;
7366 int fd, result;
7367
7368 FileDetails info;
7369
7370 info.doesExist = false;
7371 info.isDirectory = false;
7372 info.isReadable = false;
7373 info.isWritable = false;
7374 info.isExecutable = false;
7375 info.size = 0;
7376 info.lastAccessTime = 0;
7377 info.lastModifyTime = 0;
7378 info.creationTime = 0;
7379
7380 // If file cannot be opened
7381 if ((fd = _open(filename, O_RDONLY)) == -1) {
7382 // On Windows, this might be a dir
7383 DIR* dir = opendir(filename);
7384 if (dir == NULL)
7385 return info;
7386 struct dirent* direntry = readdir(dir);
7387
7388 info.doesExist = true;
7389 info.isDirectory = true;
7391 info.isReadable = true;
7392 info.isWritable = true;
7393 info.isExecutable = true;
7394
7395 closedir(dir);
7396 return info;
7397 }
7398
7399 // Get data associated with "fd":
7400 result = fstat(fd, &statbuf);
7401
7402 // Check if statistics are valid:
7403 if( result != 0 ) {
7404 _close(fd);
7405 return info;
7406 }
7407
7408 _close(fd);
7409 info.doesExist = true;
7410
7411 info.size = statbuf.st_size;
7412 info.isDirectory = ((statbuf.st_mode & S_IFDIR) != 0);
7413 info.lastAccessTime = FTime2PsyTime(statbuf.st_atime);
7414 info.lastModifyTime = FTime2PsyTime(statbuf.st_ctime);
7415 info.creationTime = FTime2PsyTime(statbuf.st_ctime);
7416
7417 #ifdef WINDOWS
7418 info.isReadable = ((statbuf.st_mode & _S_IREAD) != 0);
7419 info.isWritable = ((statbuf.st_mode & _S_IWRITE) != 0);
7420 info.isExecutable = ((statbuf.st_mode & _S_IEXEC) != 0);
7421 #else
7422 info.isReadable = ((statbuf.st_mode & S_IRUSR) != 0);
7423 info.isWritable = ((statbuf.st_mode & S_IWUSR) != 0);
7424 info.isExecutable = ((statbuf.st_mode & S_IXUSR) != 0);
7425 #endif
7426
7427 return info;
7428
7429}
7430
7431char* TextSubstringCopy(const char* ascii, uint32 start, uint32 end) {
7432 uint32 len;
7433 char* copy;
7434 if (!ascii || (start >= end) || (!(len = (uint32)strlen(ascii))) ) {
7435 copy = new char[1];
7436 copy[0] = 0;
7437 }
7438 else {
7439 if (end > len - 1)
7440 end = len - 1;
7441 copy = new char[end - start + 2];
7442 memcpy(copy, ascii + start,
7443 end - start + 1);
7444 copy[end - start + 1] = 0;
7445 }
7446 return copy;
7447}
7448
7449
7450bool IsTextNumeric(const char* ascii, uint32 start, uint32 end) {
7451 if (!ascii || (start > end)) return false;
7452 uint32 len = (uint32)strlen(ascii);
7453 uint32 stop = end ? end+1 : len;
7454 if (stop > len) stop = len;
7455 for (uint32 n=start; n<stop; n++) {
7456 if (( ascii[n] < '0' || ascii[n] > '9') && ascii[n] != '.')
7457 return false;
7458 }
7459 return true;
7460}
7461
7462int64 Ascii2Int64(const char* ascii, uint32 start, uint32 end) {
7463 if (!ascii || (start > end)) return false;
7464 if (!end)
7465 #ifdef WINDOWS
7466 return _strtoi64(ascii + start, NULL, 10);
7467 #else
7468 return strtoll(ascii + start, NULL, 10);
7469 #endif
7470 char* copy = TextSubstringCopy(ascii, start, end);
7471 #ifdef WINDOWS
7472 int64 val = _strtoi64(copy, NULL, 10);
7473 #else
7474 int64 val = strtoll(copy, NULL, 10);
7475 #endif
7476 delete[] copy;
7477 return val;
7478}
7479
7480uint64 Ascii2Uint64(const char* ascii, uint32 start, uint32 end) {
7481 if (!ascii || (start > end)) return false;
7482 if (!end)
7483 #ifdef WINDOWS
7484 return _strtoui64(ascii + start, NULL, 10);
7485 #else
7486 return strtoull(ascii + start, NULL, 10);
7487 #endif
7488 char* copy = TextSubstringCopy(ascii, start, end);
7489 #ifdef WINDOWS
7490 uint64 val = _strtoui64(copy, NULL, 10);
7491 #else
7492 uint64 val = strtoull(copy, NULL, 10);
7493 #endif
7494 delete[] copy;
7495 return val;
7496}
7497
7498uint64 AsciiHex2Uint64(const char* ascii, uint32 start, uint32 end) {
7499 if (!ascii || (start > end)) return false;
7500 if (!end)
7501 #ifdef WINDOWS
7502 return _strtoui64(ascii + start, NULL, 16);
7503 #else
7504 return strtoull(ascii + start, NULL, 16);
7505 #endif
7506 char* copy = TextSubstringCopy(ascii, start, end);
7507 #ifdef WINDOWS
7508 uint64 val = _strtoui64(copy, NULL, 16);
7509 #else
7510 uint64 val = strtoull(copy, NULL, 16);
7511 #endif
7512 delete[] copy;
7513 return val;
7514}
7515
7516int32 Ascii2Int32(const char* ascii, uint32 start, uint32 end) {
7517 if (!ascii || (start > end)) return false;
7518 if (!end)
7519 return (int32)strtol(ascii + start, NULL, 10);
7520 char* copy = TextSubstringCopy(ascii, start, end);
7521 int32 val = (int32)strtol(copy, NULL, 10);
7522 delete[] copy;
7523 return val;
7524}
7525
7526uint32 Ascii2Uint32(const char* ascii, uint32 start, uint32 end) {
7527 if (!ascii || (start > end)) return false;
7528 if (!end)
7529 return (uint32)strtoul(ascii + start, NULL, 10);
7530 char* copy = TextSubstringCopy(ascii, start, end);
7531 uint32 val = (uint32)strtoul(copy, NULL, 10);
7532 delete[] copy;
7533 return val;
7534}
7535
7536uint32 AsciiHex2Uint32(const char* ascii, uint32 start, uint32 end) {
7537 if (!ascii || (start > end)) return false;
7538 if (!end)
7539 return (uint32)strtoul(ascii + start, NULL, 16);
7540 char* copy = TextSubstringCopy(ascii, start, end);
7541 uint32 val = (uint32)strtoul(copy, NULL, 16);
7542 delete[] copy;
7543 return val;
7544}
7545
7546float64 Ascii2Float64(const char* ascii, uint32 start, uint32 end) {
7547 if (!ascii || (start > end)) return false;
7548 if (!end)
7549 return strtod(ascii + start, NULL);
7550 char* copy = TextSubstringCopy(ascii, start, end);
7551 float64 val = strtod(copy, NULL);
7552 delete[] copy;
7553 return val;
7554}
7555
7556
7557std::string DecodeJSON(std::string str) {
7558 bool isEscaped = false;
7559 char* tmp = new char[5];
7560 tmp[4] = 0;
7561 std::ostringstream o;
7562 std::string::iterator c;
7563 for (c = str.begin(); c != str.end(); c++) {
7564 if (isEscaped) {
7565 switch (*c) {
7566 case '"': o << "\""; break;
7567 case '\\': o << "\\"; break;
7568 case 'b': o << "\b"; break;
7569 case 'f': o << "\f"; break;
7570 case 'n': o << "\n"; break;
7571 case 'r': o << "\r"; break;
7572 case 't': o << "\t"; break;
7573 case 'u':
7574 c++;
7575 tmp[0] = (uint8)(*c++);
7576 tmp[1] = (uint8)(*c++);
7577 tmp[2] = (uint8)(*c++);
7578 tmp[3] = (uint8)(*c);
7579 o << (char) strtol(tmp, NULL, 16);
7580 break;
7581 default: o << *c;
7582 }
7583 isEscaped = false;
7584 }
7585 else {
7586 switch (*c) {
7587 case '\\': isEscaped = true; break;
7588 default: o << *c;
7589 }
7590 }
7591 }
7592 delete[] tmp;
7593 return o.str();
7594}
7595
7596std::string EncodeJSON(std::string str) {
7597 std::ostringstream o;
7598 std::string::iterator c;
7599 for (c = str.begin(); c != str.end(); c++) {
7600 switch (*c) {
7601 case '"': o << "\\\""; break;
7602 case '\\': o << "\\\\"; break;
7603 case '\b': o << "\\b"; break;
7604 case '\f': o << "\\f"; break;
7605 case '\n': o << "\\n"; break;
7606 case '\r': o << "\\r"; break;
7607 case '\t': o << "\\t"; break;
7608 default:
7609 if ('\x00' <= *c && *c <= '\x1f') {
7610 o << "\\u"
7611 << std::hex << std::setw(4) << std::setfill('0') << (int)*c;
7612 } else {
7613 o << *c;
7614 }
7615 }
7616 }
7617 return o.str();
7618
7619 //if (str.size() == 0)
7620 // return str;
7621 //std::string result = str;
7622 //char c;
7623 //char* tmp = (char*)malloc(20);
7624
7625 //for (uint32 n=0; n<result.size(); n++) {
7626 // switch(c = result[n]) {
7627 // case '\n':
7628 // result.replace(n, 1, "\\n");
7629 // n+=1;
7630 // break;
7631 // case '\r':
7632 // result.replace(n, 1, "\\r");
7633 // n+=1;
7634 // break;
7635 // case '\t':
7636 // result.replace(n, 1, "\\t");
7637 // n+=2;
7638 // break;
7639 // case '"':
7640 // result.replace(n, 1, "\\\"");
7641 // n+=2;
7642 // break;
7643 // case '\\':
7644 // result.replace(n, 1, "\\\\");
7645 // n+=2;
7646 // break;
7647 // case '\b':
7648 // result.replace(n, 1, "\\b");
7649 // n+=2;
7650 // break;
7651 // case '\f':
7652 // result.replace(n, 1, "\\f");
7653 // n+=2;
7654 // break;
7655 // default:
7656 // if ('\x00' <= c && c <= '\x1f') {
7657 // snprintf(tmp, 20, "\\u%.4x;", (int) c & 0xFF);
7658 // result.replace(n, 1, tmp);
7659 // n+=(uint32)strlen(tmp)-1;
7660 // }
7661 // break;
7662 // }
7663 //}
7664
7665 //free((char*)tmp);
7666
7667 //return result;
7668}
7669
7670
7671// Seeds the rand() function
7672bool SeedRandomValues(uint32 seedvalue) {
7673 srand( seedvalue ? seedvalue : (uint32)GetTimeNow());
7674 return true;
7675}
7676
7677// Returns a random value between 0.0 and 1.0
7678double RandomValue() {
7679 double d = 0;
7680 double t = (1.0/((RAND_MAX + 1.0)*(RAND_MAX + 1.0)*(RAND_MAX + 1.0)));
7681 do {
7682 d = (rand () * ((RAND_MAX + 1.0) * (RAND_MAX + 1.0))
7683 + rand () * (RAND_MAX + 1.0)
7684 + rand ()) * t;
7685 } while (d >= 1); /* Round off */
7686 return d;
7687}
7688
7689// Returns a random value between 0.0 and max
7690double RandomValue(double max) {
7691 return RandomValue() * max;
7692}
7693
7694// Returns a random value between from and to
7695double RandomValue(double from, double to) {
7696 if (to < from)
7697 return (RandomValue()*(from-to))+to;
7698 else
7699 return (RandomValue()*(to-from))+from;
7700}
7701
7702// Returns a random value between from and to, rounded to nearest interval
7703double RandomValue(double from, double to, double interval) {
7704 if (to < from)
7705 return RandomValue(to, from, interval);
7706 double r = RandomValue(0, to-from);
7707 uint64 n = (uint64)(r/interval);
7708 double l = r - (n*interval);
7709 if (l >= (0.5*interval))
7710 return from + (n*interval);
7711 else
7712 return from + ((n+1)*interval);
7713}
7714
7715int64 RandomInt(int64 from, int64 to) {
7716 return (int64)roundl(RandomValue((double)from, (double)to));
7717}
7718
7719
7720//std::string BytifySize(int32 val) {
7721// return BytifySize((double)val);
7722//}
7723
7724std::string BytifySize(double val) {
7725
7726 double kb = 1024;
7727 double mb = kb*1024;
7728 double gb = mb*1024;
7729 double tb = gb*1024;
7730
7731 char *tmp = new char[64];
7732
7733 if (val < 512)
7734 snprintf(tmp, 64, "%.2f B", val);
7735 else if (val < 512*kb) {
7736 val = val / kb;
7737 snprintf(tmp, 64, "%.2f KB", val);
7738 }
7739 else if (val < 512*mb) {
7740 val = val / mb;
7741 snprintf(tmp, 64, "%.2f MB", val);
7742 }
7743 else if (val < 512*gb) {
7744 val = val / gb;
7745 snprintf(tmp, 64, "%.2f GB", val);
7746 }
7747 else {
7748 val = val / tb;
7749 snprintf(tmp, 64, "%.2f TB", val);
7750 }
7751
7752 std::string result = tmp;
7753 delete [] tmp;
7754 return result;
7755}
7756
7757//std::string BytifySizes(int32 val1, int32 val2) {
7758// return BytifySizes((double)val1, (double) val2);
7759//}
7760
7761std::string BytifySizes(double val1, double val2) {
7762
7763 double kb = 1024;
7764 double mb = kb*1024;
7765 double gb = mb*1024;
7766 double tb = gb*1024;
7767
7768 char *tmp = new char[64];
7769 char *end = new char[64];
7770
7771 double val;
7772 double maximum = ((val1 > val2) ? val1 : val2);
7773
7774 if (maximum < 512) {
7775 val = 1;
7776 utils::strcpyavail(end, "B", 32, true);
7777 }
7778 else if (maximum < 512*kb) {
7779 val = kb;
7780 utils::strcpyavail(end, "KB", 32, true);
7781 }
7782 else if (maximum < 512*mb) {
7783 val = mb;
7784 utils::strcpyavail(end, "MB", 32, true);
7785 }
7786 else if (maximum < 512*gb) {
7787 val = gb;
7788 utils::strcpyavail(end, "GB", 32, true);
7789 }
7790 else {
7791 val = gb;
7792 utils::strcpyavail(end, "TB", 32, true);
7793 }
7794 snprintf(tmp, 64, "%.2f / %.2f %s", ((double)val1)/val, ((double)val2)/val, (char*) end);
7795
7796 std::string result = tmp;
7797 delete [] tmp;
7798 delete [] end;
7799 return result;
7800
7801}
7802
7803//std::string BytifyRate(int32 val) {
7804// return BytifyRate((double)val);
7805//}
7806
7807std::string BytifyRate(double val) {
7808 char *tmp = new char[64];
7809 snprintf(tmp, 64, "%s/sec", (char*) BytifySize(val).c_str());
7810 std::string result = tmp;
7811 delete [] tmp;
7812 return result;
7813}
7814
7815//std::string BytifyRates(int32 val1, int32 val2) {
7816// return BytifyRates((double)val1, (double)val2);
7817//}
7818
7819std::string BytifyRates(double val1, double val2) {
7820 char *tmp = new char[64];
7821 snprintf(tmp, 64, "%s/sec", (char*) BytifySizes(val1, val2).c_str());
7822 std::string result = tmp;
7823 delete [] tmp;
7824 return result;
7825}
7826
7827
7828
7829
7830
7831
7832
7833#ifdef WINDOWS
7834
7835uint32 ReadRegistryDWORD(const char* key, const char* entry) {
7836 HKEY hKeyRoot, hKey;
7837 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7838
7839 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
7840 if (err != ERROR_SUCCESS)
7841 return 0;
7842
7843 DWORD dwType = REG_DWORD;
7844 DWORD numVal = 0;
7845 DWORD dwSize = sizeof(numVal);
7846
7847 err = RegQueryValueEx(hKey, entry, NULL, &dwType, (LPBYTE)&numVal, &dwSize);
7848 RegCloseKey(hKey);
7849 if (err != ERROR_SUCCESS)
7850 return 0;
7851 return numVal;
7852}
7853
7854uint64 ReadRegistryQWORD(const char* key, const char* entry) {
7855 HKEY hKeyRoot, hKey;
7856 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7857
7858 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
7859 if (err != ERROR_SUCCESS)
7860 return 0;
7861
7862 DWORD dwType = REG_QWORD;
7863 uint64 numVal = 0;
7864 DWORD dwSize = sizeof(numVal);
7865
7866 err = RegQueryValueEx(hKey, entry, NULL, &dwType, (LPBYTE)&numVal, &dwSize);
7867 RegCloseKey(hKey);
7868 if (err != ERROR_SUCCESS)
7869 return 0;
7870 return numVal;
7871}
7872
7873std::string ReadRegistryString(const char* key, const char* entry) {
7874 HKEY hKeyRoot, hKey;
7875 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7876
7877 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
7878 if (err != ERROR_SUCCESS) {
7879 return "";
7880 }
7881
7882 DWORD dwType = REG_SZ;
7883 DWORD dwSize = 4096;
7884 char* lszValue = new char[dwSize];
7885
7886 err = RegQueryValueEx(hKey, entry, NULL, &dwType, (LPBYTE)lszValue, &dwSize);
7887 RegCloseKey(hKey);
7888 if (err != ERROR_SUCCESS) {
7889 delete[] lszValue;
7890 return "";
7891 }
7892
7893 std::string val = lszValue;
7894 delete[] lszValue;
7895 return val;
7896}
7897
7898bool WriteRegistryDWORD(const char* key, const char* entry, uint32 value) {
7899 DWORD dwDisposition;
7900 HKEY hKeyRoot, hKey;
7901 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7902
7903 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);
7904 if (err != ERROR_SUCCESS) {
7905 err = RegCreateKeyEx(hKeyRoot, keySubName.c_str(), 0, NULL, 0, KEY_WRITE | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition);
7906 if (err != ERROR_SUCCESS)
7907 return false;
7908 }
7909
7910 DWORD dwType = REG_DWORD;
7911 err = RegSetValueEx(hKey, entry, 0, dwType, (const BYTE*)&value, sizeof(value));
7912 RegCloseKey(hKey);
7913 return (err == ERROR_SUCCESS);
7914}
7915
7916bool WriteRegistryQWORD(const char* key, const char* entry, uint64 value) {
7917 DWORD dwDisposition;
7918 HKEY hKeyRoot, hKey;
7919 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7920
7921 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);
7922 if (err != ERROR_SUCCESS) {
7923 err = RegCreateKeyEx(hKeyRoot, keySubName.c_str(), 0, NULL, 0, KEY_WRITE | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition);
7924 if (err != ERROR_SUCCESS)
7925 return false;
7926 }
7927
7928 DWORD dwType = REG_QWORD;
7929 err = RegSetValueEx(hKey, entry, 0, dwType, (const BYTE*)&value, sizeof(value));
7930 RegCloseKey(hKey);
7931 return (err == ERROR_SUCCESS);
7932}
7933
7934bool WriteRegistryString(const char* key, const char* entry, const char* value) {
7935 DWORD dwDisposition;
7936 HKEY hKeyRoot, hKey;
7937 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7938
7939 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_WRITE | KEY_WOW64_64KEY, &hKey);
7940 if (err != ERROR_SUCCESS) {
7941 err = RegCreateKeyEx(hKeyRoot, keySubName.c_str(), 0, NULL, 0, KEY_WRITE | KEY_WOW64_64KEY, NULL, &hKey, &dwDisposition);
7942 if (err != ERROR_SUCCESS)
7943 return false;
7944 }
7945
7946 DWORD dwType = REG_SZ;
7947 DWORD dwSize = 4096;
7948
7949 err = RegSetValueEx(hKey, entry, 0, dwType, (LPBYTE)value, (DWORD)(strlen(value) + 1));
7950 RegCloseKey(hKey);
7951 return (err == ERROR_SUCCESS);
7952}
7953
7954bool DeleteRegistryEntry(const char* key, const char* entry) {
7955 HKEY hKeyRoot, hKey;
7956 std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7957
7958 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_SET_VALUE | KEY_WOW64_64KEY, &hKey);
7959 if (err != ERROR_SUCCESS)
7960 return false;
7961
7962 //std::string keySubName = GetRegistryKeyInfo(key, hKeyRoot);
7963 err = RegDeleteValue(hKey, entry);
7964 return (err == ERROR_SUCCESS);
7965}
7966
7967bool DeleteRegistryKey(const char* entry) {
7968 // https://msdn.microsoft.com/en-us/library/aa379776(VS.85).aspx
7969
7970 HKEY hKeyRoot;
7971 std::string keySubName = GetRegistryKeyInfo(entry, hKeyRoot);
7972 uint32 err = RegDeleteKeyEx(hKeyRoot, keySubName.c_str(), KEY_WOW64_64KEY, 0);
7973 return (err == ERROR_SUCCESS);
7974}
7975
7976bool DeleteRegistryTree(const char* root, const char* key) {
7977 if (!key || !strlen(key))
7978 return false;
7979
7980 HKEY hKey;
7981 HKEY hKeyRoot;
7982 std::string keySubName = GetRegistryKeyInfo(root, hKeyRoot);
7983 uint32 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey);
7984 if (err != ERROR_SUCCESS)
7985 return false;
7986
7987 err = RegDeleteTree(hKey, key);
7988 return (err == ERROR_SUCCESS);
7989}
7990
7991//bool CopyRegistryKey(const char* key, const char* newName) {
7992//}
7993
7994bool CopyRegistryTree(const char* entry, const char* newName) {
7995 // https://msdn.microsoft.com/en-us/library/aa379768(VS.85).aspx
7996
7997 // access 64 or 32-bit registry: https://msdn.microsoft.com/en-us/library/aa384129(v=vs.85).aspx
7998 // we always use the 64-bit registry here
7999
8000 DWORD dwDisposition;
8001 HKEY hKey;
8002 HKEY hKeyRoot;
8003 HKEY hKeyNew;
8004 HKEY hKeyNewRoot;
8005 uint32 err;
8006
8007 std::string keySubName = GetRegistryKeyInfo(entry, hKeyRoot);
8008 std::string keySubNewName = GetRegistryKeyInfo(newName, hKeyNewRoot);
8009
8010 err = RegOpenKeyEx(hKeyRoot, keySubName.c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
8011 if (err != ERROR_SUCCESS)
8012 return false;
8013
8014 err = RegCreateKeyEx(hKeyNewRoot, keySubNewName.c_str(), 0, NULL, 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, NULL, &hKeyNew, &dwDisposition);
8015 if (err != ERROR_SUCCESS) {
8016 RegCloseKey(hKey);
8017 return false;
8018 }
8019
8020 err = RegCopyTree(hKey, NULL, hKeyNew);
8021
8022 RegCloseKey(hKey);
8023 RegCloseKey(hKeyNew);
8024
8025 if (err != ERROR_SUCCESS) {
8026 RegDeleteKeyEx(hKeyNewRoot, keySubNewName.c_str(), KEY_WOW64_64KEY, 0);
8027 return false;
8028 }
8029 return true;
8030}
8031
8032//bool RenameRegistryKey(const char* key, const char* newName) {
8033// if (!CopyRegistryKey(key, newName))
8034// return false;
8035// if (!DeleteRegistryKey(key)) {
8036// CopyRegistryKey(newName, key);
8037// return false;
8038// }
8039// return true;
8040//}
8041
8042//bool RenameRegistryTree(const char* entry, const char* newName) {
8043 //if (!CopyRegistryTree(entry, newName))
8044 // return false;
8045 //if (!DeleteRegistryTree(entry)) {
8046 // CopyRegistryTree(newName, entry);
8047 // return false;
8048 //}
8049// return true;
8050//}
8051
8052std::string GetRegistryKeyInfo(const char* key, HKEY &hKeyRoot) {
8053 std::vector<std::string> path = utils::TextListSplit(key, "\\");
8054 if (!path.size()) path = utils::TextListSplit(key, "/");
8055 if (path.size() < 2) return false;
8056 if (stristr(path.at(0).c_str(), "HKEY_CLASSES_ROOT"))
8057 hKeyRoot = HKEY_CLASSES_ROOT;
8058 else if (stristr(path.at(0).c_str(), "HKEY_CURRENT_USER"))
8059 hKeyRoot = HKEY_CURRENT_USER;
8060 else if (stristr(path.at(0).c_str(), "HKEY_LOCAL_MACHINE"))
8061 hKeyRoot = HKEY_LOCAL_MACHINE;
8062 else if (stristr(path.at(0).c_str(), "HKEY_USERS"))
8063 hKeyRoot = HKEY_USERS;
8064 return utils::TextJoin(path, "\\", 1, (DWORD)(path.size() - 1));
8065}
8066
8067std::string GetRegistryParentKeyInfo(const char* key, HKEY &hKeyRoot) {
8068 std::vector<std::string> path = utils::TextListSplit(key, "\\");
8069 if (!path.size()) path = utils::TextListSplit(key, "/");
8070 if (path.size() < 2) return false;
8071 if (stristr(path.at(0).c_str(), "HKEY_CLASSES_ROOT"))
8072 hKeyRoot = HKEY_CLASSES_ROOT;
8073 else if (stristr(path.at(0).c_str(), "HKEY_CURRENT_USER"))
8074 hKeyRoot = HKEY_CURRENT_USER;
8075 else if (stristr(path.at(0).c_str(), "HKEY_LOCAL_MACHINE"))
8076 hKeyRoot = HKEY_LOCAL_MACHINE;
8077 else if (stristr(path.at(0).c_str(), "HKEY_USERS"))
8078 hKeyRoot = HKEY_USERS;
8079 return utils::TextJoin(path, "\\", 1, (DWORD)(path.size() - 2));
8080}
8081
8082
8083#else // WINDOWS
8084 int32 ReadRegistryDWORD(const char* key) { return 0; }
8085 int64 ReadRegistryQWORD(const char* key) { return 0; }
8086 std::string ReadRegistryString(const char* key) { return ""; }
8087 bool WriteRegistryDWORD(const char* key, int32 value) { return false; }
8088 bool WriteRegistryQWORD(const char* key, int64 value) { return false; }
8089 bool WriteRegistryString(const char* key, const char* value) { return false; }
8090 bool DeleteRegistryKey(const char* key) { return false; }
8091 bool DeleteRegistryTree(const char* key) { return false; }
8092 //bool CopyRegistryKey(const char* key, const char* newName) { return false; }
8093 bool CopyRegistryTree(const char* entry, const char* newName) { return false; }
8094 //bool RenameRegistryKey(const char* key, const char* newName) { return false; }
8095 bool RenameRegistryTree(const char* entry, const char* newName) { return false; }
8096#endif // WINDOWS
8097
8098
8099
8100} // namespace utils
8101
8102// Adapters so the utils:: free-function tests can be registered as bool() pointers.
8103static bool Test_Utils() { return utils::UnitTest_Utils(); }
8104static bool Test_Timer() { return utils::UnitTest_Timer(); }
8105
8108 "Bitfield slot allocation: SetBit/SetBitN, first-free and last-occupied searches", "util");
8110 "Timer scheduling and trigger delivery via waitForTimer", "util");
8111}
8112
8113} // namespace cmlabs
8114
8115
HTML/URL helper utilities: entity encoding/decoding, MIME type lookup and URL component parsing.
#define PROC_ERROR
Error state.
Definition MemoryMaps.h:153
Object type ids used to tag and verify every binary structure in CMSDK memory.
#define CONSTCHARID
Definition ObjectIDs.h:38
#define CHARDATAID
Definition ObjectIDs.h:40
#define CONSTCHARINFOID
Definition ObjectIDs.h:43
#define DOUBLEID
Definition ObjectIDs.h:42
#define DATAMESSAGEINFOID
Definition ObjectIDs.h:69
#define LOGENTRYID
Definition ObjectIDs.h:55
#define DATAMESSAGEID
Definition ObjectIDs.h:75
#define INTID
Definition ObjectIDs.h:41
#define CHARDATAINFOID
Definition ObjectIDs.h:44
#define TIMEID
Definition ObjectIDs.h:39
#define strnicmp
Definition Standard.h:188
Process-wide thread registry and lifecycle manager: the concurrency core of CMSDK.
#define BITOCCUPIED
Definition Types.h:34
#define BITFREE
Definition Types.h:33
#define MAXVALUINT16
Definition Types.h:85
#define MAXVALUINT32
Definition Types.h:87
Small, dependency-free unit test harness used by all CMSDK object tests.
#define poly
Definition Utils.cpp:6771
Cross-platform utility toolbox for CMSDK: threading, synchronization, shared memory,...
#define LOGPRINT
Definition Utils.h:210
#define WINSHMEMSPACE
Definition Utils.h:82
#define SD_BOTH
Definition Utils.h:151
#define MAXKEYNAMELEN
Definition Utils.h:85
#define OSCPU_IA64
Definition Utils.h:157
#define LOG_SYSTEM
Definition Utils.h:197
#define OSCPU_X86
Definition Utils.h:155
#define OSCPU_UNKNOWN
Definition Utils.h:154
#define LOGDEBUG
Definition Utils.h:211
#define EVENTMEMSIZE
Definition Utils.h:143
#define INVALID_SOCKET
Definition Utils.h:137
#define GetCurrentDirEx
Definition Utils.h:79
#define THREAD_STATS_ADHOC
Definition Utils.h:102
#define closesocket(X)
Definition Utils.h:138
#define THREAD_STATS_OFF
Definition Utils.h:100
#define SEMAPHOREMEMSIZE
Definition Utils.h:144
#define stricmp
Definition Utils.h:132
#define SOCKET_ERROR
Definition Utils.h:136
#define LogPrint
Definition Utils.h:313
#define MAXFILENAMELEN
Definition Utils.h:89
THREAD_RET(* THREAD_FUNCTION)(void *)
Definition Utils.h:128
#define LOG_NETWORK
Definition Utils.h:198
#define THREAD_STATS_AUTO
Definition Utils.h:101
#define MUTEXMEMSIZE
Definition Utils.h:142
#define ThreadHandle
Definition Utils.h:125
#define OSCPU_AMD64
Definition Utils.h:156
#define MAXSHMEMNAMELEN
Definition Utils.h:90
struct sockaddr SOCKADDR
Definition Utils.h:135
#define LOG_MAXCOUNT
Definition Utils.h:208
#define SOCKET
Definition Utils.h:134
RAII guard whose single static instance triggers global utility cleanup at program exit.
Definition Utils.h:178
CleanShutdown()
Default constructor; no side effects.
Definition Utils.cpp:35
~CleanShutdown()
Destroys all lazily-created global utility maps via ClearUtilsMaps().
Definition Utils.cpp:39
Callback interface for receiving log entries produced through LogSystem.
Definition Utils.h:256
Process-wide singleton logging hub with per-topic verbosity/debug levels.
Definition Utils.h:272
char * logfile
Definition Utils.h:309
static bool SetLogFileOutput(const char *logfile, bool printOut=true)
Direct log output to a file.
Definition Utils.cpp:275
static bool SetLogReceiver(LogReceiver *rec)
Register a receiver that gets every accepted LogEntry.
Definition Utils.cpp:169
bool printToStdOut
Definition Utils.h:310
static bool LogSystemPrint(uint32 source, uint8 subject, uint8 level, const char *formatstring,...)
printf-style informational logging (usually invoked via the LogPrint macro).
Definition Utils.cpp:306
static bool LogSystemDebug(uint32 source, uint8 subject, uint8 level, const char *formatstring,...)
printf-style debug logging (usually invoked via the LogDebug macro); same parameters as LogSystemPrin...
Definition Utils.cpp:354
static LogSystem * LogSingleton
Lazily-created global instance used by all static functions.
Definition Utils.h:278
static bool SetLogLevelDebug(uint8 level)
Set the debug level threshold for all topics.
Definition Utils.cpp:180
static bool SetLogLevelVerbose(uint8 level)
Set the verbose (print) level threshold for all topics.
Definition Utils.cpp:204
static bool Shutdown()
Terminate all managed threads, then destroy the singleton.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
Singleton snapshot of the parsed process command line (set via SetCommandLine()).
Definition Utils.h:1257
static CommandLineInfo * CommandLineInfoSingleton
Definition Utils.h:1259
Auto-reset notification event (condition variable style), optionally named for cross-process use.
Definition Utils.h:533
pthread_cond_t * event
Definition Utils.h:552
bool waitNext()
Block until the next signal() occurs.
Definition Utils.cpp:1568
Event()
Create an anonymous, process-local event.
Definition Utils.cpp:1485
bool signal()
Wake all threads currently waiting on this event.
Definition Utils.cpp:1592
pthread_mutex_t * mutex
Definition Utils.h:553
Thin RAII wrapper around a dynamically loaded library (LoadLibrary / dlopen).
Definition Utils.h:1297
LibraryFunction getFunction(const char *funcName)
Resolve an exported function.
Definition Utils.cpp:4457
static std::string patchLibraryFilename(const char *filename, const char *path=NULL)
Normalize a library name into a platform filename (adds lib prefix / .dll, .so, .dylib suffix and opt...
Definition Utils.cpp:4339
bool load(const char *filename)
Load a library.
Definition Utils.cpp:4369
Recursive mutual-exclusion lock, optionally named for cross-process use.
Definition Utils.h:463
Mutex()
Create an anonymous, process-local mutex.
Definition Utils.cpp:948
bool leave()
Release the mutex.
Definition Utils.cpp:1194
bool enter()
Block until the mutex is acquired.
Definition Utils.cpp:1059
pthread_mutex_t * mutex
Definition Utils.h:492
Counting semaphore, optionally named for cross-process use.
Definition Utils.h:502
Semaphore(uint32 maxCount=100)
Create an anonymous semaphore.
Definition Utils.cpp:1260
bool signal()
Increment (release) the semaphore, waking one waiter.
Definition Utils.cpp:1434
bool wait()
Block until the semaphore can be decremented.
Definition Utils.cpp:1365
Multiplexing timer: schedule many periodic timers and consume their expiries from one queue.
Definition Utils.h:640
bool addTimer(uint32 id, uint32 interval, uint64 start=0, uint64 end=0)
Register a periodic timer.
Definition Utils.cpp:1662
static std::map< uint32, Timer * > * timers
Global registry mapping globalID to live Timer instances, used by the OS callbacks.
Definition Utils.h:643
bool triggerTimer(uint32 id)
Manually inject an expiry for timer id, as if it had fired now.
Definition Utils.cpp:1786
bool waitForTimer(uint32 timeout, uint32 &id, uint64 &time)
Wait for the next expiry of any registered timer.
Definition Utils.cpp:1808
bool removeTimer(uint32 id)
Unregister a timer and cancel its OS timer.
Definition Utils.cpp:1759
uint64 FTime2PsyTime(uint64 t)
Convert an ftime-style value (ms since Unix epoch) to a PsyTime µs timestamp.
Definition PsyTime.cpp:758
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
std::string PrintTimeNowString(bool local=true, bool us=true, bool ms=true)
Format GetTimeNow().
Definition PsyTime.cpp:672
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
Definition PsyTime.cpp:35
bool UnitTest_Utils()
Aggregate self test for miscellaneous utils functionality.
Definition Utils.cpp:1921
int64 AtomicDecrement64(int64 volatile &v)
Atomically decrement a 64-bit value.
Definition Utils.cpp:2792
bool SeedRandomValues(uint32 seedvalue=0)
Seed the pseudo-random generator.
Definition Utils.cpp:7672
int GetLastOSErrorNumber()
Get the last OS error number (errno / GetLastError()).
Definition Utils.cpp:5242
std::string GetLastOSErrorMessage()
Get the last OS error as human-readable text.
Definition Utils.cpp:5252
uint32 NewProcess(const char *cmdline, const char *initdir=NULL, const char *title=NULL, int16 x=-1, int16 y=-1, int16 w=-1, int16 h=-1)
Launch a detached child process.
Definition Utils.cpp:3922
std::vector< std::string > TextListBreakLines(const char *text, uint32 maxLineLength=80)
Word-wrap text into lines no longer than maxLineLength.
Definition Utils.cpp:6352
bool SetSharedSystemInstance(uint32 inst)
Set the instance number used to namespace shared OS objects, allowing several independent CMSDK syste...
Definition Utils.cpp:938
int8 CompareFloats(float64 a, float64 b)
Compare two doubles with epsilon tolerance.
Definition Utils.cpp:6760
uint32 * GetLocalIPAddresses(uint32 &count)
List all local IPv4 addresses.
Definition Utils.cpp:5654
uint32 GetThreadStatColAbility()
Report this platform's capability for per-thread CPU statistics collection.
Definition Utils.cpp:3119
std::string EncodeJSON(std::string str)
Escape text for embedding as a JSON string value.
Definition Utils.cpp:7596
unsigned char * Ascii2UTF16LE(const char *ascii, uint32 len, uint32 &size)
Convert 8-bit ASCII text to UTF-16LE (used for Windows wide APIs and some protocols).
Definition Utils.cpp:5087
uint64 GetProcessMemoryUsage()
Current resident memory usage of this process.
Definition Utils.cpp:4557
bool WaitForThreadToFinish(ThreadHandle hThread, uint32 timeoutMS=0)
Join a thread.
Definition Utils.cpp:2943
char ** SplitCommandline(const char *cmdline, int &argc)
Split a command line into a malloc'ed argv array.
Definition Utils.cpp:6237
uint64 ReadRegistryQWORD(const char *key, const char *entry)
Read a 64-bit registry value.
bool SignalSemaphore(const char *name)
Signal a named global semaphore.
Definition Utils.cpp:804
std::string GetCommandLineArg(uint16 n)
Get the n-th positional command line item.
Definition Utils.cpp:4298
bool GetThreadPriority(ThreadHandle hThread, uint16 priority)
Query a thread's scheduling priority.
Definition Utils.cpp:3511
bool CreateADir(const char *dirname)
Create a directory (parents included where supported).
Definition Utils.cpp:7053
std::string BytifyRates(double val1, double val2)
Format two byte rates as "x / y" with matching units.
Definition Utils.cpp:7819
bool CopyAFile(const char *oldfilename, const char *newfilename, bool force=false)
Copy a file.
Definition Utils.cpp:7005
bool DeleteFilesInADir(const char *dirname, bool force)
Delete all files inside a directory, leaving the directory itself.
Definition Utils.cpp:7146
uint32 GetCommandLineArgCount()
Number of positional command line items (excluding the executable).
Definition Utils.cpp:4292
std::pair< std::string, Mutex * > SharedMemoryMutexMapPair
Definition Utils.h:589
int FromOSPriority(int pri)
Map a native OS priority back to the CMSDK priority scale.
Definition Utils.cpp:3601
uint16 GetCPUArchitecture()
CPU architecture id.
Definition Utils.cpp:4648
bool EndProcess(uint32 proc)
Forcibly terminate a child process.
Definition Utils.cpp:4107
#define PROC_RUNNING
Definition Utils.h:1189
std::pair< std::string, Semaphore * > SharedMemorySemaphoreMapPair
Definition Utils.h:592
std::string ReadAFileString(std::string filename)
Read an entire file into a std::string.
Definition Utils.cpp:6797
static Mutex * SharedMemorySemaphoreMapMutex
Definition Utils.h:590
bool GetLastOccupiedBitLoc(const char *bitfield, uint32 bytesize, uint32 &loc)
Find the highest set (occupied) bit.
Definition Utils.cpp:2689
const char * laststrstr(const char *str1, const char *str2)
Find the last occurrence of str2 in str1.
Definition Utils.cpp:7183
char * StringFormatVA(uint32 &size, const char *format, va_list args)
va_list core used by the other StringFormat overloads.
Definition Utils.cpp:6566
#define CHECKNETWORKINIT
Definition Utils.h:1380
std::pair< std::string, Event * > SharedMemoryEventMapPair
Definition Utils.h:595
bool DestroyEvent(const char *name)
Destroy a named global event.
Definition Utils.cpp:917
bool WaitForSemaphore(const char *name, uint32 ms, bool autocreate=true)
Wait on a named global semaphore.
Definition Utils.cpp:765
static SharedMemoryFileHandleMapType * SharedMemoryFileHandleMap
Definition Utils.h:395
bool TextStartsWith(const char *str, const char *start, bool caseSensitive=true)
Test whether str starts with start.
Definition Utils.cpp:7240
std::string TextUppercase(const char *text)
Convert to upper case (ASCII/current locale).
Definition Utils.cpp:6107
int CRC32(const char *addr, uint32 length, int32 crc=0)
Compute (or continue) a CRC-32 checksum.
Definition Utils.cpp:6779
bool Sleep(uint32 ms)
Suspend the calling thread.
Definition Utils.cpp:2802
bool WaitForSocketReadability(SOCKET s, int32 timeout)
Wait until a socket has data to read.
Definition Utils.cpp:5300
uint64 * GetLocalMACAddresses(uint32 &count)
List all local MAC addresses.
Definition Utils.cpp:5580
bool SetThreadPriority(ThreadHandle hThread, uint16 priority)
Set a thread's scheduling priority.
Definition Utils.cpp:3534
bool GetProcAndOSCPUUsage(double &procPercentUse, double &osPercentUse, uint64 &prevOSTicks, uint64 &prevOSIdleTicks, uint64 &prevProcTicks)
Sample CPU usage of this process and of the whole OS since the previous call.
Definition Utils.cpp:3336
bool PauseThread(ThreadHandle hThread)
Suspend a thread's execution.
Definition Utils.cpp:3023
static std::map< std::string, Event * > * SharedMemoryEventMap
Definition Utils.h:594
bool MoveConsoleWindow(int32 x=-1, int32 y=-1, int32 w=-1, int32 h=-1)
Move/resize the console window.
Definition Utils.cpp:3683
const char * GetSystemArchitecture()
Architecture name string, e.g.
Definition Utils.cpp:4796
std::string TextTrim(const char *text)
Strip leading and trailing whitespace.
Definition Utils.cpp:6169
bool IsThreadRunning(ThreadHandle hThread)
Check whether a thread is still alive.
Definition Utils.cpp:3093
bool CreateThread(THREAD_FUNCTION func, void *args, ThreadHandle &thread, uint32 &osID)
Start a new OS thread.
Definition Utils.cpp:2868
int32 AtomicDecrement32(int32 volatile &v)
Atomically decrement a 32-bit value.
Definition Utils.cpp:2782
std::string GetCommandLinePath()
Get the directory portion of the executable path.
Definition Utils.cpp:4252
static std::map< uint32, DrumBeatInfo > * DrumBeatMap
Definition Utils.h:441
#define WSAEWOULDBLOCK
Definition Utils.h:1381
bool HasCommandLineArg(const char *key, std::string &value)
Test for a 'key=value' argument without mutating the argument map.
Definition Utils.cpp:4310
bool SignalThread(ThreadHandle hThread, int32 signal)
Send a signal to a thread (POSIX pthread_kill; limited emulation on Windows).
Definition Utils.cpp:3625
bool SetSocketBlockingMode(SOCKET s)
Put a socket into blocking mode.
Definition Utils.cpp:5349
uint32 Ascii2Uint32(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 32-bit decimal integer from a substring.
Definition Utils.cpp:7526
uint64 GetCPUSpeed()
Nominal CPU clock speed.
Definition Utils.cpp:4685
wchar_t ** SplitCommandlineW(const char *cmdline, int &argc)
Wide-character variant of SplitCommandline() (for Windows APIs).
Definition Utils.cpp:6257
std::string TextVectorConcat(std::vector< std::string >, const char *sep, bool allowEmpty=true)
Concatenate vector entries with sep.
Definition Utils.cpp:6539
bool AppendToAFile(const char *filename, const char *data, uint32 length, bool binary=false)
Append to a file, creating it if missing.
Definition Utils.cpp:6905
char * OpenSharedMemorySegment(const char *name, uint64 size)
Open and map an existing named shared memory segment.
Definition Utils.cpp:2259
std::string TextIndent(const char *text, const char *indent)
Prefix every line of text with indent.
Definition Utils.cpp:6119
int64 AtomicIncrement64(int64 volatile &v)
Atomically increment a 64-bit value.
Definition Utils.cpp:2772
#define LOCALHOSTIP
Definition Utils.h:1439
uint32 GetSharedSystemInstance()
Get the current shared-system instance number.
Definition Utils.cpp:943
unsigned char Dec2Char(const char *str)
Parse up to three decimal digits into a byte.
Definition Utils.cpp:6752
bool StopDrumBeat(uint32 id)
Stop a running drum beat without destroying it.
Definition Utils.cpp:581
char * GetFileList(const char *dirname, const char *ext, uint32 &count, bool fullpath, uint32 maxNameLen=256)
List files in a directory matching an extension.
Definition Utils.cpp:7293
bool GetNextAvailableLocalPort(uint16 lastPort, uint16 &nextPort)
Find the next free TCP port above lastPort.
Definition Utils.cpp:5910
bool EnterMutex(const char *name, uint32 ms, bool autocreate=true)
Acquire a named global mutex, creating it on first use.
Definition Utils.cpp:649
const char * laststristr(const char *str1, const char *str2)
Case-insensitive laststrstr().
Definition Utils.cpp:7208
bool MoveAFile(const char *oldfilename, const char *newfilename, bool force=false)
Move/rename a file.
Definition Utils.cpp:6957
static Mutex * SharedMemoryMutexMapMutex
Definition Utils.h:587
#define SharedMemoryFileHandleMapType
Definition Utils.h:393
bool CreateDrumBeat(uint32 id, uint32 interval, DrumBeatFunc func, bool autostart=false)
Create a periodic timer ("drum beat") that calls func every interval ms.
Definition Utils.cpp:482
uint32 StringMultiReplace(std::string &text, std::map< std::string, std::string > &map, bool onlyFirst)
Apply many key→value replacements in one pass.
Definition Utils.cpp:6662
std::string PrintProgramTrace(uint32 startLine=0, uint32 endLine=0)
Format the current call stack as printable text.
Definition Utils.cpp:2812
uint8 GetProcessStatus(uint32 proc, int &returncode)
Poll a child started with NewProcess().
Definition Utils.cpp:4049
bool(* DrumBeatFunc)(uint32 id, uint32 count)
Callback invoked on every drum-beat tick.
Definition Utils.h:418
std::vector< std::string > TextListSplit(const char *text, const char *split, bool keepEmpty=true, bool autoTrim=false)
Split text on a separator.
Definition Utils.cpp:6511
bool IsTextNumeric(const char *ascii, uint32 start=0, uint32 end=0)
Test whether a (sub)string is a valid number.
Definition Utils.cpp:7450
static Mutex * SharedMemoryEventMapMutex
Definition Utils.h:593
uint16 GetCPUCount()
Number of logical CPU cores.
Definition Utils.cpp:4629
char * Uint2Ascii(uint64 value, char *result, uint16 size, uint8 base)
Render an unsigned integer as text in an arbitrary base.
Definition Utils.cpp:5063
std::map< std::string, std::string > TextMapSplit(const char *text, const char *outersplit, const char *innersplit)
Split "k=v<sep>k=v..." text into a map (later duplicates overwrite earlier ones).
Definition Utils.cpp:6211
uint64 GetPeakProcessMemoryUsage()
Peak resident memory usage of this process.
Definition Utils.cpp:4589
bool DeleteCommandline(char **argv, int argc)
Free an argv array produced by SplitCommandline().
Definition Utils.cpp:6277
Semaphore * GetSemaphore(const char *name, bool autocreate=true)
Look up (and optionally create) a named semaphore in the global registry.
Definition Utils.cpp:726
uint32 AsciiHex2Uint32(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 32-bit hexadecimal integer from a substring.
Definition Utils.cpp:7536
bool DeleteRegistryKey(const char *key)
Delete a (leaf) registry key.
Definition Utils.cpp:8090
bool GetLocalHostname(char *name, uint32 maxSize)
Local hostname into a caller buffer.
Definition Utils.cpp:5508
std::string TextUnindent(const char *text)
Remove one level of leading indentation from every line.
Definition Utils.cpp:6130
bool GetSystemOSVersion(uint16 &major, uint16 &minor, uint16 &build, char *text, uint16 textSize)
Detailed OS version.
Definition Utils.cpp:4885
uint32 StringScriptReplace(std::string &text, std::string name, std::list< std::map< std::string, std::string > > &list)
Expand a named repeating template block in text once per map in list, substituting each map's keys in...
Definition Utils.cpp:6696
std::string TextJoinXML(std::map< std::string, std::string > &map, const char *innernodeName, const char *outernodeName)
Serialize a map as XML, one innernodeName element per pair inside an outernodeName element.
Definition Utils.cpp:6493
bool SetCommandLine(int argc, char *argv[])
Parse and store the process command line for later retrieval by the Get/HasCommandLine* functions.
Definition Utils.cpp:4205
bool LeaveMutex(const char *name)
Release a named global mutex previously acquired with EnterMutex().
Definition Utils.cpp:689
uint32 StringSingleReplace(std::string &text, std::string key, std::string value, bool onlyFirst)
Replace occurrences of key with value in text.
Definition Utils.cpp:6644
int RunOSCommand(const char *cmdline, const char *initdir, uint32 timeout, std::string &stdoutString, std::string &stderrString)
Run a command synchronously and capture its output.
Definition Utils.cpp:3729
uint64 GetSystemMemorySize()
Total physical RAM installed.
Definition Utils.cpp:4732
char * CreateSharedMemorySegment(const char *name, uint64 size, bool force=false)
Create a named shared memory segment and map it into this process.
Definition Utils.cpp:2156
uint32 ReadRegistryDWORD(const char *key, const char *entry)
Read a 32-bit registry value.
std::string PrintBitFieldString(const char *bitfield, uint32 bytesize, uint32 size, const char *title)
Like GetBitFieldAsString() but prefixed with title and formatted for printing.
Definition Utils.cpp:2733
bool GetLocalMACAddress(uint64 &address)
Get the primary local MAC address.
Definition Utils.cpp:5568
bool WaitForSocketWriteability(SOCKET s, int32 timeout)
Wait until a socket can be written without blocking.
Definition Utils.cpp:5268
FileDetails GetFileDetails(const char *filename)
Stat a file.
Definition Utils.cpp:7364
double RandomValue()
Uniform random double in [0,1).
Definition Utils.cpp:7678
bool GetSocketError(int wsaError, char *errorString, uint16 errorStringMaxSize, bool *isRecoverable)
Translate a socket error code into text and classify it.
Definition Utils.cpp:5106
std::string GetCommandLineExecutableOnly()
Get just the executable filename without path.
Definition Utils.cpp:4275
#define MALLOC(x)
Definition Utils.h:1440
std::string GetBitFieldAsString(const char *bitfield, uint32 bytesize, uint32 size)
Render the first size bits as a '0'/'1' string, for debugging.
Definition Utils.cpp:2714
uint8 WaitForProcess(uint32 proc, uint32 timeout, int &returncode)
Wait for a child to exit.
Definition Utils.cpp:4139
std::multimap< std::string, std::string > TextMultiMapSplit(const char *text, const char *outersplit, const char *innersplit)
Split "k=v<sep>k=v..." text into a multimap (duplicate keys preserved).
Definition Utils.cpp:6184
uint32 GetLocalProcessID()
Get the OS process id of the current process.
Definition Utils.cpp:3720
bool EndDrumBeat(uint32 id)
Destroy a drum beat and release its OS timer.
Definition Utils.cpp:614
bool GetLocalIPAddress(uint32 &address)
Get the primary local IPv4 address.
Definition Utils.cpp:5622
bool DestroySemaphore(const char *name)
Destroy a named global semaphore.
Definition Utils.cpp:836
bool LookupHostname(uint32 address, char *name, uint32 maxSize)
Reverse-resolve an IPv4 address to a hostname.
Definition Utils.cpp:5440
char * TextSubstringCopy(const char *ascii, uint32 start, uint32 end)
Copy the substring [start,end) into a new NUL-terminated buffer.
Definition Utils.cpp:7431
bool CloseSharedMemorySegment(char *data, uint64 size)
Unmap a segment previously created/opened here.
Definition Utils.cpp:2374
bool TerminateThread(ThreadHandle hThread)
Forcibly kill a thread.
Definition Utils.cpp:2993
bool LookupIPAddress(const char *name, uint32 &address)
Resolve a hostname to an IPv4 address.
Definition Utils.cpp:5361
bool GetFirstFreeBitLocN(const char *bitfield, uint32 bytesize, uint32 num, uint32 &loc)
Find the first run of num consecutive 0 bits.
Definition Utils.cpp:2468
bool GetCurrentThreadUniqueID(uint32 &tid)
Get a process-unique id for the calling thread.
Definition Utils.cpp:3043
int32 AtomicIncrement32(int32 volatile &v)
Atomically increment a 32-bit value.
Definition Utils.cpp:2762
bool GetDesktopSize(uint32 &width, uint32 &height)
Get the primary desktop resolution.
Definition Utils.cpp:3641
char * Int2Ascii(int64 value, char *result, uint16 size, uint8 base)
Render a signed integer as text in an arbitrary base.
Definition Utils.cpp:5036
std::string GetLocalHostnameString()
Local hostname as std::string.
Definition Utils.cpp:5496
bool CheckForThreadFinished(ThreadHandle hThread)
Non-blocking check whether a thread has terminated.
Definition Utils.cpp:2914
bool DestroyMutex(const char *name)
Destroy a named global mutex and remove it from the registry.
Definition Utils.cpp:702
int32 Ascii2Int32(const char *ascii, uint32 start=0, uint32 end=0)
Parse a signed 32-bit decimal integer from a substring.
Definition Utils.cpp:7516
bool DoesAFileExist(const char *filename)
Test whether a regular file exists.
Definition Utils.cpp:7359
NetworkInterfaces * GetLocalInterfaces(uint32 &count)
Enumerate local network interfaces with address, MAC and names.
Definition Utils.cpp:5764
bool ContinueThread(ThreadHandle hThread)
Resume a thread paused with PauseThread().
Definition Utils.cpp:3032
std::string TextTrimQuotes(const char *text)
Strip a single pair of surrounding quotes if present.
Definition Utils.cpp:6151
#define PROC_TERMINATED
Definition Utils.h:1187
const char * stristr(const char *str, const char *substr, uint32 len=0)
Case-insensitive strstr.
Definition Utils.cpp:6035
std::list< std::string > GetProgramTrace()
Capture the current call stack.
Definition Utils.cpp:2827
unsigned char Hex2Char(const char *str)
Parse two hex digits into a byte.
Definition Utils.cpp:6744
uint64 hton64(const uint64_t *input)
Convert a 64-bit value from host to network byte order.
bool DeleteAFile(const char *filename, bool force)
Delete a file.
Definition Utils.cpp:6933
bool ChangeAFileAttr(const char *filename, bool read, bool write)
Change read/write permission attributes of a file.
Definition Utils.cpp:6937
static uint16 SharedSystemInstance
Definition Utils.h:397
static void TimerCallback(int sig, siginfo_t *siginfo, void *context)
POSIX signal-based timer callback trampoline (SIGEV_SIGNAL); routes the expiry into the owning Timer'...
Definition Utils.cpp:1844
void PrintBinary(void *p, uint32 size, bool asInt, const char *title)
Hex/decimal dump a memory region to stdout for debugging.
Definition Utils.cpp:6000
static std::map< std::string, Mutex * > * SharedMemoryMutexMap
Definition Utils.h:588
std::string BytifySize(double val)
Format a byte count with binary units, e.g.
Definition Utils.cpp:7724
bool GetFirstFreeBitLoc(const char *bitfield, uint32 bytesize, uint32 &loc)
Find the first 0 (free) bit.
Definition Utils.cpp:2445
std::string GetCommandLineExecutable()
Get the full executable path as invoked.
Definition Utils.cpp:4269
bool StringFormatInto(char *dst, uint32 maxsize, const char *format,...)
printf into a caller-supplied buffer with truncation.
Definition Utils.cpp:6596
std::vector< std::string > TextListSplitLines(const char *text, bool keepEmpty=true, bool autoTrim=false)
Split text into lines, handling both \n and \r\n.
Definition Utils.cpp:6334
bool WriteAFile(const char *filename, const char *data, uint32 length, bool binary=false)
Write (create/overwrite) a file.
Definition Utils.cpp:6877
std::string GetCurrentDir()
Current working directory.
Definition Utils.cpp:7280
bool SignalEvent(const char *name)
Signal a named global event.
Definition Utils.cpp:904
std::string GetCommandLine()
Get the full original command line as one string.
Definition Utils.cpp:4246
bool GetCPUTicks(ThreadHandle hThread, uint64 &ticks)
Get accumulated CPU time of a specific thread.
Definition Utils.cpp:3131
bool GetNextLineEnd(const char *str, uint32 size, uint32 &len, uint32 &crSize)
Find the end of the current line.
Definition Utils.cpp:6074
std::string ReadRegistryString(const char *key, const char *entry)
Read a string registry value.
std::vector< std::string > TextCommandlineSplit(const char *cmdline)
Split a command line into arguments, honouring quoting rules.
Definition Utils.cpp:6284
bool GetBit(uint32 loc, const char *bitfield, uint32 bytesize, bit &val)
Read bit loc.
Definition Utils.cpp:2664
uint64 ntoh64(const uint64 *input)
Convert a 64-bit value from network to host byte order.
Definition Utils.cpp:2414
bool DoesADirExist(const char *dirname)
Test whether a directory exists.
Definition Utils.cpp:7354
bool GetProcessCPUTicks(uint64 &ticks)
Get accumulated CPU time of the current process.
Definition Utils.cpp:3289
bool DeleteRegistryEntry(const char *key, const char *entry)
Delete a single value from a key.
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:6626
int ToOSPriority(int pri)
Map a CMSDK priority value to the platform's native priority scale.
Definition Utils.cpp:3553
static std::map< std::string, Semaphore * > * SharedMemorySemaphoreMap
Definition Utils.h:591
bool SetSocketNonBlockingMode(SOCKET s)
Put a socket into non-blocking mode.
Definition Utils.cpp:5337
bool DeleteADir(const char *dirname, bool force)
Delete a directory (recursively when force).
Definition Utils.cpp:7079
bool SetBitN(uint32 loc, uint32 num, bit value, char *bitfield, uint32 bytesize)
Set num consecutive bits starting at loc to value.
Definition Utils.cpp:2601
bool WriteRegistryQWORD(const char *key, const char *entry, uint64 value)
Write a 64-bit registry value.
bool Reset32BitField(char *bitfield, uint32 bytesize)
Zero the whole bitfield, marking every bit as free.
Definition Utils.cpp:2439
char * ReadAFile(const char *filename, uint32 &length, bool binary=false)
Read an entire file into a new buffer.
Definition Utils.cpp:6818
bool StartDrumBeat(uint32 id)
Start (or resume) a previously created drum beat.
Definition Utils.cpp:535
uint64 Ascii2Uint64(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 64-bit decimal integer from a substring.
Definition Utils.cpp:7480
bool TextEndsWith(const char *str, const char *end, bool caseSensitive=true)
Test whether str ends with end.
Definition Utils.cpp:7233
uint64 AsciiHex2Uint64(const char *ascii, uint32 start=0, uint32 end=0)
Parse an unsigned 64-bit hexadecimal integer (with or without 0x) from a substring.
Definition Utils.cpp:7498
const char * GetFileBasename(const char *filename)
Filename portion of a path.
Definition Utils.cpp:7264
Library * OpenLibrary(const char *libName)
Load a library by name, applying platform filename conventions.
Definition Utils.cpp:4492
bool UnitTest_Timer()
Self test for the Timer class.
Definition Utils.cpp:1857
bool WriteRegistryString(const char *key, const char *entry, const char *value)
Write a string registry value.
#define PROC_TIMEOUT
Definition Utils.h:1190
bool GetSystemMemoryUsage(uint64 &totalRAM, uint64 &freeRAM)
Query total and free physical memory.
Definition Utils.cpp:4755
int64 Ascii2Int64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a signed 64-bit decimal integer from a substring.
Definition Utils.cpp:7462
bool SetBit(uint32 loc, bit value, char *bitfield, uint32 bytesize)
Set bit loc to value.
Definition Utils.cpp:2569
bool GetCurrentThread(ThreadHandle &thread)
Get the handle of the calling thread.
Definition Utils.cpp:3083
bool WriteRegistryDWORD(const char *key, const char *entry, uint32 value)
Write a 32-bit registry value (creates the key when needed).
bool RenameConsoleWindow(const char *name, bool prepend=false)
Set the console window title.
Definition Utils.cpp:3661
std::string TextJoinJSON(std::map< std::string, std::string > &map)
Serialize a map as a JSON object (keys/values escaped).
Definition Utils.cpp:6477
bool UtilsTest()
Run the built-in self test of the utils module.
Definition Utils.cpp:5958
#define PROCBUFSIZE
Definition Utils.h:1204
bool CopyRegistryTree(const char *entry, const char *newName)
Recursively copy a registry subtree.
Definition Utils.cpp:8093
uint32 Calc32BitFieldSize(uint32 bitsize)
Compute the byte size needed for a bitfield of bitsize bits, rounded up to a 32-bit boundary.
Definition Utils.cpp:2435
int(* LibraryFunction)()
Signature of a plain function exported from a dynamically loaded library.
Definition Utils.h:1252
bool DeleteRegistryTree(const char *root, const char *key)
Recursively delete a key and all subkeys.
std::string TextLowercase(const char *text)
Convert to lower case (ASCII/current locale).
Definition Utils.cpp:6113
uint32 TextReplaceCharsInPlace(char *str, uint32 size, char find, char replace)
Replace every occurrence of a character, in place.
Definition Utils.cpp:7172
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:6056
std::string DecodeJSON(std::string str)
Unescape a JSON string value (\" \\ \n \t \uXXXX etc.).
Definition Utils.cpp:7557
std::string TextCapitalise(const char *text)
Capitalise the first letter of text.
Definition Utils.cpp:6093
const char * GetComputerName()
Get this machine's hostname.
Definition Utils.cpp:4510
std::string GetFilePath(const char *filename)
Directory portion of a path.
Definition Utils.cpp:7248
bool GetOSCPUUsage(double &percentUse)
Get the instantaneous total OS CPU usage.
Definition Utils.cpp:3454
const char * GetSystemOSName()
OS name string, e.g.
Definition Utils.cpp:4857
std::string BytifySizes(double val1, double val2)
Format two byte counts as "x / y" with matching units.
Definition Utils.cpp:7761
bool IsLocalIPAddress(const char *addr)
Test whether a textual address refers to this machine (loopback or a local interface).
Definition Utils.cpp:5595
bool GetCurrentThreadOSID(uint32 &tid)
Get the OS-level id of the calling thread (gettid / GetCurrentThreadId).
Definition Utils.cpp:3063
float64 Ascii2Float64(const char *ascii, uint32 start=0, uint32 end=0)
Parse a 64-bit float from a substring (decimal point, not locale dependent).
Definition Utils.cpp:7546
std::string TextJoin(std::vector< std::string > &list, const char *split, uint32 start=0, uint32 count=0)
Join vector elements with split.
Definition Utils.cpp:6430
int64 RandomInt(int64 from=0, int64 to=100)
Uniform random integer in [from,to].
Definition Utils.cpp:7715
std::string BytifyRate(double val)
Format a byte rate, e.g.
Definition Utils.cpp:7807
std::string EncodeHTML(std::string str)
Encode a plain string for safe embedding in HTML (e.g.
Definition HTML.cpp:51
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
char OSLocalHostName[1024]
Definition Utils.cpp:4506
char OSArchitectureName[1024]
Definition Utils.cpp:4507
bool WaitForNextEvent(const char *name, uint32 ms, bool autocreate)
Definition Utils.cpp:865
uint64 GetTime()
Definition Utils.cpp:448
bool RenameRegistryTree(const char *entry, const char *newName)
Definition Utils.cpp:8095
bool CalcTimeout(struct timespec &timeout, uint32 ms)
Definition Utils.cpp:433
char OSName[1024]
Definition Utils.cpp:4508
static void DrumBeatCallback(union sigval p)
Definition Utils.cpp:470
static bool Test_Utils()
Definition Utils.cpp:8103
CleanShutdown CleanShutdownInstance
Definition Utils.cpp:33
struct dirent * readdir(DIR *)
DIR * opendir(const char *)
Definition direntwin.cpp:53
bool ClearUtilsMaps()
Free all lazily-allocated global registries (mutex/semaphore/event/shared-memory maps).
Definition Utils.cpp:49
uint32 CleanShutdownInstanceCount
Definition Utils.cpp:32
void Register_Utils_Tests()
Definition Utils.cpp:8106
int closedir(DIR *)
Definition direntwin.cpp:95
uint32 GetDataTypeID(const char *typeName)
Inverse of GetDataTypeName(): look up the numeric datatype id for a type name.
Definition Utils.cpp:142
static bool Test_Timer()
Definition Utils.cpp:8104
std::string GetDataTypeName(uint32 datatype)
Translate a CMSDK datatype id (e.g.
Definition Utils.cpp:117
Wire/storage layout of one log record: fixed header immediately followed by the message text.
Definition Utils.h:228
uint32 source
Definition Utils.h:232
uint32 size
Definition Utils.h:229
std::string toJSON()
Serialize the entry (header fields + text) as a JSON object string.
Definition Utils.cpp:258
uint8 level
Definition Utils.h:234
uint64 time
Definition Utils.h:231
bool setText(char *text, uint32 len)
Copy len bytes of text into the payload area and update size.
Definition Utils.cpp:247
uint8 subject
Definition Utils.h:233
uint8 type
Definition Utils.h:235
uint32 cid
Definition Utils.h:230
const char * getText(uint32 &len)
Access the text payload stored after the header.
Definition Utils.cpp:240
std::string toXML()
Serialize the entry as an XML fragment.
Definition Utils.cpp:266
char * d_name
Definition direntwin.h:35
Bookkeeping record for one periodic "drum beat" timer.
Definition Utils.h:423
Existence, type, permission and timestamp information for one file, as returned by GetFileDetails().
Definition Utils.h:1666
Description of one local network interface (IPv4 address, MAC and names).
Definition Utils.h:1407
char friendlyName[MAXKEYNAMELEN+1]
Definition Utils.h:1411
char name[MAXKEYNAMELEN+1]
Definition Utils.h:1410
One scheduled entry inside a Timer: id, active window and platform timer handle.
Definition Utils.h:611
A single timer expiry: which timer fired and when.
Definition Utils.h:629
#define TRUE
Definition xml_parser.h:124
#define FALSE
Definition xml_parser.h:121