"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