"Fossies" - the Fresh Open Source Software Archive 
Member "muscle/system/SetupSystem.cpp" (21 Nov 2020, 75065 Bytes) of package /linux/privat/muscle7.62.zip:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "SetupSystem.cpp" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
7.61_vs_7.62.
1 /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc. See the included LICENSE.txt file for details. */
2
3 #include "system/SetupSystem.h"
4 #include "support/Flattenable.h"
5 #include "dataio/SeekableDataIO.h"
6 #include "reflector/SignalHandlerSession.h" // for SetMainReflectServerCatchSignals()
7 #include "system/SystemInfo.h" // for GetBuildFlags()
8 #include "util/ObjectPool.h"
9 #include "util/ByteBuffer.h"
10 #include "util/DebugTimer.h"
11 #include "util/CountedObject.h"
12 #include "util/MiscUtilityFunctions.h" // for PrintHexBytes()
13 #include "util/NetworkUtilityFunctions.h" // for IPAddressAndPort
14 #include "util/String.h"
15
16 #ifdef MUSCLE_ENABLE_SSL
17 # include <openssl/err.h>
18 # include <openssl/ssl.h>
19 # ifndef WIN32
20 # include <pthread.h>
21 # endif
22 #endif
23
24 #ifdef WIN32
25 # if !(defined(__MINGW32__) || defined(__MINGW64__))
26 # pragma comment(lib, "ws2_32.lib")
27 # pragma comment(lib, "winmm.lib")
28 # pragma comment(lib, "iphlpapi.lib")
29 # pragma comment(lib, "version.lib")
30 # endif
31 # include <signal.h>
32 # include <mmsystem.h>
33 #else
34 # if defined(__BEOS__) || defined(__HAIKU__)
35 # include <signal.h>
36 # elif defined(__CYGWIN__)
37 # include <signal.h>
38 # include <sys/select.h>
39 # include <sys/signal.h>
40 # include <sys/times.h>
41 # elif defined(__QNX__)
42 # include <signal.h>
43 # include <sys/times.h>
44 # elif defined(SUN) || defined(__sparc__) || defined(sun386)
45 # include <signal.h>
46 # include <sys/times.h>
47 # include <limits.h>
48 # elif defined(ANDROID)
49 # include <signal.h>
50 # include <sys/times.h>
51 # else
52 # include <signal.h>
53 # include <sys/times.h>
54 # endif
55 #endif
56
57 #if defined(__BORLANDC__)
58 # include <math.h>
59 # include <float.h>
60 #endif
61
62 #if defined(__APPLE__)
63 # include <mach/mach.h>
64 # include <mach/mach_time.h>
65 # include <mach/message.h> // for mach_msg_type_number_t
66 # include <mach/kern_return.h> // for kern_return_t
67 # include <mach/task_info.h>
68 #endif
69
70 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
71 # include "system/AtomicCounter.h"
72 # include "system/ThreadLocalStorage.h"
73 #endif
74
75 #ifdef WIN32
76 # include <psapi.h> // for PROCESS_MEMORY_COUNTERS (yes, this include has to be down here)
77 #endif
78
79 namespace muscle {
80
81 // Commonly used error codes for status_t
82 const status_t B_OUT_OF_MEMORY( "Out of Memory");
83 const status_t B_UNIMPLEMENTED( "Unimplemented");
84 const status_t B_ACCESS_DENIED( "Access Denied");
85 const status_t B_DATA_NOT_FOUND( "Data not Found");
86 const status_t B_FILE_NOT_FOUND( "File not Found");
87 const status_t B_BAD_ARGUMENT( "Bad Argument");
88 const status_t B_BAD_DATA( "Bad Data");
89 const status_t B_BAD_OBJECT( "Bad Object");
90 const status_t B_TIMED_OUT( "Timed Out");
91 const status_t B_IO_ERROR( "I/O Error");
92 const status_t B_LOCK_FAILED( "Lock Failed");
93 const status_t B_TYPE_MISMATCH( "Type Mismatch");
94 const status_t B_ZLIB_ERROR( "ZLib Error");
95 const status_t B_SSL_ERROR( "SSL Error");
96 const status_t B_LOGIC_ERROR( "Logic Error");
97
98 #ifdef MUSCLE_COUNT_STRING_COPY_OPERATIONS
99 uint32 _stringOpCounts[NUM_STRING_OPS] = {0};
100 #endif
101
102 #ifdef MUSCLE_SINGLE_THREAD_ONLY
103 bool _muscleSingleThreadOnly = true;
104 #else
105 bool _muscleSingleThreadOnly = false;
106 #endif
107
108 #ifdef MUSCLE_CATCH_SIGNALS_BY_DEFAULT
109 bool _mainReflectServerCatchSignals = true;
110 #else
111 bool _mainReflectServerCatchSignals = false;
112 #endif
113
114 static Mutex * _muscleLock = NULL;
115 Mutex * GetGlobalMuscleLock() {return _muscleLock;}
116
117 #if defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
118 Mutex * _muscleAtomicMutexes = NULL; // used by DoMutexAtomicIncrement()
119 #endif
120
121 static uint32 _threadSetupCount = 0;
122 #ifndef MUSCLE_SINGLE_THREAD_ONLY
123 static muscle_thread_id _mainThreadID;
124 #endif
125
126 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
127 # ifdef MUSCLE_DEFAULT_RUNTIME_DISABLE_DEADLOCK_FINDER
128 bool _enableDeadlockFinderPrints = false;
129 # else
130 bool _enableDeadlockFinderPrints = true;
131 # endif
132 #endif
133
134 static uint32 _failedMemoryRequestSize = MUSCLE_NO_LIMIT; // start with an obviously-invalid guard value
135 uint32 GetAndClearFailedMemoryRequestSize(); // just to avoid a compiler warning
136 uint32 GetAndClearFailedMemoryRequestSize()
137 {
138 const uint32 ret = _failedMemoryRequestSize; // yes, it's racy. But I'll live with that for now.
139 _failedMemoryRequestSize = MUSCLE_NO_LIMIT;
140 return ret;
141 }
142 void SetFailedMemoryRequestSize(uint32 numBytes); // just to avoid a compiler warning
143 void SetFailedMemoryRequestSize(uint32 numBytes) {_failedMemoryRequestSize = numBytes;}
144
145 static int swap_memcmp(const void * vp1, const void * vp2, uint32 numBytes)
146 {
147 const uint8 * p1 = (const uint8 *) vp1;
148 const uint8 * p2 = (const uint8 *) vp2;
149 for (uint32 i=0; i<numBytes; i++)
150 {
151 const int diff = p2[numBytes-(i+1)]-p1[i];
152 if (diff) return diff;
153 }
154 return 0;
155 }
156
157 // Implemented here so that every program doesn't have to link
158 // in MiscUtilityFunctions.cpp just for this function.
159 void ExitWithoutCleanup(int exitCode)
160 {
161 _exit(exitCode);
162 }
163
164 void Crash()
165 {
166 #ifdef WIN32
167 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
168 #else
169 abort();
170 #endif
171 }
172
173 static void GoInsane(const char * why, const char * why2 = NULL)
174 {
175 printf("SanitySetupSystem: MUSCLE COMPILATION RUNTIME SANITY CHECK FAILED!\n");
176 printf("REASON: %s %s\n", why, why2?why2:"");
177 printf("PLEASE CHECK YOUR COMPILATION SETTINGS! THIS PROGRAM WILL NOW EXIT.\n");
178 fflush(stdout);
179 ExitWithoutCleanup(10);
180 }
181
182 static void CheckOp(uint32 numBytes, const void * orig, const void * swapOne, const void * swapTwo, const void * origOne, const void * origTwo, const char * why)
183 {
184 if ((swapOne)&&(swap_memcmp(orig, swapOne, numBytes))) GoInsane(why, "(swapOne)");
185 if ((swapTwo)&&(swap_memcmp(orig, swapTwo, numBytes))) GoInsane(why, "(swapTwo)");
186 if ((origOne)&&(memcmp(orig, origOne, numBytes))) GoInsane(why, "(origOne)");
187 if ((origTwo)&&(memcmp(orig, origTwo, numBytes))) GoInsane(why, "(origTwo)");
188 }
189
190 #ifndef MUSCLE_AVOID_CPLUSPLUS11
191 template<typename T> void VerifyTypeIsTrivial()
192 {
193 if (std::is_trivial<T>::value == false)
194 {
195 char buf[512];
196 muscleSprintf(buf, "ERROR: Type %s was expected to be trivial, but std::is_trivial() returned false!\n", typeid(T).name());
197 GoInsane(buf);
198 }
199 }
200
201 template<typename T> void VerifyTypeIsNonTrivial()
202 {
203 if (std::is_trivial<T>::value == true)
204 {
205 char buf[512];
206 muscleSprintf(buf, "ERROR: Type %s was expected to be non-trivial, but std::is_trivial() returned true!\n", typeid(T).name());
207 GoInsane(buf);
208 }
209 }
210 #endif
211
212 SanitySetupSystem :: SanitySetupSystem()
213 {
214 // Make sure our data type lengths are as expected
215 if (sizeof(uint8) != 1) GoInsane("sizeof(uint8) != 1");
216 if (sizeof(int8) != 1) GoInsane("sizeof(int8) != 1");
217 if (sizeof(uint16) != 2) GoInsane("sizeof(uint16) != 2");
218 if (sizeof(int16) != 2) GoInsane("sizeof(int16) != 2");
219 if (sizeof(uint32) != 4) GoInsane("sizeof(uint32) != 4");
220 if (sizeof(int32) != 4) GoInsane("sizeof(int32) != 4");
221 if (sizeof(uint64) != 8) GoInsane("sizeof(uint64) != 8");
222 if (sizeof(int64) != 8) GoInsane("sizeof(int64) != 8");
223 if (sizeof(float) != 4) GoInsane("sizeof(float) != 4");
224 if (sizeof(double) != 8) GoInsane("sizeof(double) != 8");
225 if (sizeof(uintptr) != sizeof(void *)) GoInsane("sizeof(uintptr) != sizeof(void *)");
226 if (sizeof(ptrdiff) != sizeof(uintptr)) GoInsane("sizeof(ptrdiff) != sizeof(uintptr)");
227
228 // Make sure our endian-ness info is correct
229 static const uint32 one = 1;
230 const bool testsLittleEndian = (*((const uint8 *) &one) == 1);
231
232 // Make sure our endian-swap macros do what we expect them to
233 #if B_HOST_IS_BENDIAN
234 if (testsLittleEndian) GoInsane("MUSCLE is compiled for a big-endian CPU, but host CPU is little-endian!?");
235 else
236 {
237 {
238 const uint16 orig = 0x1234;
239 const uint16 HtoL = B_HOST_TO_LENDIAN_INT16(orig);
240 const uint16 LtoH = B_LENDIAN_TO_HOST_INT16(orig);
241 const uint16 HtoB = B_HOST_TO_BENDIAN_INT16(orig); // should be a no-op
242 const uint16 BtoH = B_BENDIAN_TO_HOST_INT16(orig); // should be a no-op
243 CheckOp(sizeof(orig), &orig, &HtoL, &LtoH, &HtoB, &BtoH, "16-bit swap macro does not work!");
244 }
245
246 {
247 const uint32 orig = 0x12345678;
248 const uint32 HtoL = B_HOST_TO_LENDIAN_INT32(orig);
249 const uint32 LtoH = B_LENDIAN_TO_HOST_INT32(orig);
250 const uint32 HtoB = B_HOST_TO_BENDIAN_INT32(orig); // should be a no-op
251 const uint32 BtoH = B_BENDIAN_TO_HOST_INT32(orig); // should be a no-op
252 CheckOp(sizeof(orig), &orig, &HtoL, &LtoH, &HtoB, &BtoH, "32-bit swap macro does not work!");
253 }
254
255 {
256 const uint64 orig = (((uint64)0x12345678)<<32)|(((uint64)0x12312312));
257 const uint64 HtoL = B_HOST_TO_LENDIAN_INT64(orig);
258 const uint64 LtoH = B_LENDIAN_TO_HOST_INT64(orig);
259 const uint64 HtoB = B_HOST_TO_BENDIAN_INT64(orig); // should be a no-op
260 const uint64 BtoH = B_BENDIAN_TO_HOST_INT64(orig); // should be a no-op
261 CheckOp(sizeof(orig), &orig, &HtoL, &LtoH, &HtoB, &BtoH, "64-bit swap macro does not work!");
262 }
263
264 {
265 const float orig = -1234567.89012345f;
266 const uint32 HtoL = B_HOST_TO_LENDIAN_IFLOAT(orig);
267 const float LtoH = B_LENDIAN_TO_HOST_IFLOAT(HtoL);
268 const uint32 HtoB = B_HOST_TO_BENDIAN_IFLOAT(orig); // should be a no-op
269 const float BtoH = B_BENDIAN_TO_HOST_IFLOAT(HtoB); // should be a no-op
270 CheckOp(sizeof(orig), &orig, &HtoL, NULL, &HtoB, &BtoH, "float swap macro does not work!");
271 CheckOp(sizeof(orig), &orig, NULL, NULL, &LtoH, NULL, "float swap macro does not work!");
272 }
273
274 {
275 const double orig = ((double)-1234567.89012345) * ((double)987654321.0987654321);
276 const uint64 HtoL = B_HOST_TO_LENDIAN_IDOUBLE(orig);
277 const double LtoH = B_LENDIAN_TO_HOST_IDOUBLE(HtoL);
278 const uint64 HtoB = B_HOST_TO_BENDIAN_IDOUBLE(orig); // should be a no-op
279 const double BtoH = B_BENDIAN_TO_HOST_IDOUBLE(HtoB); // should be a no-op
280 CheckOp(sizeof(orig), &orig, &HtoL, NULL, &HtoB, &BtoH, "double swap macro does not work!");
281 CheckOp(sizeof(orig), &orig, NULL, NULL, &LtoH, NULL, "double swap macro does not work!");
282 }
283 }
284 #else
285 if (testsLittleEndian)
286 {
287 {
288 const uint16 orig = 0x1234;
289 const uint16 HtoB = B_HOST_TO_BENDIAN_INT16(orig);
290 const uint16 BtoH = B_BENDIAN_TO_HOST_INT16(orig);
291 const uint16 HtoL = B_HOST_TO_LENDIAN_INT16(orig); // should be a no-op
292 const uint16 LtoH = B_LENDIAN_TO_HOST_INT16(orig); // should be a no-op
293 CheckOp(sizeof(orig), &orig, &HtoB, &BtoH, &HtoL, &LtoH, "16-bit swap macro does not work!");
294 }
295
296 {
297 const uint32 orig = 0x12345678;
298 const uint32 HtoB = B_HOST_TO_BENDIAN_INT32(orig);
299 const uint32 BtoH = B_BENDIAN_TO_HOST_INT32(orig);
300 const uint32 HtoL = B_HOST_TO_LENDIAN_INT32(orig); // should be a no-op
301 const uint32 LtoH = B_LENDIAN_TO_HOST_INT32(orig); // should be a no-op
302 CheckOp(sizeof(orig), &orig, &HtoB, &BtoH, &HtoL, &LtoH, "32-bit swap macro does not work!");
303 }
304
305 {
306 const uint64 orig = (((uint64)0x12345678)<<32)|(((uint64)0x12312312));
307 const uint64 HtoB = B_HOST_TO_BENDIAN_INT64(orig);
308 const uint64 BtoH = B_BENDIAN_TO_HOST_INT64(orig);
309 const uint64 HtoL = B_HOST_TO_LENDIAN_INT64(orig); // should be a no-op
310 const uint64 LtoH = B_LENDIAN_TO_HOST_INT64(orig); // should be a no-op
311 CheckOp(sizeof(orig), &orig, &HtoB, &BtoH, &HtoL, &LtoH, "64-bit swap macro does not work!");
312 }
313
314 {
315 const float orig = -1234567.89012345f;
316 const uint32 HtoB = B_HOST_TO_BENDIAN_IFLOAT(orig);
317 const float BtoH = B_BENDIAN_TO_HOST_IFLOAT(HtoB);
318 const uint32 HtoL = B_HOST_TO_LENDIAN_IFLOAT(orig); // should be a no-op
319 const float LtoH = B_LENDIAN_TO_HOST_IFLOAT(HtoL); // should be a no-op
320 CheckOp(sizeof(orig), &orig, &HtoB, NULL, &HtoL, &LtoH, "float swap macro does not work!");
321 CheckOp(sizeof(orig), &orig, NULL, NULL, &BtoH, NULL, "float swap macro does not work!");
322 }
323
324 {
325 const double orig = ((double)-1234567.89012345) * ((double)987654321.0987654321);
326 const uint64 HtoB = B_HOST_TO_BENDIAN_IDOUBLE(orig);
327 const double BtoH = B_BENDIAN_TO_HOST_IDOUBLE(HtoB);
328 const uint64 HtoL = B_HOST_TO_LENDIAN_IDOUBLE(orig); // should be a no-op
329 const double LtoH = B_LENDIAN_TO_HOST_IDOUBLE(HtoL); // should be a no-op
330 CheckOp(sizeof(orig), &orig, &HtoB, NULL, &HtoL, &LtoH, "double swap macro does not work!");
331 CheckOp(sizeof(orig), &orig, NULL, NULL, &BtoH, NULL, "double swap macro does not work!");
332 }
333 }
334 else GoInsane("MUSCLE is compiled for a little-endian CPU, but host CPU is big-endian!?");
335 #endif
336
337 #ifndef MUSCLE_AVOID_CPLUSPLUS11
338 // Just because I'm paranoid and want to make sure that std::is_trivial() works the way I think it does --jaf
339 VerifyTypeIsTrivial<int>();
340 VerifyTypeIsTrivial<float>();
341 VerifyTypeIsTrivial<double>();
342 VerifyTypeIsTrivial<int8>();
343 VerifyTypeIsTrivial<int16>();
344 VerifyTypeIsTrivial<int32>();
345 VerifyTypeIsTrivial<int64>();
346 VerifyTypeIsTrivial<const char *>();
347 VerifyTypeIsTrivial<const String *>();
348 VerifyTypeIsTrivial<String *>();
349
350 VerifyTypeIsNonTrivial<Point>();
351 VerifyTypeIsNonTrivial<Rect>();
352 VerifyTypeIsNonTrivial<String>();
353 VerifyTypeIsNonTrivial<ByteBuffer>();
354 VerifyTypeIsNonTrivial<ByteBufferRef>();
355 VerifyTypeIsNonTrivial<DataIO>();
356 VerifyTypeIsNonTrivial<DataIORef>();
357 VerifyTypeIsNonTrivial<Socket>();
358 VerifyTypeIsNonTrivial<ConstSocketRef>();
359 #endif
360
361 // Make sure our pointer-size matches the defined/not-defined state of our MUSCLE_64_BIT_PLATFORM define
362 #ifdef MUSCLE_64_BIT_PLATFORM
363 if (sizeof(void *) != 8) GoInsane("MUSCLE_64_BIT_PLATFORM is defined, but sizeof(void*) is not 8!");
364 #else
365 if (sizeof(void *) != 4) GoInsane("MUSCLE_64_BIT_PLATFORM is not defined, and sizeof(void*) is not 4!");
366 #endif
367 }
368
369 SanitySetupSystem :: ~SanitySetupSystem()
370 {
371 #ifdef MUSCLE_COUNT_STRING_COPY_OPERATIONS
372 PrintAndClearStringCopyCounts("At end of main()");
373 #endif
374 }
375
376 #ifdef MUSCLE_COUNT_STRING_COPY_OPERATIONS
377 void PrintAndClearStringCopyCounts(const char * optDesc)
378 {
379 const uint32 * s = _stringOpCounts; // just to save chars
380 const uint32 totalCopies = s[STRING_OP_COPY_CTOR] + s[STRING_OP_PARTIAL_COPY_CTOR] + s[STRING_OP_SET_FROM_STRING];
381 const uint32 totalMoves = s[STRING_OP_MOVE_CTOR] + s[STRING_OP_MOVE_FROM_STRING];
382
383 printf("String Op Counts [%s]\n", optDesc?optDesc:"Untitled");
384 printf("# Default Ctors = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_DEFAULT_CTOR]);
385 printf("# Cstr Ctors = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_CSTR_CTOR]);
386 printf("# Copy Ctors = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_COPY_CTOR]);
387 printf("# PtCopy Ctors = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_PARTIAL_COPY_CTOR]);
388 printf("# Set from Cstr = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_SET_FROM_CSTR]);
389 printf("# Set from Str = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_SET_FROM_STRING]);
390 printf("# Move Ctor = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_MOVE_CTOR]);
391 printf("# Move from Str = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_MOVE_FROM_STRING]);
392 printf("# Dtors = " UINT32_FORMAT_SPEC "\n", s[STRING_OP_DTOR]);
393 printf("-----------------------------\n");
394 printf("# Total Copies = " UINT32_FORMAT_SPEC "\n", totalCopies);
395 printf("# Total Moves = " UINT32_FORMAT_SPEC "\n", totalMoves);
396 printf("# Total Either = " UINT32_FORMAT_SPEC "\n", totalCopies+totalMoves);
397 printf("\n");
398
399 for (uint32 i=0; i<NUM_STRING_OPS; i++) _stringOpCounts[i] = 0; // reset counts for next time
400 }
401 #endif
402
403 MathSetupSystem :: MathSetupSystem()
404 {
405 #if defined(__BORLANDC__)
406 _control87(MCW_EM,MCW_EM); // disable floating point exceptions
407 #endif
408 }
409
410 MathSetupSystem :: ~MathSetupSystem()
411 {
412 // empty
413 }
414
415 #if defined(__BEOS__) || defined(__HAIKU__)
416 // empty
417 #elif defined(TARGET_PLATFORM_XENOMAI) && !defined(MUSCLE_AVOID_XENOMAI)
418 // empty
419 #elif defined(WIN32)
420 static Mutex _rtMutex; // used for serializing access inside GetRunTime64Aux(), if necessary
421 # if defined(MUSCLE_USE_QUERYPERFORMANCECOUNTER)
422 static uint64 _qpcTicksPerSecond = 0;
423 # endif
424 #elif defined(__APPLE__)
425 static mach_timebase_info_data_t _machTimebase = {0,0};
426 #elif defined(MUSCLE_USE_LIBRT) && defined(_POSIX_MONOTONIC_CLOCK)
427 // empty
428 #else
429 static Mutex _rtMutex; // used for serializing access inside GetRunTime64Aux(), if necessary
430 static clock_t _posixTicksPerSecond = 0;
431 #endif
432
433 static void InitClockFrequency()
434 {
435 #if defined(__BEOS__) || defined(__HAIKU__)
436 // empty
437 #elif defined(TARGET_PLATFORM_XENOMAI) && !defined(MUSCLE_AVOID_XENOMAI)
438 // empty
439 #elif defined(WIN32)
440 # if defined(MUSCLE_USE_QUERYPERFORMANCECOUNTER)
441 LARGE_INTEGER tps;
442 if (QueryPerformanceFrequency(&tps)) _qpcTicksPerSecond = tps.QuadPart;
443 else MCRASH("QueryPerformanceFrequency() failed!");
444 # endif
445 #elif defined(__APPLE__)
446 if ((mach_timebase_info(&_machTimebase) != KERN_SUCCESS)||(_machTimebase.denom <= 0)) MCRASH("mach_timebase_info() failed!");
447 #elif defined(MUSCLE_USE_LIBRT) && defined(_POSIX_MONOTONIC_CLOCK)
448 // empty
449 #else
450 _posixTicksPerSecond = sysconf(_SC_CLK_TCK);
451 if (_posixTicksPerSecond < 0) MCRASH("sysconf(_SC_CLK_TCK) failed!");
452 #endif
453 }
454
455 TimeSetupSystem :: TimeSetupSystem()
456 {
457 InitClockFrequency();
458 }
459
460 TimeSetupSystem :: ~TimeSetupSystem()
461 {
462 // empty
463 }
464
465 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
466 /** Gotta do a custom data structure because we can't use the standard new/delete/muscleAlloc()/muscleFree() memory operators,
467 * because to do so would cause an infinite regress if they call Mutex::Lock() or Mutex::Unlock() (which they do)
468 */
469 class MutexEventLog
470 {
471 public:
472 // Note: You MUST call Initialize() after creating a MutexEventLog object!
473 MutexEventLog() {/* empty */}
474
475 void Initialize(const muscle_thread_id & id) {_threadID = id; _headBlock = _tailBlock = NULL;}
476
477 void AddEvent(bool isLock, const void * mutexPtr, const char * fileName, int fileLine)
478 {
479 if ((_tailBlock == NULL)||(_tailBlock->IsFull()))
480 {
481 MutexEventBlock * newBlock = static_cast<MutexEventBlock *>(malloc(sizeof(MutexEventBlock))); // THIS LINE CAN ONLY CALL plain old malloc() and nothing else!!!
482 if (newBlock)
483 {
484 newBlock->Initialize();
485 if (_headBlock == NULL) _headBlock = newBlock;
486 if (_tailBlock) _tailBlock->_nextBlock = newBlock;
487 _tailBlock = newBlock;
488 }
489 else
490 {
491 printf("MutexEventLog::AddEvent(): malloc() failed!\n"); // what else to do? Even WARN_OUT_OF_MEMORY isn't safe here
492 return;
493 }
494 }
495 if (_tailBlock) _tailBlock->AddEvent(isLock, mutexPtr, fileName, fileLine);
496 }
497
498 void PrintToStream() const
499 {
500 MutexEventBlock * meb = _headBlock;
501 while(meb)
502 {
503 meb->PrintToStream(_threadID);
504 meb = meb->_nextBlock;
505 }
506 }
507
508 private:
509 class MutexEventBlock
510 {
511 public:
512 MutexEventBlock() {/* empty */}
513
514 void Initialize() {_validCount = 0; _nextBlock = NULL;}
515 bool IsFull() const {return (_validCount == ARRAYITEMS(_events));}
516 void AddEvent(bool isLock, const void * mutexPtr, const char * fileName, int fileLine) {_events[_validCount++] = MutexEvent(isLock, mutexPtr, fileName, fileLine);}
517 void PrintToStream(const muscle_thread_id & tid) const {for (uint32 i=0; i<_validCount; i++) _events[i].PrintToStream(tid);}
518
519 private:
520 friend class MutexEventLog;
521
522 class MutexEvent
523 {
524 public:
525 MutexEvent() {/* empty */}
526
527 MutexEvent(bool isLock, const void * mutexPtr, const char * fileName, uint32 fileLine) : _fileLine(fileLine | (isLock?(1L<<31):0)), _mutexPtr(mutexPtr)
528 {
529 const char * lastSlash = strrchr(fileName, '/');
530 if (lastSlash) fileName = lastSlash+1;
531
532 muscleStrncpy(_fileName, fileName, sizeof(_fileName));
533 _fileName[sizeof(_fileName)-1] = '\0';
534 }
535
536 void PrintToStream(const muscle_thread_id & threadID) const
537 {
538 char buf[20];
539 printf("%s: tid=%s m=%p loc=%s:" UINT32_FORMAT_SPEC "\n", (_fileLine&(1L<<31))?"mx_lock":"mx_unlk", threadID.ToString(buf), _mutexPtr, _fileName, (uint32)(_fileLine&~(1L<<31)));
540 }
541
542 private:
543 uint32 _fileLine;
544 const void * _mutexPtr;
545 char _fileName[48];
546 };
547
548 MutexEventBlock * _nextBlock;
549 uint32 _validCount;
550 MutexEvent _events[4096];
551 };
552
553 muscle_thread_id _threadID;
554 MutexEventBlock * _headBlock;
555 MutexEventBlock * _tailBlock;
556 };
557
558 static ThreadLocalStorage<MutexEventLog> _mutexEventsLog(false); // false argument is necessary otherwise we can't read the threads' logs after they've gone away!
559 static Mutex _mutexLogTableMutex;
560 static Queue<MutexEventLog *> _mutexLogTable; // read at process-shutdown time (I use a Queue rather than a Hashtable because muscle_thread_id isn't usable as a Hashtable key)
561
562 void DeadlockFinder_LogEvent(bool isLock, const void * mutexPtr, const char * fileName, int fileLine)
563 {
564 MutexEventLog * mel = _mutexEventsLog.GetThreadLocalObject();
565 if (mel == NULL)
566 {
567 mel = static_cast<MutexEventLog *>(malloc(sizeof(MutexEventLog))); // MUST CALL malloc() here to avoid inappropriate re-entrancy!
568 if (mel)
569 {
570 mel->Initialize(muscle_thread_id::GetCurrentThreadID());
571 _mutexEventsLog.SetThreadLocalObject(mel);
572 if (_mutexLogTableMutex.Lock() == B_NO_ERROR)
573 {
574 _mutexLogTable.AddTail(mel);
575 _mutexLogTableMutex.Unlock();
576 }
577 }
578 }
579 if (mel) mel->AddEvent(isLock, mutexPtr, fileName, fileLine);
580 else printf("DeadlockFinder_LogEvent: malloc failed!?\n"); // we can't even call WARN_OUT_OF_MEMORY here
581 }
582
583 static void DeadlockFinder_ProcessEnding()
584 {
585 MutexGuard mg(_mutexLogTableMutex);
586 for (uint32 i=0; i<_mutexLogTable.GetNumItems(); i++) _mutexLogTable[i]->PrintToStream();
587 }
588
589 #endif
590
591 ThreadSetupSystem :: ThreadSetupSystem(bool muscleSingleThreadOnly)
592 {
593 if (++_threadSetupCount == 1)
594 {
595 #ifdef MUSCLE_SINGLE_THREAD_ONLY
596 (void) muscleSingleThreadOnly; // shut the compiler up
597 #else
598 _mainThreadID = muscle_thread_id::GetCurrentThreadID();
599 _muscleSingleThreadOnly = muscleSingleThreadOnly;
600 if (_muscleSingleThreadOnly) _lock.Neuter(); // if we're single-thread, then this Mutex can be a no-op!
601 #endif
602 _muscleLock = &_lock;
603
604 #if defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
605 _muscleAtomicMutexes = newnothrow_array(Mutex, MUSCLE_MUTEX_POOL_SIZE);
606 MASSERT(_muscleAtomicMutexes, "Could not allocate atomic mutexes!");
607 #endif
608 }
609 }
610
611 ThreadSetupSystem :: ~ThreadSetupSystem()
612 {
613 if (--_threadSetupCount == 0)
614 {
615 #if defined(MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS)
616 delete [] _muscleAtomicMutexes; _muscleAtomicMutexes = NULL;
617 #endif
618 _muscleLock = NULL;
619
620 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
621 DeadlockFinder_ProcessEnding();
622 #endif
623 }
624 }
625
626 static uint32 _networkSetupCount = 0;
627
628 #if defined(MUSCLE_ENABLE_SSL) && !defined(MUSCLE_SINGLE_THREAD_ONLY)
629
630 // OpenSSL thread-safety-callback setup code provided by Tosha at
631 // http://stackoverflow.com/questions/3417706/openssl-and-multi-threads/12810000#12810000
632 # if defined(WIN32)
633 # define OPENSSL_MUTEX_TYPE HANDLE
634 # define OPENSSL_MUTEX_SETUP(x) (x) = CreateMutex(NULL, FALSE, NULL)
635 # define OPENSSL_MUTEX_CLEANUP(x) CloseHandle(x)
636 # define OPENSSL_MUTEX_LOCK(x) WaitForSingleObject((x), INFINITE)
637 # define OPENSSL_MUTEX_UNLOCK(x) ReleaseMutex(x)
638 # define OPENSSL_THREAD_ID GetCurrentThreadId()
639 # else
640 # define OPENSSL_MUTEX_TYPE pthread_mutex_t
641 # define OPENSSL_MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
642 # define OPENSSL_MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
643 # define OPENSSL_MUTEX_LOCK(x) pthread_mutex_lock(&(x))
644 # define OPENSSL_MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
645 # define OPENSSL_THREAD_ID pthread_self()
646 # endif
647
648 /* This array will store all of the mutexes available to OpenSSL. */
649 static OPENSSL_MUTEX_TYPE *mutex_buf=NULL;
650
651 static void openssl_locking_function(int mode, int n, const char * file, int line)
652 {
653 (void) file;
654 (void) line;
655 if (mode & CRYPTO_LOCK) OPENSSL_MUTEX_LOCK(mutex_buf[n]);
656 else OPENSSL_MUTEX_UNLOCK(mutex_buf[n]);
657 }
658
659 static unsigned long openssl_id_function(void) {return ((unsigned long)OPENSSL_THREAD_ID);}
660
661 static int openssl_thread_setup(void)
662 {
663 mutex_buf = (OPENSSL_MUTEX_TYPE *) malloc(CRYPTO_num_locks() * sizeof(OPENSSL_MUTEX_TYPE));
664 if (!mutex_buf) return -1;
665 for (int i=0; i<CRYPTO_num_locks(); i++) OPENSSL_MUTEX_SETUP(mutex_buf[i]);
666 CRYPTO_set_id_callback(openssl_id_function);
667 CRYPTO_set_locking_callback(openssl_locking_function);
668 return 0;
669 }
670
671 static int openssl_thread_cleanup(void)
672 {
673 if (!mutex_buf) return -1;
674 CRYPTO_set_id_callback(NULL);
675 CRYPTO_set_locking_callback(NULL);
676 for (int i=0; i < CRYPTO_num_locks(); i++) OPENSSL_MUTEX_CLEANUP(mutex_buf[i]);
677 free(mutex_buf);
678 mutex_buf = NULL;
679 return 0;
680 }
681
682 #endif
683
684 NetworkSetupSystem :: NetworkSetupSystem()
685 {
686 if (++_networkSetupCount == 1)
687 {
688 #ifdef WIN32
689 WORD versionWanted = MAKEWORD(1, 1);
690 WSADATA wsaData;
691 if (WSAStartup(versionWanted, &wsaData) != 0) MCRASH("NetworkSetupSystem: Could not initialize Winsock!");
692 #else
693 struct sigaction sa;
694 memset(&sa, 0, sizeof(sa));
695 sa.sa_handler = SIG_IGN;
696 if (sigaction(SIGPIPE, &sa, NULL) != 0) MCRASH("NetworkSetupSystem: Could not ignore SIGPIPE signal!");
697 #endif
698
699 #ifdef MUSCLE_ENABLE_SSL
700 SSL_load_error_strings();
701 SSLeay_add_ssl_algorithms();
702 ERR_load_BIO_strings();
703 SSL_library_init();
704 # ifndef MUSCLE_SINGLE_THREAD_ONLY
705 if (openssl_thread_setup() != 0) MCRASH("Error setting up thread-safety callbacks for OpenSSL!");
706 # endif
707 #endif
708 }
709 }
710
711 NetworkSetupSystem :: ~NetworkSetupSystem()
712 {
713 if (--_networkSetupCount == 0)
714 {
715 #if defined(MUSCLE_ENABLE_SSL) && !defined(MUSCLE_SINGLE_THREAD_ONLY)
716 (void) openssl_thread_cleanup();
717 #endif
718 #ifdef WIN32
719 WSACleanup();
720 #endif
721 }
722 }
723
724 #if defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) && defined (MUSCLE_POWERPC_TIMEBASE_HZ)
725 static inline uint32 get_tbl() {uint32 tbl; asm volatile("mftb %0" : "=r" (tbl) :); return tbl;}
726 static inline uint32 get_tbu() {uint32 tbu; asm volatile("mftbu %0" : "=r" (tbu) :); return tbu;}
727 #endif
728
729 /** Defined here since every MUSCLE program will have to include this file anyway... */
730 static uint64 GetRunTime64Aux()
731 {
732 #if defined(__BEOS__) || defined(__HAIKU__)
733 return return system_time();
734 #elif defined(TARGET_PLATFORM_XENOMAI) && !defined(MUSCLE_AVOID_XENOMAI)
735 return rt_timer_tsc2ns(rt_timer_tsc())/1000;
736 #elif defined(WIN32)
737 uint64 ret = 0;
738 if (_rtMutex.Lock() == B_NO_ERROR)
739 {
740 # ifdef MUSCLE_USE_QUERYPERFORMANCECOUNTER
741 if (_qpcTicksPerSecond == 0) InitClockFrequency(); // in case we got called before main()
742
743 static int64 _brokenQPCOffset = 0;
744 if (_brokenQPCOffset != 0) ret = (((uint64)timeGetTime())*1000) + _brokenQPCOffset;
745 else
746 {
747 LARGE_INTEGER curTicks;
748 if ((_qpcTicksPerSecond > 0)&&(QueryPerformanceCounter(&curTicks)))
749 {
750 const uint64 checkGetTime = ((uint64)timeGetTime())*1000;
751 ret = (curTicks.QuadPart*MICROS_PER_SECOND)/_qpcTicksPerSecond;
752
753 // Hack-around for evil Windows/hardware bug in QueryPerformanceCounter().
754 // see http://support.microsoft.com/default.aspx?scid=kb;en-us;274323
755 static uint64 _lastCheckGetTime = 0;
756 static uint64 _lastCheckQPCTime = 0;
757 if (_lastCheckGetTime > 0)
758 {
759 const uint64 getTimeElapsed = checkGetTime - _lastCheckGetTime;
760 const uint64 qpcTimeElapsed = ret - _lastCheckQPCTime;
761 if ((muscleMax(getTimeElapsed, qpcTimeElapsed) - muscleMin(getTimeElapsed, qpcTimeElapsed)) > 500000)
762 {
763 //LogTime(MUSCLE_LOG_DEBUG, "QueryPerformanceCounter() is buggy, reverting to timeGetTime() method instead!\n");
764 _brokenQPCOffset = (_lastCheckQPCTime-_lastCheckGetTime);
765 ret = (((uint64)timeGetTime())*1000) + _brokenQPCOffset;
766 }
767 }
768 _lastCheckGetTime = checkGetTime;
769 _lastCheckQPCTime = ret;
770 }
771 }
772 # endif
773 if (ret == 0)
774 {
775 static uint32 _prevVal = 0;
776 static uint64 _wrapOffset = 0;
777
778 const uint32 newVal = (uint32) timeGetTime();
779 if (newVal < _prevVal) _wrapOffset += (((uint64)1)<<32);
780 ret = (_wrapOffset+newVal)*1000; // convert to microseconds
781 _prevVal = newVal;
782 }
783 _rtMutex.Unlock();
784 }
785 return ret;
786 #elif defined(__APPLE__)
787 if (_machTimebase.denom == 0) InitClockFrequency(); // in case we got called before main()
788 return (uint64)((mach_absolute_time() * _machTimebase.numer) / (1000 * _machTimebase.denom));
789 #elif defined(MUSCLE_USE_POWERPC_INLINE_ASSEMBLY) && defined(MUSCLE_POWERPC_TIMEBASE_HZ)
790 while(1)
791 {
792 const uint32 hi1 = get_tbu();
793 const uint32 low = get_tbl();
794 const uint32 hi2 = get_tbu();
795 if (hi1 == hi2)
796 {
797 // FogBugz #3199
798 const uint64 cycles = ((((uint64)hi1)<<32)|((uint64)low));
799 return ((cycles/MUSCLE_POWERPC_TIMEBASE_HZ)*MICROS_PER_SECOND)+(((cycles%MUSCLE_POWERPC_TIMEBASE_HZ)*(MICROS_PER_SECOND))/MUSCLE_POWERPC_TIMEBASE_HZ);
800 }
801 }
802 #elif defined(MUSCLE_USE_LIBRT) && defined(_POSIX_MONOTONIC_CLOCK)
803 struct timespec ts;
804 return (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) ? (SecondsToMicros(ts.tv_sec)+NanosToMicros(ts.tv_nsec)) : 0;
805 #else
806 // default implementation: use POSIX API
807 if (_posixTicksPerSecond <= 0) InitClockFrequency(); // in case we got called before main()
808 if (sizeof(clock_t) > sizeof(uint32))
809 {
810 // Easy case: with a wide clock_t, we don't need to worry about it wrapping
811 struct tms junk; clock_t newTicks = (clock_t) times(&junk);
812 return ((((uint64)newTicks)*MICROS_PER_SECOND)/_posixTicksPerSecond);
813 }
814 else
815 {
816 // Oops, clock_t is skinny enough that it might wrap. So we need to watch for that.
817 if (_rtMutex.Lock() == B_NO_ERROR)
818 {
819 static uint32 _prevVal;
820 static uint64 _wrapOffset = 0;
821
822 struct tms junk; clock_t newTicks = (clock_t) times(&junk);
823 const uint32 newVal = (uint32) newTicks;
824 if (newVal < _prevVal) _wrapOffset += (((uint64)1)<<32);
825 const uint64 ret = ((_wrapOffset+newVal)*MICROS_PER_SECOND)/_posixTicksPerSecond; // convert to microseconds
826 _prevVal = newTicks;
827
828 _rtMutex.Unlock();
829 return ret;
830 }
831 else return 0; // Oops?
832 }
833 #endif
834 }
835
836 static int64 _perProcessRunTimeOffset = 0;
837 uint64 GetRunTime64() {return GetRunTime64Aux()+_perProcessRunTimeOffset;}
838 void SetPerProcessRunTime64Offset(int64 offset) {_perProcessRunTimeOffset = offset;}
839 int64 GetPerProcessRunTime64Offset() {return _perProcessRunTimeOffset;}
840
841 #if !(defined(__BEOS__) || defined(__HAIKU__))
842 status_t Snooze64(uint64 micros)
843 {
844 if (micros == MUSCLE_TIME_NEVER)
845 {
846 while(Snooze64(DaysToMicros(1)) == B_NO_ERROR) {/* empty */}
847 return B_ERROR; // we should never exit the while loop above; so if we got here, it's an error
848 }
849
850 #if __ATHEOS__
851 return (snooze(micros) >= 0) ? B_NO_ERROR : B_ERRNO;
852 #elif WIN32
853 Sleep((DWORD)((micros/1000)+(((micros%1000)!=0)?1:0)));
854 return B_NO_ERROR;
855 #elif defined(MUSCLE_USE_LIBRT) && defined(_POSIX_MONOTONIC_CLOCK) && !defined(__EMSCRIPTEN__)
856 const struct timespec ts = {(time_t) MicrosToSeconds(micros), (time_t) MicrosToNanos(micros%MICROS_PER_SECOND)};
857 return (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL) == 0) ? B_NO_ERROR : B_ERRNO;
858 #else
859 /** We can use select(), if nothing else */
860 struct timeval waitTime;
861 Convert64ToTimeVal(micros, waitTime);
862 return (select(0, NULL, NULL, NULL, &waitTime) >= 0) ? B_NO_ERROR : B_ERRNO;
863 #endif
864 }
865
866 #ifdef WIN32
867 // Broken out so ParseHumanReadableTimeValues() can use it also
868 uint64 __Win32FileTimeToMuscleTime(const FILETIME & ft)
869 {
870 union {
871 uint64 ns100; /*time since 1 Jan 1601 in 100ns units */
872 FILETIME ft;
873 } theTime;
874 theTime.ft = ft;
875
876 static const uint64 TIME_DIFF = ((uint64)116444736)*NANOS_PER_SECOND;
877 struct timeval tv;
878 tv.tv_usec = (long)((theTime.ns100 / ((uint64)10)) % MICROS_PER_SECOND);
879 tv.tv_sec = (long)((theTime.ns100 - TIME_DIFF) / (10*MICROS_PER_SECOND));
880 return ConvertTimeValTo64(tv);
881 }
882 #endif
883
884 #endif /* !__BEOS__ && !__HAIKU__ */
885
886 /** Defined here since every MUSCLE program will have to include this file anyway... */
887 uint64 GetCurrentTime64(uint32 timeType)
888 {
889 #ifdef WIN32
890 FILETIME ft;
891 GetSystemTimeAsFileTime(&ft);
892 if (timeType == MUSCLE_TIMEZONE_LOCAL) (void) FileTimeToLocalFileTime(&ft, &ft);
893 return __Win32FileTimeToMuscleTime(ft);
894 #else
895 # if defined(__BEOS__) || defined(__HAIKU__)
896 uint64 ret = real_time_clock_usecs();
897 # else
898 struct timeval tv;
899 gettimeofday(&tv, NULL);
900 uint64 ret = ConvertTimeValTo64(tv);
901 # endif
902 if (timeType == MUSCLE_TIMEZONE_LOCAL)
903 {
904 time_t now = time(NULL);
905 # if defined(__BEOS__) && !defined(__HAIKU__)
906 struct tm * tm = gmtime(&now);
907 # else
908 struct tm gmtm;
909 struct tm * tm = gmtime_r(&now, &gmtm);
910 # endif
911 if (tm)
912 {
913 ret += SecondsToMicros(now-mktime(tm));
914 if (tm->tm_isdst>0) ret += HoursToMicros(1); // FogBugz #4498
915 }
916 }
917 return ret;
918 #endif
919 }
920
921 #if MUSCLE_TRACE_CHECKPOINTS > 0
922 static volatile uint32 _defaultTraceLocation[MUSCLE_TRACE_CHECKPOINTS];
923 volatile uint32 * _muscleTraceValues = _defaultTraceLocation;
924 uint32 _muscleNextTraceValueIndex = 0;
925
926 void SetTraceValuesLocation(volatile uint32 * location)
927 {
928 _muscleTraceValues = location ? location : _defaultTraceLocation;
929 _muscleNextTraceValueIndex = 0;
930 for (uint32 i=0; i<MUSCLE_TRACE_CHECKPOINTS; i++) _muscleTraceValues[i] = 0;
931 }
932 #endif
933
934 static AbstractObjectRecycler * _firstRecycler = NULL;
935
936 AbstractObjectRecycler :: AbstractObjectRecycler()
937 {
938 Mutex * m = GetGlobalMuscleLock();
939 if ((m)&&(m->Lock() != B_NO_ERROR)) m = NULL;
940
941 // Append us to the front of the linked list
942 if (_firstRecycler) _firstRecycler->_prev = this;
943 _prev = NULL;
944 _next = _firstRecycler;
945 _firstRecycler = this;
946
947 if (m) m->Unlock();
948 }
949
950 AbstractObjectRecycler :: ~AbstractObjectRecycler()
951 {
952 Mutex * m = GetGlobalMuscleLock();
953 if ((m)&&(m->Lock() != B_NO_ERROR)) m = NULL;
954
955 // Remove us from the linked list
956 if (_prev) _prev->_next = _next;
957 if (_next) _next->_prev = _prev;
958 if (_firstRecycler == this) _firstRecycler = _next;
959
960 if (m) m->Unlock();
961 }
962
963 void AbstractObjectRecycler :: GlobalFlushAllCachedObjects()
964 {
965 Mutex * m = GetGlobalMuscleLock();
966 if ((m)&&(m->Lock() != B_NO_ERROR)) m = NULL;
967
968 // We restart at the head of the list anytime anything is flushed,
969 // for safety. When we get to the end of the list, everything has
970 // been flushed.
971 AbstractObjectRecycler * r = _firstRecycler;
972 while(r) r = (r->FlushCachedObjects() > 0) ? _firstRecycler : r->_next;
973 if (m) m->Unlock();
974 }
975
976 void AbstractObjectRecycler :: GlobalPrintRecyclersToStream()
977 {
978 Mutex * m = GetGlobalMuscleLock();
979 if ((m)&&(m->Lock() != B_NO_ERROR)) m = NULL;
980
981 const AbstractObjectRecycler * r = _firstRecycler;
982 while(r)
983 {
984 r->PrintToStream();
985 r = r->_next;
986 }
987
988 if (m) m->Unlock();
989 }
990
991 static CompleteSetupSystem * _activeCSS = NULL;
992 CompleteSetupSystem * CompleteSetupSystem :: GetCurrentCompleteSetupSystem() {return _activeCSS;}
993
994 CompleteSetupSystem :: CompleteSetupSystem(bool muscleSingleThreadOnly)
995 : _threads(muscleSingleThreadOnly)
996 , _prevInstance(_activeCSS)
997 , _initialMemoryUsage((size_t) GetProcessMemoryUsage())
998 {
999 _activeCSS = this; // push us onto the stack
1000 }
1001
1002 CompleteSetupSystem :: ~CompleteSetupSystem()
1003 {
1004 // We'll assume that by this point all spawned threads are gone, and therefore mutex-ordering problems detected after this are not real problems.
1005 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
1006 _enableDeadlockFinderPrints = false;
1007 #endif
1008
1009 GenericCallbackRef r;
1010 while(_cleanupCallbacks.RemoveTail(r) == B_NO_ERROR) (void) r()->Callback(NULL);
1011
1012 AbstractObjectRecycler::GlobalFlushAllCachedObjects();
1013
1014 _activeCSS = _prevInstance; // pop us off the stack
1015 }
1016
1017 uint32 DataIO :: WriteFully(const void * buffer, uint32 size)
1018 {
1019 const uint8 * b = (const uint8 *)buffer;
1020 const uint8 * firstInvalidByte = b+size;
1021 while(b < firstInvalidByte)
1022 {
1023 const int32 bytesWritten = Write(b, (uint32)(firstInvalidByte-b));
1024 if (bytesWritten <= 0) break;
1025 b += bytesWritten;
1026 }
1027 return (uint32) (b-((const uint8 *)buffer));
1028 }
1029
1030 uint32 DataIO :: ReadFully(void * buffer, uint32 size)
1031 {
1032 uint8 * b = (uint8 *) buffer;
1033 uint8 * firstInvalidByte = b+size;
1034 while(b < firstInvalidByte)
1035 {
1036 const int32 bytesRead = Read(b, (uint32) (firstInvalidByte-b));
1037 if (bytesRead <= 0) break;
1038 b += bytesRead;
1039 }
1040 return (uint32) (b-((const uint8 *)buffer));
1041 }
1042
1043 int64 SeekableDataIO :: GetLength()
1044 {
1045 const int64 origPos = GetPosition();
1046 if ((origPos >= 0)&&(Seek(0, IO_SEEK_END) == B_NO_ERROR))
1047 {
1048 const int64 ret = GetPosition();
1049 if (Seek(origPos, IO_SEEK_SET) == B_NO_ERROR) return ret;
1050 }
1051 return -1; // error!
1052 }
1053
1054 status_t Flattenable :: FlattenToDataIO(DataIO & outputStream, bool addSizeHeader) const
1055 {
1056 uint8 smallBuf[256];
1057 uint8 * bigBuf = NULL;
1058
1059 const uint32 fs = FlattenedSize();
1060 const uint32 bufSize = fs+(addSizeHeader?sizeof(uint32):0);
1061
1062 uint8 * b;
1063 if (bufSize<=ARRAYITEMS(smallBuf)) b = smallBuf;
1064 else
1065 {
1066 b = bigBuf = newnothrow_array(uint8, bufSize);
1067 if (bigBuf == NULL) RETURN_OUT_OF_MEMORY;
1068 }
1069
1070 // Populate the buffer
1071 if (addSizeHeader)
1072 {
1073 muscleCopyOut(b, B_HOST_TO_LENDIAN_INT32(fs));
1074 Flatten(b+sizeof(uint32));
1075 }
1076 else Flatten(b);
1077
1078 // And finally, write out the buffer
1079 const status_t ret = (outputStream.WriteFully(b, bufSize) == bufSize) ? B_NO_ERROR : B_IO_ERROR;
1080 delete [] bigBuf;
1081 return ret;
1082 }
1083
1084 status_t Flattenable :: UnflattenFromDataIO(DataIO & inputStream, int32 optReadSize, uint32 optMaxReadSize)
1085 {
1086 uint32 readSize = (uint32) optReadSize;
1087 if (optReadSize < 0)
1088 {
1089 uint32 leSize;
1090 if (inputStream.ReadFully(&leSize, sizeof(leSize)) != sizeof(leSize)) return B_IO_ERROR;
1091 readSize = (uint32) B_LENDIAN_TO_HOST_INT32(leSize);
1092 if (readSize > optMaxReadSize) return B_BAD_DATA;
1093 }
1094
1095 uint8 smallBuf[256];
1096 uint8 * bigBuf = NULL;
1097 uint8 * b;
1098 if (readSize<=ARRAYITEMS(smallBuf)) b = smallBuf;
1099 else
1100 {
1101 b = bigBuf = newnothrow_array(uint8, readSize);
1102 if (bigBuf == NULL) RETURN_OUT_OF_MEMORY;
1103 }
1104
1105 const status_t ret = (inputStream.ReadFully(b, readSize) == readSize) ? Unflatten(b, readSize) : B_IO_ERROR;
1106 delete [] bigBuf;
1107 return ret;
1108 }
1109
1110 status_t Flattenable :: CopyFromImplementation(const Flattenable & copyFrom)
1111 {
1112 uint8 smallBuf[256];
1113 uint8 * bigBuf = NULL;
1114 const uint32 flatSize = copyFrom.FlattenedSize();
1115 if (flatSize > ARRAYITEMS(smallBuf))
1116 {
1117 bigBuf = newnothrow_array(uint8, flatSize);
1118 if (bigBuf == NULL) RETURN_OUT_OF_MEMORY;
1119 }
1120 copyFrom.Flatten(bigBuf ? bigBuf : smallBuf);
1121 const status_t ret = Unflatten(bigBuf ? bigBuf : smallBuf, flatSize);
1122 delete [] bigBuf;
1123 return ret;
1124 }
1125
1126 #if defined(MUSCLE_USE_KQUEUE) || defined(MUSCLE_USE_EPOLL)
1127 extern void NotifySocketMultiplexersThatSocketIsClosed(int fd);
1128 #endif
1129
1130 // This function is now a private one, since it should no longer be necessary to call it
1131 // from user code. Instead, attach any socket file descriptors you create to ConstSocketRef
1132 // objects by calling GetConstSocketRefFromPool(fd), and the file descriptors will be automatically
1133 // closed when the last ConstSocketRef that references them is destroyed.
1134 static void CloseSocket(int fd)
1135 {
1136 if (fd >= 0)
1137 {
1138 #if defined(MUSCLE_USE_KQUEUE) || defined(MUSCLE_USE_EPOLL)
1139 // We have to do this, otherwise a socket fd value can get re-used before the next call
1140 // to WaitForEvents(), causing the SocketMultiplexers to fail to update their in-kernel state.
1141 NotifySocketMultiplexersThatSocketIsClosed(fd);
1142 #endif
1143
1144 #if defined(WIN32) || defined(BEOS_OLD_NETSERVER)
1145 ::closesocket(fd);
1146 #else
1147 close(fd);
1148 #endif
1149 }
1150 }
1151
1152 const ConstSocketRef & GetInvalidSocket()
1153 {
1154 static const ConstSocketRef _ref(&GetDefaultObjectForType<Socket>(), false);
1155 return _ref;
1156 }
1157
1158 ConstSocketRef GetConstSocketRefFromPool(int fd, bool okayToClose, bool returnNULLOnInvalidFD)
1159 {
1160 static ConstSocketRef::ItemPool _socketPool;
1161
1162 if ((fd < 0)&&(returnNULLOnInvalidFD)) return ConstSocketRef();
1163 else
1164 {
1165 Socket * s = _socketPool.ObtainObject();
1166 ConstSocketRef ret(s);
1167
1168 if (s)
1169 {
1170 s->SetFileDescriptor(fd, okayToClose);
1171 #ifdef WIN32
1172 // FogBugz #9911: Make the socket un-inheritable, since that
1173 // is the behavior you want 99% of the time. (Anyone who wants
1174 // to inherit the socket will have to either avoid calling this
1175 // for those sockets, or call SetHandleInformation() again
1176 // afterwards to reinstate the inherit-handle flag)
1177 (void) SetHandleInformation((HANDLE)((ptrdiff)fd), HANDLE_FLAG_INHERIT, 0);
1178 #endif
1179 }
1180 else if (okayToClose) CloseSocket(fd);
1181
1182 return ret;
1183 }
1184 }
1185
1186 Socket :: ~Socket()
1187 {
1188 Clear();
1189 }
1190
1191 void Socket :: SetFileDescriptor(int newFD, bool okayToClose)
1192 {
1193 if (newFD != _fd)
1194 {
1195 if (_okayToClose) CloseSocket(_fd); // CloseSocket(-1) is a no-op, so no need to check fd twice
1196 _fd = newFD;
1197 }
1198 _okayToClose = okayToClose;
1199 }
1200
1201 static void FlushStringAsciiChars(String & s, int idx, char * ascBuf, char * hexBuf, uint32 count, uint32 numColumns)
1202 {
1203 while(count<numColumns) ascBuf[count++] = ' ';
1204 ascBuf[count] = '\0';
1205 char tempBuf[32]; muscleSprintf(tempBuf, "%04i: ", idx); s += tempBuf;
1206 s += ascBuf;
1207 s += " [";
1208 s += hexBuf;
1209 s += "]\n";
1210 hexBuf[0] = '\0';
1211 }
1212
1213 static void FlushAsciiChars(FILE * file, int idx, char * ascBuf, char * hexBuf, uint32 count, uint32 numColumns)
1214 {
1215 while(count<numColumns) ascBuf[count++] = ' ';
1216 ascBuf[count] = '\0';
1217 fprintf(file, "%04i: %s [%s]\n", idx, ascBuf, hexBuf);
1218 hexBuf[0] = '\0';
1219 }
1220
1221 static void FlushLogAsciiChars(int lvl, int idx, char * ascBuf, char * hexBuf, uint32 count, uint32 numColumns)
1222 {
1223 while(count<numColumns) ascBuf[count++] = ' ';
1224 ascBuf[count] = '\0';
1225 LogTime(lvl, "%04i: %s [%s]\n", idx, ascBuf, hexBuf);
1226 hexBuf[0] = '\0';
1227 }
1228
1229 void PrintHexBytes(const void * vbuf, uint32 numBytes, const char * optDesc, uint32 numColumns, FILE * optFile)
1230 {
1231 if (optFile == NULL) optFile = stdout;
1232
1233 const uint8 * buf = (const uint8 *) vbuf;
1234
1235 if (numColumns == 0)
1236 {
1237 // A simple, single-line format
1238 if (optDesc) fprintf(optFile, "%s: ", optDesc);
1239 fprintf(optFile, "[");
1240 if (buf) for (uint32 i=0; i<numBytes; i++) fprintf(optFile, "%s%02x", (i==0)?"":" ", buf[i]);
1241 else fprintf(optFile, "NULL buffer");
1242 fprintf(optFile, "]\n");
1243 }
1244 else
1245 {
1246 // A more useful columnar format with ASCII sidebar
1247 char headBuf[256];
1248 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1249 fprintf(optFile, "%s", headBuf);
1250
1251 const int hexBufSize = (numColumns*8)+1;
1252 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1253 for (int i=0; i<numDashes; i++) fputc('-', optFile);
1254 fputc('\n', optFile);
1255 if (buf)
1256 {
1257 char * ascBuf = newnothrow_array(char, numColumns+1);
1258 char * hexBuf = newnothrow_array(char, hexBufSize);
1259 if ((ascBuf)&&(hexBuf))
1260 {
1261 ascBuf[0] = hexBuf[0] = '\0';
1262
1263 uint32 idx = 0;
1264 while(idx<numBytes)
1265 {
1266 const uint8 c = buf[idx];
1267 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1268 const size_t hexBufLen = strlen(hexBuf);
1269 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1270 idx++;
1271 if ((idx%numColumns) == 0) FlushAsciiChars(optFile, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1272 }
1273 const uint32 leftovers = (numBytes%numColumns);
1274 if (leftovers > 0) FlushAsciiChars(optFile, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1275 }
1276 else WARN_OUT_OF_MEMORY;
1277
1278 delete [] ascBuf;
1279 delete [] hexBuf;
1280 }
1281 else fprintf(optFile, "NULL buffer\n");
1282 }
1283 }
1284
1285 void PrintHexBytes(const ByteBuffer & bb, const char * optDesc, uint32 numColumns, FILE * optFile)
1286 {
1287 PrintHexBytes(bb.GetBuffer(), bb.GetNumBytes(), optDesc, numColumns, optFile);
1288 }
1289
1290 void PrintHexBytes(const ConstByteBufferRef & bbRef, const char * optDesc, uint32 numColumns, FILE * optFile)
1291 {
1292 PrintHexBytes(bbRef()?bbRef()->GetBuffer():NULL, bbRef()?bbRef()->GetNumBytes():0, optDesc, numColumns, optFile);
1293 }
1294
1295 void PrintHexBytes(const Queue<uint8> & buf, const char * optDesc, uint32 numColumns, FILE * optFile)
1296 {
1297 if (optFile == NULL) optFile = stdout;
1298
1299 const uint32 numBytes = buf.GetNumItems();
1300 if (numColumns == 0)
1301 {
1302 // A simple, single-line format
1303 if (optDesc) fprintf(optFile, "%s: ", optDesc);
1304 fprintf(optFile, "[");
1305 for (uint32 i=0; i<numBytes; i++) fprintf(optFile, "%s%02x", (i==0)?"":" ", (unsigned int) buf[i]);
1306 fprintf(optFile, "]\n");
1307 }
1308 else
1309 {
1310 // A more useful columnar format with ASCII sidebar
1311 char headBuf[256];
1312 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1313 fprintf(optFile, "%s", headBuf);
1314
1315 const int hexBufSize = (numColumns*8)+1;
1316 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1317 for (int i=0; i<numDashes; i++) fputc('-', optFile);
1318 fputc('\n', optFile);
1319 char * ascBuf = newnothrow_array(char, numColumns+1);
1320 char * hexBuf = newnothrow_array(char, hexBufSize);
1321 if ((ascBuf)&&(hexBuf))
1322 {
1323 ascBuf[0] = hexBuf[0] = '\0';
1324
1325 uint32 idx = 0;
1326 while(idx<numBytes)
1327 {
1328 const uint8 c = buf[idx];
1329 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1330 const size_t hexBufLen = strlen(hexBuf);
1331 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1332 idx++;
1333 if ((idx%numColumns) == 0) FlushAsciiChars(optFile, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1334 }
1335 const uint32 leftovers = (numBytes%numColumns);
1336 if (leftovers > 0) FlushAsciiChars(optFile, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1337 }
1338 else WARN_OUT_OF_MEMORY;
1339
1340 delete [] ascBuf;
1341 delete [] hexBuf;
1342 }
1343 }
1344
1345 void LogHexBytes(int logLevel, const void * vbuf, uint32 numBytes, const char * optDesc, uint32 numColumns)
1346 {
1347 const uint8 * buf = (const uint8 *) vbuf;
1348
1349 if (numColumns == 0)
1350 {
1351 // A simple, single-line format
1352 if (optDesc) LogTime(logLevel, "%s: ", optDesc);
1353 Log(logLevel, "[");
1354 if (buf) for (uint32 i=0; i<numBytes; i++) Log(logLevel, "%s%02x", (i==0)?"":" ", buf[i]);
1355 else Log(logLevel, "NULL buffer");
1356 Log(logLevel, "]\n");
1357 }
1358 else
1359 {
1360 // A more useful columnar format with ASCII sidebar
1361 char headBuf[256];
1362 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1363 LogTime(logLevel, "%s", headBuf);
1364
1365 const int hexBufSize = (numColumns*8)+1;
1366 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1367 for (int i=0; i<numDashes; i++) Log(logLevel, "-");
1368 Log(logLevel, "\n");
1369 if (buf)
1370 {
1371 char * ascBuf = newnothrow_array(char, numColumns+1);
1372 char * hexBuf = newnothrow_array(char, hexBufSize);
1373 if ((ascBuf)&&(hexBuf))
1374 {
1375 ascBuf[0] = hexBuf[0] = '\0';
1376
1377 uint32 idx = 0;
1378 while(idx<numBytes)
1379 {
1380 const uint8 c = buf[idx];
1381 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1382 const size_t hexBufLen = strlen(hexBuf);
1383 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1384 idx++;
1385 if ((idx%numColumns) == 0) FlushLogAsciiChars(logLevel, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1386 }
1387 const uint32 leftovers = (numBytes%numColumns);
1388 if (leftovers > 0) FlushLogAsciiChars(logLevel, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1389 }
1390 else WARN_OUT_OF_MEMORY;
1391
1392 delete [] ascBuf;
1393 delete [] hexBuf;
1394 }
1395 else LogTime(logLevel, "NULL buffer\n");
1396 }
1397 }
1398
1399 void LogHexBytes(int logLevel, const Queue<uint8> & buf, const char * optDesc, uint32 numColumns)
1400 {
1401 const uint32 numBytes = buf.GetNumItems();
1402 if (numColumns == 0)
1403 {
1404 // A simple, single-line format
1405 if (optDesc) LogTime(logLevel, "%s: ", optDesc);
1406 Log(logLevel, "[");
1407 for (uint32 i=0; i<numBytes; i++) Log(logLevel, "%s%02x", (i==0)?"":" ", buf[i]);
1408 Log(logLevel, "]\n");
1409 }
1410 else
1411 {
1412 // A more useful columnar format with ASCII sidebar
1413 char headBuf[256];
1414 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1415 Log(logLevel, "%s", headBuf);
1416
1417 const int hexBufSize = (numColumns*8)+1;
1418 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1419 for (int i=0; i<numDashes; i++) Log(logLevel, "-");
1420 Log(logLevel, "\n");
1421 char * ascBuf = newnothrow_array(char, numColumns+1);
1422 char * hexBuf = newnothrow_array(char, hexBufSize);
1423 if ((ascBuf)&&(hexBuf))
1424 {
1425 ascBuf[0] = hexBuf[0] = '\0';
1426
1427 uint32 idx = 0;
1428 while(idx<numBytes)
1429 {
1430 const uint8 c = buf[idx];
1431 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1432 const size_t hexBufLen = strlen(hexBuf);
1433 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1434 idx++;
1435 if ((idx%numColumns) == 0) FlushLogAsciiChars(logLevel, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1436 }
1437 const uint32 leftovers = (numBytes%numColumns);
1438 if (leftovers > 0) FlushLogAsciiChars(logLevel, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1439 }
1440 else WARN_OUT_OF_MEMORY;
1441
1442 delete [] ascBuf;
1443 delete [] hexBuf;
1444 }
1445 }
1446
1447 void LogHexBytes(int logLevel, const ByteBuffer & bb, const char * optDesc, uint32 numColumns)
1448 {
1449 LogHexBytes(logLevel, bb.GetBuffer(), bb.GetNumBytes(), optDesc, numColumns);
1450 }
1451
1452 void LogHexBytes(int logLevel, const ConstByteBufferRef & bbRef, const char * optDesc, uint32 numColumns)
1453 {
1454 LogHexBytes(logLevel, bbRef()?bbRef()->GetBuffer():NULL, bbRef()?bbRef()->GetNumBytes():0, optDesc, numColumns);
1455 }
1456
1457 String HexBytesToAnnotatedString(const void * vbuf, uint32 numBytes, const char * optDesc, uint32 numColumns)
1458 {
1459 String ret;
1460
1461 const uint8 * buf = (const uint8 *) vbuf;
1462 if (numColumns == 0)
1463 {
1464 // A simple, single-line format
1465 if (optDesc) {ret += optDesc; ret += ": ";}
1466 ret += '[';
1467 if (buf) for (uint32 i=0; i<numBytes; i++) {char zbuf[32]; muscleSprintf(zbuf, "%s%02x", (i==0)?"":" ", buf[i]); ret += zbuf;}
1468 else ret += "NULL buffer";
1469 ret += ']';
1470 }
1471 else
1472 {
1473 // A more useful columnar format with ASCII sidebar
1474 char headBuf[256];
1475 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1476 ret += headBuf;
1477
1478 const int hexBufSize = (numColumns*8)+1;
1479 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1480 for (int i=0; i<numDashes; i++) ret += '-';
1481 ret += '\n';
1482 if (buf)
1483 {
1484 char * ascBuf = newnothrow_array(char, numColumns+1);
1485 char * hexBuf = newnothrow_array(char, hexBufSize);
1486 if ((ascBuf)&&(hexBuf))
1487 {
1488 ascBuf[0] = hexBuf[0] = '\0';
1489
1490 uint32 idx = 0;
1491 while(idx<numBytes)
1492 {
1493 const uint8 c = buf[idx];
1494 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1495 const size_t hexBufLen = strlen(hexBuf);
1496 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1497 idx++;
1498 if ((idx%numColumns) == 0) FlushStringAsciiChars(ret, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1499 }
1500 const uint32 leftovers = (numBytes%numColumns);
1501 if (leftovers > 0) FlushStringAsciiChars(ret, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1502 }
1503 else WARN_OUT_OF_MEMORY;
1504
1505 delete [] ascBuf;
1506 delete [] hexBuf;
1507 }
1508 else ret += "NULL buffer";
1509 }
1510 return ret;
1511 }
1512
1513 String HexBytesToAnnotatedString(const Queue<uint8> & buf, const char * optDesc, uint32 numColumns)
1514 {
1515 String ret;
1516
1517 const uint32 numBytes = buf.GetNumItems();
1518 if (numColumns == 0)
1519 {
1520 // A simple, single-line format
1521 if (optDesc) {ret += optDesc; ret += ": ";}
1522 ret += '[';
1523 for (uint32 i=0; i<numBytes; i++) {char xbuf[32]; muscleSprintf(xbuf, "%s%02x", (i==0)?"":" ", (unsigned int) buf[i]); ret += xbuf;}
1524 ret += ']';
1525 }
1526 else
1527 {
1528 // A more useful columnar format with ASCII sidebar
1529 char headBuf[256];
1530 muscleSprintf(headBuf, "--- %s (" UINT32_FORMAT_SPEC " bytes): ", ((optDesc)&&(strlen(optDesc)<200))?optDesc:"", numBytes);
1531 ret += headBuf;
1532
1533 const int hexBufSize = (numColumns*8)+1;
1534 const int numDashes = 8+(4*numColumns)-(int)strlen(headBuf);
1535 for (int i=0; i<numDashes; i++) ret += '-';
1536 ret += '\n';
1537 char * ascBuf = newnothrow_array(char, numColumns+1);
1538 char * hexBuf = newnothrow_array(char, hexBufSize);
1539 if ((ascBuf)&&(hexBuf))
1540 {
1541 ascBuf[0] = hexBuf[0] = '\0';
1542
1543 uint32 idx = 0;
1544 while(idx<numBytes)
1545 {
1546 const uint8 c = buf[idx];
1547 ascBuf[idx%numColumns] = muscleInRange(c,(uint8)' ',(uint8)'~')?c:'.';
1548 const size_t hexBufLen = strlen(hexBuf);
1549 muscleSnprintf(hexBuf+hexBufLen, hexBufSize-hexBufLen, "%s%02x", ((idx%numColumns)==0)?"":" ", (unsigned int)(((uint32)buf[idx])&0xFF));
1550 idx++;
1551 if ((idx%numColumns) == 0) FlushStringAsciiChars(ret, idx-numColumns, ascBuf, hexBuf, numColumns, numColumns);
1552 }
1553 const uint32 leftovers = (numBytes%numColumns);
1554 if (leftovers > 0) FlushStringAsciiChars(ret, numBytes-leftovers, ascBuf, hexBuf, leftovers, numColumns);
1555 }
1556 else WARN_OUT_OF_MEMORY;
1557
1558 delete [] ascBuf;
1559 delete [] hexBuf;
1560 }
1561 return ret;
1562 }
1563
1564 String HexBytesToAnnotatedString(const ByteBuffer & bb, const char * optDesc, uint32 numColumns)
1565 {
1566 return HexBytesToAnnotatedString(bb.GetBuffer(), bb.GetNumBytes(), optDesc, numColumns);
1567 }
1568
1569 String HexBytesToAnnotatedString(const ConstByteBufferRef & bbRef, const char * optDesc, uint32 numColumns)
1570 {
1571 return HexBytesToAnnotatedString(bbRef()?bbRef()->GetBuffer():NULL, bbRef()?bbRef()->GetNumBytes():0, optDesc, numColumns);
1572 }
1573
1574 DebugTimer :: DebugTimer(const String & title, uint64 mlt, uint32 startMode, int debugLevel)
1575 : _currentMode(startMode+1)
1576 , _title(title)
1577 , _minLogTime(mlt)
1578 , _debugLevel(debugLevel)
1579 , _enableLog(true)
1580 {
1581 SetMode(startMode);
1582 _startTime = MUSCLE_DEBUG_TIMER_CLOCK; // re-set it here so that we don't count the Hashtable initialization!
1583 }
1584
1585 DebugTimer :: ~DebugTimer()
1586 {
1587 if (_enableLog)
1588 {
1589 // Finish off the current mode
1590 uint64 * curElapsed = _modeToElapsedTime.Get(_currentMode);
1591 if (curElapsed) *curElapsed += MUSCLE_DEBUG_TIMER_CLOCK-_startTime;
1592
1593 // And print out our stats
1594 for (HashtableIterator<uint32, uint64> iter(_modeToElapsedTime); iter.HasData(); iter++)
1595 {
1596 const uint64 nextTime = iter.GetValue();
1597 if (nextTime >= _minLogTime)
1598 {
1599 if (_debugLevel >= 0)
1600 {
1601 if (nextTime >= 1000) LogTime(_debugLevel, "%s: mode " UINT32_FORMAT_SPEC ": " UINT64_FORMAT_SPEC " milliseconds elapsed\n", _title(), iter.GetKey(), nextTime/1000);
1602 else LogTime(_debugLevel, "%s: mode " UINT32_FORMAT_SPEC ": " UINT64_FORMAT_SPEC " microseconds elapsed\n", _title(), iter.GetKey(), nextTime);
1603 }
1604 else
1605 {
1606 // For cases where we don't want to call LogTime()
1607 if (nextTime >= 1000) printf("%s: mode " UINT32_FORMAT_SPEC ": " UINT64_FORMAT_SPEC " milliseconds elapsed\n", _title(), iter.GetKey(), nextTime/1000);
1608 else printf("%s: mode " UINT32_FORMAT_SPEC ": " UINT64_FORMAT_SPEC " microseconds elapsed\n", _title(), iter.GetKey(), nextTime);
1609 }
1610 }
1611 }
1612 }
1613 }
1614
1615 /** Gotta define this myself, since atoll() isn't standard. :^(
1616 * Note that this implementation doesn't handle negative numbers!
1617 */
1618 uint64 Atoull(const char * str)
1619 {
1620 TCHECKPOINT;
1621
1622 const char * s = str;
1623 if (muscleInRange(*s, '0', '9') == false) return 0;
1624
1625 uint64 base = 1;
1626 uint64 ret = 0;
1627
1628 // Move to the last digit in the number
1629 while(muscleInRange(*s, '0', '9')) s++;
1630
1631 // Then iterate back to the beginning, tabulating as we go
1632 while((--s >= str)&&(*s >= '0')&&(*s <= '9'))
1633 {
1634 ret += base * ((uint64)(*s-'0'));
1635 base *= (uint64)10;
1636 }
1637 return ret;
1638 }
1639
1640 // Returns the integer value of the specified hex char, or -1 if c is not a valid hex char (i.e. not 0-9, a-f, or A-F)
1641 static int ParseHexDigit(char c)
1642 {
1643 if (muscleInRange(c, '0', '9')) return (c-'0');
1644 else if (muscleInRange(c, 'a', 'f')) return 10+(c-'a');
1645 else if (muscleInRange(c, 'A', 'F')) return 10+(c-'A');
1646 else return -1;
1647 }
1648
1649 uint64 Atoxll(const char * str)
1650 {
1651 if ((str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) str += 2; // skip any optional "0x" prefix in "0xDEADBEEF"
1652
1653 const char * s = str;
1654 if (ParseHexDigit(*s) < 0) return 0;
1655
1656 uint64 base = 1;
1657 uint64 ret = 0;
1658
1659 // Move to the last digit in the number
1660 while(ParseHexDigit(*s) >= 0) s++;
1661
1662 // Then iterate back to the beginning, tabulating as we go
1663 while((--s >= str)&&(ParseHexDigit(*s) >= 0))
1664 {
1665 ret += base * ((uint64)ParseHexDigit(*s));
1666 base *= (uint64)16;
1667 }
1668 return ret;
1669 }
1670
1671 int64 Atoll(const char * str)
1672 {
1673 TCHECKPOINT;
1674
1675 bool negative = false;
1676 const char * s = str;
1677 while(*s == '-')
1678 {
1679 negative = (negative == false);
1680 s++;
1681 }
1682 const int64 ret = (int64) Atoull(s);
1683 return negative ? -ret : ret;
1684 }
1685
1686 /** Set the timer to record elapsed time to a different mode. */
1687 void DebugTimer :: SetMode(uint32 newMode)
1688 {
1689 if (newMode != _currentMode)
1690 {
1691 uint64 * curElapsed = _modeToElapsedTime.Get(_currentMode);
1692 if (curElapsed) *curElapsed += MUSCLE_DEBUG_TIMER_CLOCK-_startTime;
1693
1694 _currentMode = newMode;
1695 (void) _modeToElapsedTime.GetOrPut(_currentMode, 0);
1696 _startTime = MUSCLE_DEBUG_TIMER_CLOCK;
1697 }
1698 }
1699
1700 #ifdef MUSCLE_SINGLE_THREAD_ONLY
1701 bool IsCurrentThreadMainThread() {return true;}
1702 #else
1703 bool IsCurrentThreadMainThread()
1704 {
1705 if (_threadSetupCount > 0) return (_mainThreadID == muscle_thread_id::GetCurrentThreadID());
1706 else
1707 {
1708 MCRASH("IsCurrentThreadMainThread() cannot be called unless there is a CompleteSetupSystem object on the stack!");
1709 return false; // to shut the compiler up
1710 }
1711 }
1712 #endif
1713
1714 uint32 CalculateHashCode(const void * key, uint32 numBytes, uint32 seed)
1715 {
1716 #define MURMUR2_MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
1717 const uint32 m = 0x5bd1e995;
1718 const int32 r = 24;
1719
1720 const unsigned char * data = (const unsigned char *)key;
1721 uint32 h = seed ^ numBytes;
1722 const uint32 align = ((uint32)((uintptr)data)) & 3;
1723 if ((align!=0)&&(numBytes >= 4))
1724 {
1725 // Pre-load the temp registers
1726 uint32 t = 0, d = 0;
1727 switch(align)
1728 {
1729 case 1: t |= data[2] << 16; // fall through!
1730 case 2: t |= data[1] << 8; // fall through!
1731 case 3: t |= data[0]; // fall through!
1732 }
1733
1734 t <<= (8 * align);
1735 data += 4-align;
1736 numBytes -= 4-align;
1737
1738 int32 sl = 8 * (4-align);
1739 int32 sr = 8 * align;
1740
1741 // Mix
1742 while(numBytes >= 4)
1743 {
1744 d = *(uint32 *)data;
1745 t = (t >> sr) | (d << sl);
1746
1747 uint32 k = t;
1748 MURMUR2_MIX(h,k,m);
1749 t = d;
1750
1751 data += 4;
1752 numBytes -= 4;
1753 }
1754
1755 // Handle leftover data in temp registers
1756 d = 0;
1757 if(numBytes >= align)
1758 {
1759 switch(align)
1760 {
1761 case 3: d |= data[2] << 16; // fall through
1762 case 2: d |= data[1] << 8; // fall through
1763 case 1: d |= data[0]; // fall through
1764 }
1765
1766 uint32 k = (t >> sr) | (d << sl);
1767 MURMUR2_MIX(h,k,m);
1768
1769 data += align;
1770 numBytes -= align;
1771
1772 //----------
1773 // Handle tail bytes
1774 switch(numBytes)
1775 {
1776 case 3: h ^= data[2] << 16; // fall through!
1777 case 2: h ^= data[1] << 8; // fall through!
1778 case 1: h ^= data[0]; // fall through!
1779 h *= m;
1780 };
1781 }
1782 else
1783 {
1784 switch(numBytes)
1785 {
1786 case 3: d |= data[2] << 16; // fall through!
1787 case 2: d |= data[1] << 8; // fall through!
1788 case 1: d |= data[0]; // fall through!
1789 case 0: h ^= (t >> sr) | (d << sl);
1790 h *= m;
1791 }
1792 }
1793
1794 h ^= h >> 13;
1795 h *= m;
1796 h ^= h >> 15;
1797
1798 return h;
1799 }
1800 else
1801 {
1802 while(numBytes >= 4)
1803 {
1804 uint32 k = *(uint32 *)data;
1805 MURMUR2_MIX(h,k,m);
1806 data += 4;
1807 numBytes -= 4;
1808 }
1809
1810 //----------
1811 // Handle tail bytes
1812
1813 switch(numBytes)
1814 {
1815 case 3: h ^= data[2] << 16; // fall through!
1816 case 2: h ^= data[1] << 8; // fall through!
1817 case 1: h ^= data[0]; // fall through!
1818 h *= m;
1819 };
1820
1821 h ^= h >> 13;
1822 h *= m;
1823 h ^= h >> 15;
1824
1825 return h;
1826 }
1827 }
1828
1829 uint64 CalculateHashCode64(const void * key, unsigned int numBytes, unsigned int seed)
1830 {
1831 const uint64 m = 0xc6a4a7935bd1e995;
1832 const int r = 47;
1833
1834 uint64 h = seed ^ (numBytes * m);
1835
1836 const uint64 * data = (const uint64 *)key;
1837 const uint64 * end = data + (numBytes/sizeof(uint64));
1838
1839 while(data != end)
1840 {
1841 uint64 k = *data++;
1842 k *= m;
1843 k ^= k >> r;
1844 k *= m;
1845 h ^= k;
1846 h *= m;
1847 }
1848
1849 const unsigned char * data2 = (const unsigned char*)data;
1850 switch(numBytes & 7)
1851 {
1852 case 7: h ^= uint64(data2[6]) << 48; // fall through!
1853 case 6: h ^= uint64(data2[5]) << 40; // fall through!
1854 case 5: h ^= uint64(data2[4]) << 32; // fall through!
1855 case 4: h ^= uint64(data2[3]) << 24; // fall through!
1856 case 3: h ^= uint64(data2[2]) << 16; // fall through!
1857 case 2: h ^= uint64(data2[1]) << 8; // fall through!
1858 case 1: h ^= uint64(data2[0]); // fall through!
1859 h *= m;
1860 }
1861
1862 h ^= h >> r;
1863 h *= m;
1864 h ^= h >> r;
1865 return h;
1866 }
1867
1868 #ifdef MUSCLE_ENABLE_OBJECT_COUNTING
1869
1870 static ObjectCounterBase * _firstObjectCounter = NULL;
1871
1872 void ObjectCounterBase :: PrependObjectCounterBaseToGlobalCountersList()
1873 {
1874 _nextCounter = _firstObjectCounter;
1875 if (_firstObjectCounter) _firstObjectCounter->_prevCounter = this;
1876 _firstObjectCounter = this;
1877 }
1878
1879 void ObjectCounterBase :: RemoveObjectCounterBaseFromGlobalCountersList()
1880 {
1881 if (_firstObjectCounter == this) _firstObjectCounter = _nextCounter;
1882 if (_prevCounter) _prevCounter->_nextCounter = _nextCounter;
1883 if (_nextCounter) _nextCounter->_prevCounter = _prevCounter;
1884 }
1885
1886 ObjectCounterBase :: ObjectCounterBase()
1887 : _prevCounter(NULL)
1888 , _nextCounter(NULL)
1889 {
1890 if (_muscleLock)
1891 {
1892 MutexGuard mg(*_muscleLock);
1893 PrependObjectCounterBaseToGlobalCountersList();
1894 }
1895 else PrependObjectCounterBaseToGlobalCountersList();
1896 }
1897
1898 ObjectCounterBase :: ~ObjectCounterBase()
1899 {
1900 if (_muscleLock)
1901 {
1902 MutexGuard mg(*_muscleLock);
1903 RemoveObjectCounterBaseFromGlobalCountersList();
1904 }
1905 else RemoveObjectCounterBaseFromGlobalCountersList();
1906 }
1907
1908 #endif
1909
1910 status_t GetCountedObjectInfo(Hashtable<const char *, uint32> & results)
1911 {
1912 #ifdef MUSCLE_ENABLE_OBJECT_COUNTING
1913 Mutex * m = _muscleLock;
1914 if ((m==NULL)||(m->Lock() == B_NO_ERROR))
1915 {
1916 status_t ret;
1917
1918 const ObjectCounterBase * oc = _firstObjectCounter;
1919 while(oc)
1920 {
1921 (void) results.Put(oc->GetCounterTypeName(), oc->GetCount()).IsError(ret);
1922 oc = oc->GetNextCounter();
1923 }
1924
1925 if (m) m->Unlock();
1926 return ret;
1927 }
1928 else return B_LOCK_FAILED;
1929 #else
1930 (void) results;
1931 return B_UNIMPLEMENTED;
1932 #endif
1933 }
1934
1935 void PrintCountedObjectInfo()
1936 {
1937 #ifdef MUSCLE_ENABLE_OBJECT_COUNTING
1938 Hashtable<const char *, uint32> table;
1939 if (GetCountedObjectInfo(table) == B_NO_ERROR)
1940 {
1941 table.SortByKey(); // so they'll be printed in alphabetical order
1942 printf("Counted Object Info report follows: (" UINT32_FORMAT_SPEC " types counted)\n", table.GetNumItems());
1943 for (HashtableIterator<const char *, uint32> iter(table); iter.HasData(); iter++) printf(" %6" UINT32_FORMAT_SPEC_NOPERCENT " %s\n", iter.GetValue(), iter.GetKey());
1944 }
1945 else printf("PrintCountedObjectInfo: GetCountedObjectInfo() failed!\n");
1946 #else
1947 printf("Counted Object Info report not available, because MUSCLE was compiled without -DMUSCLE_ENABLE_OBJECT_COUNTING\n");
1948 #endif
1949 }
1950
1951 void SetMainReflectServerCatchSignals(bool enable)
1952 {
1953 _mainReflectServerCatchSignals = enable;
1954 }
1955
1956 bool GetMainReflectServerCatchSignals()
1957 {
1958 return _mainReflectServerCatchSignals;
1959 }
1960
1961 Queue<String> GetBuildFlags()
1962 {
1963 Queue<String> q;
1964
1965 #ifdef MUSCLE_ENABLE_SSL
1966 q.AddTail("MUSCLE_ENABLE_SSL");
1967 #endif
1968
1969 #ifdef MUSCLE_AVOID_CPLUSPLUS11
1970 q.AddTail("MUSCLE_AVOID_CPLUSPLUS11");
1971 #endif
1972
1973 #ifdef MUSCLE_AVOID_CPLUSPLUS11_THREADS
1974 q.AddTail("MUSCLE_AVOID_CPLUSPLUS11_THREADS");
1975 #endif
1976
1977 #ifdef MUSCLE_AVOID_CPLUSPLUS11_THREAD_LOCAL_KEYWORD
1978 q.AddTail("MUSCLE_AVOID_CPLUSPLUS11_THREAD_LOCAL_KEYWORD");
1979 #endif
1980
1981 #ifdef MUSCLE_AVOID_IPV6
1982 q.AddTail("MUSCLE_AVOID_IPV6");
1983 #endif
1984
1985 #ifdef MUSCLE_AVOID_STDINT
1986 q.AddTail("MUSCLE_AVOID_STDINT");
1987 #endif
1988
1989 #ifdef MUSCLE_SINGLE_THREAD_ONLY
1990 q.AddTail("MUSCLE_SINGLE_THREAD_ONLY");
1991 #endif
1992
1993 #ifdef MUSCLE_USE_EPOLL
1994 q.AddTail("MUSCLE_USE_EPOLL");
1995 #endif
1996
1997 #ifdef MUSCLE_USE_POLL
1998 q.AddTail("MUSCLE_USE_POLL");
1999 #endif
2000
2001 #ifdef MUSCLE_USE_KQUEUE
2002 q.AddTail("MUSCLE_USE_KQUEUE");
2003 #endif
2004
2005 #ifdef MUSCLE_MAX_ASYNC_CONNECT_DELAY_MICROSECONDS
2006 q.AddTail(String("MUSCLE_MAX_ASYNC_CONNECT_DELAY_MICROSECONDS=%1").Arg(MUSCLE_MAX_ASYNC_CONNECT_DELAY_MICROSECONDS));
2007 #endif
2008
2009 #ifdef MUSCLE_CATCH_SIGNALS_BY_DEFAULT
2010 q.AddTail("MUSCLE_CATCH_SIGNALS_BY_DEFAULT");
2011 #endif
2012
2013 #ifdef MUSCLE_USE_LIBRT
2014 q.AddTail("MUSCLE_USE_LIBRT");
2015 #endif
2016
2017 #ifdef MUSCLE_AVOID_MULTICAST_API
2018 q.AddTail("MUSCLE_AVOID_MULTICAST_API");
2019 #endif
2020
2021 #ifdef MUSCLE_DISABLE_KEEPALIVE_API
2022 q.AddTail("MUSCLE_DISABLE_KEEPALIVE_API");
2023 #endif
2024
2025 #ifdef MUSCLE_64_BIT_PLATFORM
2026 q.AddTail("MUSCLE_64_BIT_PLATFORM");
2027 #endif
2028
2029 #ifdef MUSCLE_USE_LLSEEK
2030 q.AddTail("MUSCLE_USE_LLSEEK");
2031 #endif
2032
2033 #ifdef MUSCLE_PREFER_QT_OVER_WIN32
2034 q.AddTail("MUSCLE_PREFER_QT_OVER_WIN32");
2035 #endif
2036
2037 #ifdef MUSCLE_ENABLE_MEMORY_PARANOIA
2038 q.AddTail(String("MUSCLE_ENABLE_MEMORY_PARANOIA=%1").Arg(MUSCLE_ENABLE_MEMORY_PARANOIA));
2039 #endif
2040
2041 #ifdef MUSCLE_NO_EXCEPTIONS
2042 q.AddTail("MUSCLE_NO_EXCEPTIONS");
2043 #endif
2044
2045 #ifdef MUSCLE_ENABLE_MEMORY_TRACKING
2046 q.AddTail("MUSCLE_ENABLE_MEMORY_TRACKING");
2047 #endif
2048
2049 #ifdef MUSCLE_AVOID_ASSERTIONS
2050 q.AddTail("MUSCLE_AVOID_ASSERTIONS");
2051 #endif
2052
2053 #ifdef MUSCLE_AVOID_SIGNAL_HANDLING
2054 q.AddTail("MUSCLE_AVOID_SIGNAL_HANDLING");
2055 #endif
2056
2057 #ifdef MUSCLE_AVOID_INLINE_ASSEMBLY
2058 q.AddTail("MUSCLE_AVOID_INLINE_ASSEMBLY");
2059 #endif
2060
2061 #ifdef MUSCLE_ENABLE_ZLIB_ENCODING
2062 q.AddTail("MUSCLE_ENABLE_ZLIB_ENCODING");
2063 #endif
2064
2065 #ifdef MUSCLE_TRACE_CHECKPOINTS
2066 q.AddTail(String("MUSCLE_TRACE_CHECKPOINTS=%1").Arg(MUSCLE_TRACE_CHECKPOINTS));
2067 #endif
2068
2069 #ifdef MUSCLE_DISABLE_MESSAGE_FIELD_POOLS
2070 q.AddTail("MUSCLE_DISABLE_MESSAGE_FIELD_POOLS");
2071 #endif
2072
2073 #ifdef MUSCLE_INLINE_LOGGING
2074 q.AddTail("MUSCLE_INLINE_LOGGING");
2075 #endif
2076
2077 #ifdef MUSCLE_DISABLE_LOGGING
2078 q.AddTail("MUSCLE_DISABLE_LOGGING");
2079 #endif
2080
2081 #ifdef MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS
2082 q.AddTail("MUSCLE_USE_MUTEXES_FOR_ATOMIC_OPERATIONS");
2083 #endif
2084
2085 #ifdef MUSCLE_MUTEX_POOL_SIZE
2086 q.AddTail(String("MUSCLE_MUTEX_POOL_SIZE").Arg(MUSCLE_MUTEX_POOL_SIZE));
2087 #endif
2088
2089 #ifdef MUSCLE_POWERPC_TIMEBASE_HZ
2090 q.AddTail(String("MUSCLE_POWERPC_TIMEBASE_HZ=%1").Arg(MUSCLE_POWERPC_TIMEBASE_HZ));
2091 #endif
2092
2093 #ifdef MUSCLE_USE_PTHREADS
2094 q.AddTail("MUSCLE_USE_PTHREADS");
2095 #endif
2096
2097 #ifdef MUSCLE_USE_PTHREADS
2098 q.AddTail("MUSCLE_USE_CPLUSPLUS11_THREADS");
2099 #endif
2100
2101 #ifdef MUSCLE_DEFAULT_TCP_STALL_TIMEOUT
2102 q.AddTail("MUSCLE_DEFAULT_TCP_STALL_TIMEOUT=%1").Arg(MUSCLE_DEFAULT_TCP_STALL_TIMEOUT);
2103 #endif
2104
2105 #ifdef MUSCLE_FD_SETSIZE
2106 q.AddTail(String("MUSCLE_FD_SETSIZE=%1").Arg(MUSCLE_FD_SETSIZE));
2107 #endif
2108
2109 #ifdef MUSCLE_AVOID_NEWNOTHROW
2110 q.AddTail("MUSCLE_AVOID_NEWNOTHROW");
2111 #endif
2112
2113 #ifdef MUSCLE_AVOID_FORKPTY
2114 q.AddTail("MUSCLE_AVOID_FORKPTY");
2115 #endif
2116
2117 #ifdef MUSCLE_HASHTABLE_DEFAULT_CAPACITY
2118 q.AddTail(String("MUSCLE_HASHTABLE_DEFAULT_CAPACITY=%1").Arg(MUSCLE_HASHTABLE_DEFAULT_CAPACITY));
2119 #endif
2120
2121 #ifdef SMALL_QUEUE_SIZE
2122 q.AddTail(String("SMALL_QUEUE_SIZE=%1").Arg(SMALL_QUEUE_SIZE));
2123 #endif
2124
2125 #ifdef SMALL_MUSCLE_STRING_LENGTH
2126 q.AddTail(String("SMALL_MUSCLE_STRING_LENGTH=%1").Arg(SMALL_MUSCLE_STRING_LENGTH));
2127 #endif
2128
2129 #ifdef MUSCLE_USE_QUERYPERFORMANCECOUNTER
2130 q.AddTail("MUSCLE_USE_QUERYPERFORMANCECOUNTER");
2131 #endif
2132
2133 #ifdef MUSCLE_INCLUDE_SOURCE_LOCATION_IN_LOGTIME
2134 q.AddTail("MUSCLE_INCLUDE_SOURCE_LOCATION_IN_LOGTIME");
2135 #endif
2136
2137 #ifdef MUSCLE_LOG_VERBOSE_SOURCE_LOCATIONS
2138 q.AddTail("MUSCLE_LOG_VERBOSE_SOURCE_LOCATIONS");
2139 #endif
2140
2141 #ifdef MUSCLE_WARN_ABOUT_LOUSY_HASH_FUNCTIONS
2142 q.AddTail(String("MUSCLE_WARN_ABOUT_LOUSY_HASH_FUNCTIONS=%1").Arg(MUSCLE_WARN_ABOUT_LOUSY_HASH_FUNCTIONS));
2143 #endif
2144
2145 #ifdef MUSCLE_ENABLE_DEADLOCK_FINDER
2146 q.AddTail("MUSCLE_ENABLE_DEADLOCK_FINDER");
2147 #endif
2148
2149 #ifdef MUSCLE_DEFAULT_RUNTIME_DISABLE_DEADLOCK_FINDER
2150 q.AddTail("MUSCLE_DEFAULT_RUNTIME_DISABLE_DEADLOCK_FINDER");
2151 #endif
2152
2153 #ifdef MUSCLE_POOL_SLAB_SIZE
2154 q.AddTail(String("MUSCLE_POOL_SLAB_SIZE=%1").Arg(MUSCLE_POOL_SLAB_SIZE));
2155 #endif
2156
2157 #ifdef MUSCLE_AVOID_BITSTUFFING
2158 q.AddTail("MUSCLE_AVOID_BITSTUFFING");
2159 #endif
2160
2161 #ifdef MUSCLE_AVOID_CHECK_THREAD_STACK_USAGE
2162 q.AddTail("MUSCLE_AVOID_CHECK_THREAD_STACK_USAGE");
2163 #endif
2164
2165 #ifdef MUSCLE_ENABLE_OBJECT_COUNTING
2166 q.AddTail("MUSCLE_ENABLE_OBJECT_COUNTING");
2167 #endif
2168
2169 #ifdef MUSCLE_AVOID_THREAD_LOCAL_STORAGE
2170 q.AddTail("MUSCLE_AVOID_THREAD_LOCAL_STORAGE");
2171 #endif
2172
2173 #ifdef MUSCLE_AVOID_MINIMIZED_HASHTABLES
2174 q.AddTail("MUSCLE_AVOID_MINIMIZED_HASHTABLES");
2175 #endif
2176
2177 #ifdef MUSCLE_AVOID_THREAD_SAFE_HASHTABLE_ITERATORS
2178 q.AddTail("MUSCLE_AVOID_THREAD_SAFE_HASHTABLE_ITERATORS");
2179 #endif
2180
2181 #ifdef MUSCLE_FAKE_SHARED_MEMORY
2182 q.AddTail("MUSCLE_FAKE_SHARED_MEMORY");
2183 #endif
2184
2185 #ifdef MUSCLE_COUNT_STRING_COPY_OPERATIONS
2186 q.AddTail("MUSCLE_COUNT_STRING_COPY_OPERATIONS");
2187 #endif
2188
2189 #ifdef MUSCLE_AVOID_XENOMAI
2190 q.AddTail("MUSCLE_AVOID_XENOMAI");
2191 #endif
2192
2193 #ifdef DEBUG_LARGE_MEMORY_ALLOCATIONS_THRESHOLD
2194 q.AddTail(String("DEBUG_LARGE_MEMORY_ALLOCATIONS_THRESHOLD=%1").Arg(DEBUG_LARGE_MEMORY_ALLOCATIONS_THRESHOLD));
2195 #endif
2196
2197 #ifdef MUSCLE_AVOID_AUTOCHOOSE_SWAP
2198 q.AddTail("MUSCLE_AVOID_AUTOCHOOSE_SWAP");
2199 #endif
2200
2201 #ifdef MUSCLE_RECORD_REFCOUNTABLE_ALLOCATION_LOCATIONS
2202 q.AddTail("MUSCLE_RECORD_REFCOUNTABLE_ALLOCATION_LOCATIONS");
2203 #endif
2204
2205 #ifdef MUSCLE_ENABLE_QTHREAD_EVENT_LOOP_INTEGRATION
2206 q.AddTail("MUSCLE_ENABLE_QTHREAD_EVENT_LOOP_INTEGRATION");
2207 #endif
2208
2209 #ifdef MUSCLE_USE_DUMMY_DETECT_NETWORK_CONFIG_CHANGES_SESSION
2210 q.AddTail("MUSCLE_USE_DUMMY_DETECT_NETWORK_CONFIG_CHANGES_SESSION");
2211 #endif
2212
2213 #ifdef MUSCLE_ENABLE_AUTHORIZATION_EXECUTE_WITH_PRIVILEGES
2214 q.AddTail("MUSCLE_ENABLE_AUTHORIZATION_EXECUTE_WITH_PRIVILEGES");
2215 #endif
2216
2217 return q;
2218 }
2219
2220 void LogBuildFlags(int logLevel)
2221 {
2222 if (GetMaxLogLevel() >= logLevel)
2223 {
2224 Queue<String> flagStrs = GetBuildFlags();
2225 for (uint32 i=0; i<flagStrs.GetNumItems(); i++) LogTime(logLevel, "MUSCLE code was compiled with preprocessor flag -D%s\n", flagStrs[i]());
2226 }
2227 }
2228
2229 void PrintBuildFlags()
2230 {
2231 Queue<String> flagStrs = GetBuildFlags();
2232 for (uint32 i=0; i<flagStrs.GetNumItems(); i++) printf("MUSCLE code was compiled with preprocessor flag -D%s\n", flagStrs[i]());
2233 }
2234
2235 uint64 GetProcessMemoryUsage()
2236 {
2237 #if defined(__linux__)
2238 FILE* fp = fopen("/proc/self/statm", "r");
2239 if (fp)
2240 {
2241 char buf[256];
2242 if (fgets(buf, sizeof(buf), fp) == NULL) buf[0] = '\0';
2243 fclose(fp);
2244
2245 // skip past the first number (total program size) and return Rss
2246 const char * firstSpace = strchr(buf, ' ');
2247 if (firstSpace) return Atoull(firstSpace+1)*sysconf(_SC_PAGESIZE);
2248 }
2249 #elif defined(__APPLE__)
2250 mach_task_basic_info_data_t taskinfo; memset(&taskinfo, 0, sizeof(taskinfo));
2251 mach_msg_type_number_t outCount = MACH_TASK_BASIC_INFO_COUNT;
2252 if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&taskinfo, &outCount) == KERN_SUCCESS) return taskinfo.resident_size;
2253 #elif defined(WIN32) && !defined(__MINGW32__)
2254 PROCESS_MEMORY_COUNTERS pmc;
2255 if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) return pmc.WorkingSetSize;
2256 #endif
2257 return 0;
2258 }
2259
2260 } // end namespace muscle