《Note --- Unreal --- MemPro (CONTINUE... ...)》

Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用”Launch” button进行加载自己待检测的application,目前支持的平台为Windows,Unix, Linux, OSX, IOS, GCC;但是按照官网的说法,其虽然只能运行到WIN上,但是根据TCP协议传输dump的方式也可以和其他平台的app进行连接;

关于内存泄露,按照官方文档中的说法,其检测内存泄露的算法主要是两种,一种是在抓取dump时候未被引用的变量会被认定为泄露,一种是在抓取的时候频繁进行的堆栈被认为是可疑的泄露;由于后者需要平台相关的callstack堆栈抓取支持,所以现在从其代码看来,还不支持PS4和XBoxOne, 这部分的官网地址为:http://www.puredevsoftware.com/MemProUserGuide/LeaksView.htm

关于支持的平台:Windows, Unix, Linux, OSX, iOS, gcc; Note: MemPro only runs on Windows but can connect to apps on these other platforms;

其官方网址为:http://www.puredevsoftware.com/mempro/index.htm

其官方文档为:http://www.puredevsoftware.com/MemProUserGuide/Introduction.htm

安装完GUI软件可以找到相关源码和测试程序,其readme简单介绍了使用方法,内容为:

-----------------------------------------------------------------------
MemPro
----------------------------------------------------------------------- Copyright (c) , All Right Reserved
Author: Stewart Lynch
date: //
Website: www.puredevsoftware.com
Version: 1.3.7.0 -----------------------------------------------------------------------
MemPro is a Windows based native memory profiler for C++. This README is taken from the setup page in the help chm file. ------------------------------------
Setup To allow MemPro to connect with your application you must compile your app
with the MemProLib code and call the tracking functions when allocating
memory. There are three main ways you can do this: * Include the MemPro.cpp file in one of your source cpp files
* Compile and Link against the MemProLib.lib
* Link with MemProDll.dll The MemProLib library can be found in the source code installation folder
that was set in the installation, the default is:
C:\Program Files\PureDevSoftware\MemPro Note: if you are profiling an application with multiple dlls you must use
the third option and link MemProDll.dll. Note: If you are including MemPro.cpp you do NOT need to link to the static library. ------------------------------------
Including MemPro.cpp This is the recommended way of embedding the code. It is simple, and easy to comment
out when not needed. It is also the most portable solution. Add these three lines of code to your main cpp source file: //#define WAIT_FOR_CONNECT true
#define OVERRIDE_NEW_DELETE
#include "MemPro.cpp" <-- include the CPP (yes, you are including the cpp file) the cpp file can be found here:
C:\Program Files\PureDevSoftware\MemPro\MemProLib\src The WAIT_FOR_CONNECT line is optional. If defined to true your application will block
on startup until MemPro has connected. This allows you to be sure that you are tracking
every single allocation. And that's it! ------------------------------------
Linking to the MemProLib library If you prefer to link to the MemPro library, include the MemPro.hpp in your main.cpp //#define WAIT_FOR_CONNECT true
#define OVERRIDE_NEW_DELETE
#include "MemPro.hpp" <-- include the HPP And link to one of the pre-built libraries in the lib folder. the header file can be found here:
C:\Program Files\PureDevSoftware\MemPro\MemProLib\src The lib files can be found here
C:\Program Files\PureDevSoftware\MemPro\MemProLib\lib If none of the pre-built libraries are suitable you can build your own MemProLib from
the source code in the src file. MemProLib builds on virtually any platform and OS. The
MemProLib source code can be found here:
C:\Program Files\PureDevSoftware\MemPro\MemProLib\src ------------------------------------
Linking to the MemProLib Dll Add these two lines to a cpp source file in each dll that you want to profile #define OVERRIDE_NEW_DELETE
Include "MemProDll.hpp" Copy the MemProDLL.dll file to your exe directory. The header file can be found here:
C:\Program Files\PureDevSoftware\MemPro\MemProDll\include The dll and lib files are here:
C:\Program Files\PureDevSoftware\MemPro\MemProDll\bin MemProDll.hpp includes a pragma telling the linker to link to MemProDll.lib. This
adds a dependency to the dll. Please make sure the linker can find the lib file
by adding the necessary path or modifying the pragma. Note: Make sure that MemProDll.hpp is included only _once_ in each dll. Put it in
the main source file, do not put it into a header that is included in multiple places. ------------------------------------
Include and Library Paths The installer automatically adds the include and library paths to the INCLUDE and
LIB environment variables. However, the IDE does not use these variables unless
run with the /useenv command line switch. So you'll probably want to add the path
in the global property sheet in the IDE. ------------------------------------
If you have already overridden new and delete In the above solutions the OVERRIDE_NEW_DELETE define tells MemPro to override new
and delete with its tracking hooks inserted. If you have already overridden
new and delete (maybe for your own memory manager) you will need to insert the
MemPro hooks into your overridden functions: Include MemPro.cpp as before but don't define OVERRIDE_NEW_DELETE. Instead use the
MemPro::TrackAlloc and MemPro::TrackFree functions #include "MemPro.hpp" // or MemProDll.hpp if linking to MemProDll.dll bool g_WaitForConnect = false; void* operator new(size_t size)
{
void* p = YourInternalAlloc(size);
MemPro::TrackAlloc(p, size, g_WaitForConnect);
return p;
} void operator delete(void* p)
{
MemPro::TrackFree(p, g_WaitForConnect);
YourInternalFree(p);
} void* operator new[](size_t size)
{
void* p = YourInternalAlloc(size);
MemPro::TrackAlloc(p, size, g_WaitForConnect);
return p;
} void operator delete[](void* p)
{
MemPro::TrackFree(p, g_WaitForConnect);
YourInternalFree(p);
} The g_WaitForConnect bool specifies whether the call blocks until the MemPro app has
connected. This is useful for making sure absolutely every allocation is being tracked. ------------------------------------
What if I can't use a winsock connection in my app? MemProLib uses a winsock TCP connection to communicate with MemPro. If for some reason
this isn't possible in your application (no network connection for example) then you
can still use MemPro. Instead of connecting to your application over TCP you can tell MemProLib to write out
a dump file of all allocations. This dump file can then be opened in MemPro and analyised
just like any other mempro file. To enable allocation dumping uncomment this line in MemPro.hpp //#define WRITE_DUMP _T("allocs.mempro_dump") When this define is enabled the specified file will be created and all operations will be written
to this file instead of being set over the network. The define also removes any dependency on
windows sockets, so you should be able to use it in any environment. This file can get pretty
big, so please ensure you have enough disk space. Note: To avoid linker errors when overriding new/delete, make sure that MemPro.cpp is included
before any system headers that also override new/delete. You may need to turn off any pre-compiled
headers for that file. You may also need to do a full re-compile of your app to avoid multiple
defined new and delete function warnings. ------------------------------------
If you have any problems setting up MemProLib: * please read the Help chm document
* see the FAQ on the website http://www.puredevsoftware.com/mempro_faq.htm
* email slynch@puredevsoftware.com Stewart Lynch
PureDev Software.

===============================================================================================================================================================

关于泄露检测方面,官方给出信息:

MemPro tracks leaks in three ways:

  • Allocations that are not freed on exit.
  • Allocations that are not referenced by anything else in the process.
  • Allocation callstacks that have specific memory allocation patterns

Unreferenced Allocations

Unreferenced allocations are:

Any allocations that have not been freed when the app are exited

Any allocations that are not referenced by anything else in memory
(note: To use this feature you must take a full snapshot).

The latter type of unreferenced allocations
can be detected while the application is still running. MemPro will take a
snapshot of the entire process memory and scan it for pointers to allocations.
Any allocations that MemPro can't find a pointer to are considered as leaked.

Suspected Leaks

MemPro analyses the allocation patterns of
all callstacks. Allocations are grouped by the callstack. Simply put, if a
callstack is constantly allocating memory and never freeing it then the
callstack graph will look like a diagonal line (bottom left to top right).
MemPro uses a set of heuristics to analyse the callstack graph to see how much
it looks like a leak and then gives that callstack a score from 0 to 100, 100
being a definite leak. Callstack graphs are normalised, so only the shape of
the graph should be taken into consideration.

MemPro will probably bring up some false
positives, to eliminate these you can use the exclusion filters discussed below
and the minimum leak score.

By default MemPro will only list the first
500 allocations. This is to keep the GUI responsive. This limit can be changed
in the settings.

======================================================================================================================================================================

MemPro最简单的使用方法:

Insert these two lines into your code:

#define OVERRIDE_NEW_DELETE
         #include "MemPro.cpp"

You will then be able to connect to your
app using MemPro.exe.

Once connected MemPro will track all
allocations and frees. At any time you can take a snapshot of the entire state
of memory. These snapshots can then be viewed in a variety of ways ( http://www.puredevsoftware.com/MemProUserGuide/SnapshotViews.htm
).

测试用例:

#include <iostream>

#define OVERRIDE_NEW_DELETE
//#include "D:\ProgramFiles\PureDevSoftware\MemPro\MemProLib\src\MemPro.cpp"
#include "..\MemProLib\src\MemPro.cpp"//copy the MemPro src folder to your project using namespace std; float leakSize = 0.0;
int leakNum = ;
int* p = NULL; void main()
{
while()
{
p = new int();
leakNum++;
leakSize = leakNum*/1024.0f;
system("cls");
std::cout<<"leak size is: " << leakSize << "k";
}
}

编译通过,然后运行MemPro,在“Launch”按钮下填好该exe路径和工程路径(应该是需要工程路径来找pdb文件),点击“Launch”按钮即可;

其余的使用方式可以从ReadMe的内容中得到;

测试结果:

《Note --- Unreal --- MemPro (CONTINUE... ...)》

《Note --- Unreal --- MemPro (CONTINUE... ...)》

===============================================================================================================================================================

关于怎样将MemPro整合入UE4并且运用于多个平台的游戏:

  • 原始的MemPro.cpp和MemPro.hpp可已从安装完MenPro后的安装目录找到:
  • /*
    This software is provided 'as-is', without any express or implied warranty.
    In no event will the author(s) be held liable for any damages arising from
    the use of this software. Permission is granted to anyone to use this software for any purpose, including
    commercial applications, and to alter it and redistribute it freely, subject to
    the following restrictions: 1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution. Author: Stewart Lynch
    www.puredevsoftware.com
    slynch@puredevsoftware.com This code is released to the public domain, as explained at
    http://creativecommons.org/publicdomain/zero/1.0/ MemProLib is the library that allows the MemPro application to communicate
    with your application. ===========================================================
    SETUP
    =========================================================== * include MemPro.cpp and MemPro.hpp into your project. * Link with Dbghelp.lib and Ws2_32.lib - these are needed for the callstack trace and the network connection * Connect to your app with the MemPro
    */ //------------------------------------------------------------------------
    // MemPro.hpp
    //------------------------------------------------------------------------
    /*
    MemPro
    Version: 1.3.7.0
    */
    //------------------------------------------------------------------------
    #ifndef MEMPRO_MEMPRO_H_INCLUDED
    #define MEMPRO_MEMPRO_H_INCLUDED //------------------------------------------------------------------------
    #define ENABLE_MEMPRO // **** enable/disable MemPro here! **** //------------------------------------------------------------------------
    // macros for tracking allocs that define to nothing if disabled
    #ifdef ENABLE_MEMPRO
    #ifndef WAIT_FOR_CONNECT
    #define WAIT_FOR_CONNECT false
    #endif
    #define MEMPRO_TRACK_ALLOC(p, size) MemPro::TrackAlloc(p, size, WAIT_FOR_CONNECT)
    #define MEMPRO_TRACK_FREE(p) MemPro::TrackFree(p, WAIT_FOR_CONNECT)
    #else
    #define MEMPRO_TRACK_ALLOC(p, size) ((void)0)
    #define MEMPRO_TRACK_FREE(p) ((void)0)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    // Some platforms have problems initialising winsock from global constructors,
    // to help get around this problem MemPro waits this amount of time before
    // initialising. Allocs and freed that happen during this time are stored in
    // a temporary buffer.
    #define MEMPRO_INIT_DELAY 100 //------------------------------------------------------------------------
    // MemPro waits this long before giving up on a connection after initialisation
    #define MEMPRO_CONNECT_TIMEOUT 500 //------------------------------------------------------------------------
    #include <stdlib.h> //------------------------------------------------------------------------
    //#define WRITE_DUMP _T("allocs.mempro_dump") //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    enum PageState
    {
    Invalid = -,
    Free,
    Reserved,
    Committed
    }; //------------------------------------------------------------------------
    enum PageType
    {
    page_Unknown = -,
    page_Image,
    page_Mapped,
    page_Private
    }; //------------------------------------------------------------------------ // You don't need to call this directly, it is automatically called on the first allocation.
    // Only call this function if you want to be able to connect to your app before it has allocated any memory.
    // If wait_for_connect is true this function will block until the external MemPro app has connected,
    // this is useful to make sure that every single allocation is being tracked.
    void Initialise(bool wait_for_connect=false); void Disconnect(); // kick all current connections, but can accept more void Shutdown(); // free all resources, no more connections allowed void TrackAlloc(void* p, size_t size, bool wait_for_connect=false); void TrackFree(void* p, bool wait_for_connect=false); bool IsPaused(); void SetPaused(bool paused); // this is used for the realtime memory graph.
    void SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory); void TakeSnapshot(); // ignore these, for internal use only
    void IncRef();
    void DecRef();
    } //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    namespace
    {
    // if we are using sockets we need to flush the sockets on global teardown
    // This class is a trick to attempt to get mempro to shutdown after all other
    // global objects.
    class MemProGLobalScope
    {
    public:
    MemProGLobalScope() { MemPro::IncRef(); }
    ~MemProGLobalScope() { MemPro::DecRef(); }
    };
    static MemProGLobalScope g_MemProGLobalScope;
    }
    #endif //------------------------------------------------------------------------
    #ifdef OVERRIDE_NEW_DELETE #if defined(__APPLE__)
    // if you get linker errors about duplicatly defined symbols please add a unexport.txt
    // file to your build settings
    // see here: https://developer.apple.com/library/mac/technotes/tn2185/_index.html
    void* operator new(std::size_t size) throw(std::bad_alloc)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void* operator new(std::size_t size, const std::nothrow_t&) throw()
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete(void* p) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void operator delete(void* p, const std::nothrow_t&) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void* operator new[](std::size_t size) throw(std::bad_alloc)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void* operator new[](std::size_t size, const std::nothrow_t&) throw()
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete[](void* p) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void operator delete[](void* p, const std::nothrow_t&) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    }
    #else
    #include <malloc.h> void* operator new(size_t size)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete(void* p)
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void* operator new[](size_t size)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete[](void* p)
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    }
    #endif #endif //------------------------------------------------------------------------
    #ifdef OVERRIDE_MALLOC_FREE #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(__WIN32__) || defined(__WINDOWS__) // NOTE: for this to work, you will need to make sure you are linking STATICALLY to the crt. eg: /MTd __declspec(restrict) __declspec(noalias) void* malloc(size_t size)
    {
    void* p = HeapAlloc(GetProcessHeap(), , size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } __declspec(restrict) __declspec(noalias) void* realloc(void *p, size_t new_size)
    {
    MEMPRO_TRACK_FREE(p);
    void* p_new = HeapReAlloc(GetProcessHeap(), , p, new_size);
    MEMPRO_TRACK_ALLOC(p_new, new_size);
    return p_new;
    } __declspec(noalias) void free(void *p)
    {
    HeapFree(GetProcessHeap(), , p);
    MEMPRO_TRACK_FREE(p);
    }
    #else
    void *malloc(int size)
    {
    void* (*ptr)(int);
    void* handle = (void*)-;
    ptr = (void*)dlsym(handle, "malloc");
    if(!ptr) abort();
    void *p = (*ptr)(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void *realloc(void *p, int size)
    {
    MEMPRO_TRACK_FREE(p);
    void * (*ptr)(void *, int);
    void * handle = (void*) -;
    ptr = (void*)dlsym(handle, "realloc");
    if (!ptr) abort();
    void* p_new = (*ptr)(p, size);
    MEMPRO_TRACK_ALLOC(p_new, size);
    return p_new;
    } void free(void *p)
    {
    MEMPRO_TRACK_FREE(p);
    void* (*ptr)(void*);
    void* handle = (void*)-;
    ptr = (void*)dlsym(handle, "free");
    if (!ptr == NULL) abort();
    (*ptr)(alloc);
    }
    #endif
    #endif //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPRO_H_INCLUDED

    MemPro.hpp

    /*
    This software is provided 'as-is', without any express or implied warranty.
    In no event will the author(s) be held liable for any damages arising from
    the use of this software. Permission is granted to anyone to use this software for any purpose, including
    commercial applications, and to alter it and redistribute it freely, subject to
    the following restrictions: 1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution. Author: Stewart Lynch
    www.puredevsoftware.com
    slynch@puredevsoftware.com This code is released to the public domain, as explained at
    http://creativecommons.org/publicdomain/zero/1.0/ MemProLib is the library that allows the MemPro application to communicate
    with your application.
    */ #if FRAMEPRO_TOOLSET_UE4
    #include "CorePrivatePCH.h"
    #endif #include "MemPro.hpp" //------------------------------------------------------------------------
    // CallstackSet.cpp //------------------------------------------------------------------------
    // MemProLib.hpp
    #ifndef MEMPRO_MEMPROLIB_H_INCLUDED
    #define MEMPRO_MEMPROLIB_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    // **** The Target Platform **** // define ONE of these #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(__WIN32__) || defined(__WINDOWS__)
    #if defined(_XBOX_ONE)
    #define MEMPRO_PLATFORM_XBOXONE
    #elif defined(_XBOX)
    #define MEMPRO_PLATFORM_XBOX360
    #else
    #define MEMPRO_PLATFORM_WIN
    #endif
    #elif defined(__APPLE__)
    #define MEMPRO_PLATFORM_APPLE
    #else
    #define MEMPRO_PLATFORM_UNIX
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN) || defined(MEMPRO_PLATFORM_XBOX360) || defined(MEMPRO_PLATFORM_XBOXONE)
    #define MEMPRO_WIN_BASED_PLATFORM
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_UNIX) || defined(MEMPRO_PLATFORM_APPLE)
    #define MEMPRO_UNIX_BASED_PLATFORM
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN)
    #if defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4
    #include "AllowWindowsPlatformTypes.h"
    #endif
    #ifndef WRITE_DUMP
    #if defined(UNICODE) && !defined(_UNICODE)
    #error for unicode builds please define both UNICODE and _UNICODE. See the FAQ for more details.
    #endif
    #if defined(AF_IPX) && !defined(_WINSOCK2API_)
    #error winsock already defined. Please include winsock2.h before including windows.h or use WIN32_LEAN_AND_MEAN. See the FAQ for more info.
    #endif
    #define WIN32_LEAN_AND_MEAN #pragma warning(push)
    #pragma warning(disable : 4668)
    #include <winsock2.h>
    #pragma warning(pop) #include <ws2tcpip.h>
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0501
    #endif
    #define WINDOWS_LEAN_AND_MEAN
    #include <windows.h>
    #include <intrin.h>
    #endif
    #if defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4
    #include "HideWindowsPlatformTypes.h"
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    #include <execinfo.h>
    #include <inttypes.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <sys/time.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    #if defined(_WIN64) || defined(__LP64__) || defined(__x86_64__) || defined(__ppc64__)
    #define MEMPRO64
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_XBOXONE) && !defined(MEMPRO64)
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    #define MEMPRO_ASSERT(b) if(!(b)) DebugBreak()
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    #define MEMPRO_ASSERT(b) if(!(b)) __builtin_trap()
    #else
    #error // platform not defined
    #endif //------------------------------------------------------------------------
    #define MEMPRO_STATIC_ASSERT(expr) typedef char STATIC_ASSERT_TEST[ (expr) ] //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class Allocator
    {
    public:
    #if defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_WIN_BASED_PLATFORM)
    static void* Alloc(int size)
    {
    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
    }
    static void Free(void* p, int size)
    {
    VirtualFree(p, size, MEM_RELEASE);
    }
    #else
    static void* Alloc(int size) { return malloc(size); }
    static void Free(void* p, int size) { free(p); }
    #endif
    }; //------------------------------------------------------------------------
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    typedef __int64 int64;
    typedef unsigned __int64 uint64;
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    typedef long long int64;
    typedef unsigned long long uint64;
    #else
    #error
    #endif //------------------------------------------------------------------------
    // platform specific stuff
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    #define MEMPRO_FORCEINLINE FORCEINLINE
    #else
    #define MEMPRO_FORCEINLINE inline
    void memcpy_s(void* p_dst, int dst_len, void* p_src, int copy_len) { memcpy(p_dst, p_src, copy_len); }
    void Sleep(int ms) { usleep( * ms); }
    typedef int SOCKET;
    typedef int DWORD;
    enum SocketValues { INVALID_SOCKET = - };
    #ifndef UINT_MAX
    enum MaxValues { UINT_MAX = 0xffffffff };
    #endif
    void OutputDebugString(const char*) {}
    #define _T(s) s
    enum SocketErrorCodes { SOCKET_ERROR = - };
    typedef sockaddr_in SOCKADDR_IN;
    enum SystemDefines { MAX_PATH = };
    #endif
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPROLIB_H_INCLUDED //------------------------------------------------------------------------
    // CallstackSet.hpp
    #ifndef MEMPRO_CALLSTACKSET_H_INCLUDED
    #define MEMPRO_CALLSTACKSET_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    struct Callstack
    {
    uint64* mp_Stack;
    int m_ID;
    int m_Size;
    unsigned int m_Hash;
    }; //------------------------------------------------------------------------
    // A hash set collection for Callstack structures. Callstacks are added and
    // retreived using the stack address array as the key.
    // This class only allocates memory using virtual alloc/free to avoid going
    // back into the mian allocator.
    class CallstackSet
    {
    public:
    CallstackSet(); ~CallstackSet(); Callstack* Get(uint64* p_stack, int stack_size, unsigned int hash); Callstack* Add(uint64* p_stack, int stack_size, unsigned int hash); void Clear(); private:
    void Grow(); void Add(Callstack* p_callstack); //------------------------------------------------------------------------
    // data
    private:
    Callstack** mp_Data;
    unsigned int m_CapacityMask;
    int m_Count;
    int m_Capacity;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_CALLSTACKSET_H_INCLUDED //------------------------------------------------------------------------
    // BlockAllocator.hpp
    #ifndef MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED
    #define MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    // a very simple allocator tat allocated blocks of 64k of memory using the
    // templatized allocator.
    template<class TAllocator>
    class BlockAllocator
    {
    public:
    inline BlockAllocator(); inline void* Alloc(int size); inline void Free(void* p); //------------------------------------------------------------------------
    // data
    private:
    static const int m_BlockSize = *;
    void* mp_CurBlock;
    int m_CurBlockUsage;
    }; //------------------------------------------------------------------------
    template<class TAllocator>
    BlockAllocator<TAllocator>::BlockAllocator()
    : mp_CurBlock(NULL),
    m_CurBlockUsage()
    {
    } //------------------------------------------------------------------------
    template<class TAllocator>
    void* BlockAllocator<TAllocator>::Alloc(int size)
    {
    MEMPRO_ASSERT(size < m_BlockSize); if(!mp_CurBlock || size > m_BlockSize - m_CurBlockUsage)
    {
    mp_CurBlock = TAllocator::Alloc(m_BlockSize);
    MEMPRO_ASSERT(mp_CurBlock);
    m_CurBlockUsage = ;
    } void* p = (char*)mp_CurBlock + m_CurBlockUsage;
    m_CurBlockUsage += size; return p;
    } //------------------------------------------------------------------------
    template<class TAllocator>
    void BlockAllocator<TAllocator>::Free(void* p)
    {
    // do nothing
    }
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    const int g_InitialCapacity = ; // must be a power of 2 MemPro::BlockAllocator<Allocator> g_BlockAllocator; //------------------------------------------------------------------------
    inline bool StacksMatch(MemPro::Callstack* p_callstack, uint64* p_stack, int stack_size, unsigned int hash)
    {
    if(p_callstack->m_Size != stack_size)
    return false; if(p_callstack->m_Hash != hash)
    return false; for(int i=; i<stack_size; ++i)
    if(p_callstack->mp_Stack[i] != p_stack[i])
    return false; return true;
    }
    } //------------------------------------------------------------------------
    MemPro::CallstackSet::CallstackSet()
    : mp_Data((Callstack**)Allocator::Alloc(g_InitialCapacity*sizeof(Callstack*))),
    m_CapacityMask(g_InitialCapacity-),
    m_Count(),
    m_Capacity(g_InitialCapacity)
    {
    memset(mp_Data, , g_InitialCapacity*sizeof(Callstack*));
    } //------------------------------------------------------------------------
    MemPro::CallstackSet::~CallstackSet()
    {
    Clear();
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Grow()
    {
    int old_capacity = m_Capacity;
    Callstack** p_old_data = mp_Data; // allocate a new set
    m_Capacity *= ;
    m_CapacityMask = m_Capacity - ;
    int size = m_Capacity * sizeof(Callstack*);
    mp_Data = (Callstack**)Allocator::Alloc(size);
    memset(mp_Data, , size); // transfer callstacks from old set
    m_Count = ;
    for(int i=; i<old_capacity; ++i)
    {
    Callstack* p_callstack = p_old_data[i];
    if(p_callstack)
    Add(p_callstack);
    } // release old buffer
    Allocator::Free(p_old_data, old_capacity*sizeof(Callstack*));
    } //------------------------------------------------------------------------
    MemPro::Callstack* MemPro::CallstackSet::Get(uint64* p_stack, int stack_size, unsigned int hash)
    {
    int index = hash & m_CapacityMask; while(mp_Data[index] && !StacksMatch(mp_Data[index], p_stack, stack_size, hash))
    index = (index + ) & m_CapacityMask; return mp_Data[index];
    } //------------------------------------------------------------------------
    MemPro::Callstack* MemPro::CallstackSet::Add(uint64* p_stack, int stack_size, unsigned int hash)
    {
    // grow the set if necessary
    if(m_Count > m_Capacity/)
    Grow(); // create a new callstack
    Callstack* p_callstack = (Callstack*)g_BlockAllocator.Alloc(sizeof(Callstack));
    p_callstack->m_ID = m_Count;
    p_callstack->m_Size = stack_size;
    p_callstack->mp_Stack = (uint64*)g_BlockAllocator.Alloc(stack_size*sizeof(uint64));
    p_callstack->m_Hash = hash;
    memcpy_s(p_callstack->mp_Stack, stack_size*sizeof(uint64), p_stack, stack_size*sizeof(uint64)); Add(p_callstack); return p_callstack;
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Add(Callstack* p_callstack)
    {
    // find a clear index
    int index = p_callstack->m_Hash & m_CapacityMask;
    while(mp_Data[index])
    index = (index + ) & m_CapacityMask; mp_Data[index] = p_callstack; ++m_Count;
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Clear()
    {
    for(int i=; i<m_Capacity; ++i)
    {
    if(mp_Data[i])
    g_BlockAllocator.Free(mp_Data[i]);
    } Allocator::Free(mp_Data, m_Capacity*sizeof(Callstack*)); size_t size = g_InitialCapacity*sizeof(Callstack*);
    mp_Data = (Callstack**)Allocator::Alloc((int)size);
    memset(mp_Data, , size);
    m_CapacityMask = g_InitialCapacity-;
    m_Count = ;
    m_Capacity = g_InitialCapacity;
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO
    //------------------------------------------------------------------------
    // MemPro.cpp //------------------------------------------------------------------------
    // RingBuffer.hpp
    #ifndef MEMPRO_RINGBUFFER_H_INCLUDED
    #define MEMPRO_RINGBUFFER_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // CriticalSection.hpp
    #ifndef MEMPRO_CRITICALSECTION_H_INCLUDED
    #define MEMPRO_CRITICALSECTION_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class CriticalSection
    {
    public:
    CriticalSection()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    InitializeCriticalSection(&cs);
    #else
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&cs, &attr);
    #endif
    } ~CriticalSection()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    DeleteCriticalSection(&cs);
    #else
    pthread_mutex_destroy(&cs);
    #endif
    } void Enter()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    EnterCriticalSection(&cs);
    #else
    pthread_mutex_lock(&cs);
    #endif
    } void Leave()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    LeaveCriticalSection(&cs);
    #else
    pthread_mutex_unlock(&cs);
    #endif
    }
    private: //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    CRITICAL_SECTION cs;
    #else
    pthread_mutex_t cs;
    #endif
    }; //------------------------------------------------------------------------
    class CriticalSectionScope
    {
    public:
    CriticalSectionScope(CriticalSection& in_cs) : cs(in_cs) { cs.Enter(); }
    ~CriticalSectionScope() { cs.Leave(); }
    private:
    CriticalSectionScope(const CriticalSectionScope&);
    CriticalSectionScope& operator=(const CriticalSectionScope&);
    CriticalSection& cs;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_CRITICALSECTION_H_INCLUDED //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    // USE_INTRINSIC can also be enabled on 32bit platform, but I left it disabled because it doesn't work on XP
    #ifdef MEMPRO64
    #define USE_INTRINSIC
    #endif
    #endif #ifdef USE_INTRINSIC
    #include <intrin.h>
    #pragma intrinsic(_InterlockedCompareExchange64)
    #pragma intrinsic(_InterlockedExchangeAdd64)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // Event.hpp
    #ifndef MEMPRO_EVENT_H_INCLUDED
    #define MEMPRO_EVENT_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //--------------------------------------------------------------------
    class Event
    {
    public:
    //--------------------------------------------------------------------
    Event(bool initial_state, bool auto_reset)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    m_Handle = CreateEvent(NULL, !auto_reset, initial_state, NULL);
    #else
    pthread_cond_init(&m_Cond, NULL);
    pthread_mutex_init(&m_Mutex, NULL);
    m_Signalled = false;
    m_AutoReset = auto_reset; if(initial_state)
    Set();
    #endif
    } //--------------------------------------------------------------------
    ~Event()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    CloseHandle(m_Handle);
    #else
    pthread_mutex_destroy(&m_Mutex);
    pthread_cond_destroy(&m_Cond);
    #endif
    } //--------------------------------------------------------------------
    void Set() const
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    SetEvent(m_Handle);
    #else
    pthread_mutex_lock(&m_Mutex);
    m_Signalled = true;
    pthread_mutex_unlock(&m_Mutex);
    pthread_cond_signal(&m_Cond);
    #endif
    } //--------------------------------------------------------------------
    void Reset()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    ResetEvent(m_Handle);
    #else
    pthread_mutex_lock(&m_Mutex);
    m_Signalled = false;
    pthread_mutex_unlock(&m_Mutex);
    #endif
    } //--------------------------------------------------------------------
    int Wait(int timeout=-) const
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMPRO_STATIC_ASSERT(INFINITE == -);
    return WaitForSingleObject(m_Handle, timeout) == /*WAIT_OBJECT_0*/;
    #else
    pthread_mutex_lock(&m_Mutex); if(m_Signalled)
    {
    m_Signalled = false;
    pthread_mutex_unlock(&m_Mutex);
    return true;
    } if(timeout == -)
    {
    while(!m_Signalled)
    pthread_cond_wait(&m_Cond, &m_Mutex); if(!m_AutoReset)
    m_Signalled = false; pthread_mutex_unlock(&m_Mutex); return true;
    }
    else
    {
    timeval curr;
    gettimeofday(&curr, NULL); timespec time;
    time.tv_sec = curr.tv_sec + timeout / ;
    time.tv_nsec = (curr.tv_usec * ) + ((timeout % ) * ); pthread_cond_timedwait(&m_Cond, &m_Mutex, &time); if(m_Signalled)
    {
    if(!m_AutoReset)
    m_Signalled = false; pthread_mutex_unlock(&m_Mutex);
    return true;
    } pthread_mutex_unlock(&m_Mutex);
    return false;
    }
    #endif
    } //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    HANDLE m_Handle;
    #else
    mutable pthread_cond_t m_Cond;
    mutable pthread_mutex_t m_Mutex;
    mutable volatile bool m_Signalled;
    bool m_AutoReset;
    #endif
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_EVENT_H_INCLUDED //------------------------------------------------------------------------
    //#define USE_CRITICAL_SECTIONS //------------------------------------------------------------------------
    namespace MemPro
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #ifndef USE_INTRINSIC
    //------------------------------------------------------------------------
    MEMPRO_FORCEINLINE int64 ssInterlockedCompareExchange64(int64 volatile *dest, int64 exchange, int64 comperand)
    {
    __asm
    {
    lea esi,comperand;
    lea edi,exchange;
    mov eax,[esi];
    mov edx,[esi];
    mov ebx,[edi];
    mov ecx,[edi];
    mov esi,dest;
    lock CMPXCHG8B [esi];
    }
    } //------------------------------------------------------------------------
    MEMPRO_FORCEINLINE int64 ssInterlockedExchangeAdd64(__inout int64 volatile *Addend, __in int64 Value)
    {
    int64 Old;
    do
    {
    Old = *Addend;
    } while (ssInterlockedCompareExchange64(Addend, Old + Value, Old) != Old);
    return Old;
    } //------------------------------------------------------------------------
    #define _InterlockedCompareExchange64 ssInterlockedCompareExchange64
    #define _InterlockedExchangeAdd64 ssInterlockedExchangeAdd64
    #endif
    #else
    // no interlocked functions, so just use a critical section
    CriticalSection g_CASCritSec;
    MEMPRO_FORCEINLINE int64 _InterlockedCompareExchange64(int64 volatile *dest, int64 exchange, int64 comperand)
    {
    g_CASCritSec.Enter();
    int64 old_value = *dest;
    if(*dest == comperand)
    *dest = exchange;
    g_CASCritSec.Leave();
    return old_value;
    } MEMPRO_FORCEINLINE int64 _InterlockedExchangeAdd64(int64 volatile *Addend, int64 Value)
    {
    g_CASCritSec.Enter();
    int64 old_value = *Addend;
    *Addend += Value;
    g_CASCritSec.Leave();
    return old_value;
    }
    #endif //------------------------------------------------------------------------
    // This ring buffer is a lockless buffer, designed to be accessed by no more
    // than two threads, one thread adding to the buffer and one removing. The
    // threads first request data and then add or remove tat data. The threads
    // will sleep if there is no space to add or no data to remove. Once the
    // threads have space on the buffer the data can be added or removed.
    class RingBuffer
    {
    public:
    //------------------------------------------------------------------------
    struct Range
    {
    Range() {}
    Range(void* p, int s) : mp_Buffer(p), m_Size(s) {} void* mp_Buffer;
    int m_Size;
    }; //------------------------------------------------------------------------
    RingBuffer(char* p_buffer, int size)
    : m_Size(size),
    mp_Buffer(p_buffer),
    m_UsedRange(),
    m_BytesRemovedEvent(false, true),
    m_BytesAddedEvent(false, true)
    {
    MEMPRO_ASSERT(IsPow2(size)); #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMPRO_ASSERT((((int64)&m_UsedRange) & ) == );
    #endif #ifdef USE_CRITICAL_SECTIONS
    InitializeCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    inline bool IsPow2(int value)
    {
    return (value & (value-)) == ;
    } //------------------------------------------------------------------------
    int GetSize() const
    {
    return m_Size;
    } //------------------------------------------------------------------------
    void Lock() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    EnterCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    void Release() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    LeaveCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    int64 GetRangeAtomic() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    Lock();
    int64 range = m_UsedRange;
    Release();
    #else
    // there must be a better way to atomically read a 64 bit value.
    int64 range = _InterlockedExchangeAdd64(const_cast<int64*>(&m_UsedRange), );
    #endif
    return range;
    } //------------------------------------------------------------------------
    // return the largest free range possible
    Range GetFreeRange(int timeout=-) const
    {
    int64 range = GetRangeAtomic();
    int size = (int)(range & 0xffffffff); // wait until there is some space
    while(size == m_Size)
    {
    if(!m_BytesRemovedEvent.Wait(timeout))
    return Range(NULL, ); range = GetRangeAtomic();
    size = (int)(range & 0xffffffff);
    } int start = (int)((range >> ) & 0xffffffff); // calculate the size
    int free_start = (start + size) & (m_Size-);
    int free_size = free_start < start ? start - free_start : m_Size - free_start; return Range(mp_Buffer + free_start, free_size);
    } //------------------------------------------------------------------------
    // return the largest used range
    Range GetAllocatedRange(int timeout=-) const
    {
    int64 range = GetRangeAtomic();
    #ifdef _XBOX
    __lwsync(); // ensure that the allocated data has finished writing
    #endif
    int size = (int)(range & 0xffffffff); // wait until there is some data
    while(!size)
    {
    if(!m_BytesAddedEvent.Wait(timeout))
    return Range(NULL, ); range = GetRangeAtomic();
    size = (int)(range & 0xffffffff);
    } int start = (int)((range >> ) & 0xffffffff); // calculate the size
    int max_size = m_Size - start;
    if(size > max_size)
    size = max_size; return Range(mp_Buffer + start, size);
    } //------------------------------------------------------------------------
    // tells the ring buffer how many bytes have been copied to the allocated range
    void Add(int size)
    {
    Lock(); MEMPRO_ASSERT(size >= ); volatile int64 old_range;
    int64 new_range; do
    {
    old_range = GetRangeAtomic(); int64 used_size = (old_range) & 0xffffffff;
    used_size += size;
    new_range = (old_range & 0xffffffff00000000LL) | used_size; } while(_InterlockedCompareExchange64(&m_UsedRange, new_range, old_range) != old_range); m_BytesAddedEvent.Set(); Release();
    } //------------------------------------------------------------------------
    // tells the ring buffer how many bytes have been removed from the allocated range
    void Remove(int size)
    {
    Lock(); MEMPRO_ASSERT(size >= ); volatile int64 old_range;
    int64 new_range;
    int mask = m_Size - ; do
    {
    old_range = GetRangeAtomic(); int64 used_start = (old_range >> ) & 0xffffffff;
    int64 used_size = (old_range) & 0xffffffff;
    used_start = (used_start + size) & mask;
    used_size -= size;
    new_range = (used_start << ) | used_size; } while(_InterlockedCompareExchange64(&m_UsedRange, new_range, old_range) != old_range); m_BytesRemovedEvent.Set(); Release();
    } //------------------------------------------------------------------------
    int GetUsedBytes() const
    {
    return (int)(m_UsedRange & 0xffffffff);
    } //------------------------------------------------------------------------
    void Clear()
    {
    m_UsedRange = ;
    m_BytesRemovedEvent.Reset();
    m_BytesAddedEvent.Reset();
    } //------------------------------------------------------------------------
    // data
    private:
    int m_Size;
    char* mp_Buffer; #ifdef MEMPRO_WIN_BASED_PLATFORM
    // NOTE: this MUST be 64bit aligned
    __declspec(align()) int64 m_UsedRange; // start index is the high int, size is the low int
    #else
    int64 m_UsedRange;
    #endif #ifdef USE_CRITICAL_SECTIONS
    mutable CRITICAL_SECTION m_CriticalSection;
    #endif
    Event m_BytesRemovedEvent;
    Event m_BytesAddedEvent;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_RINGBUFFER_H_INCLUDED //------------------------------------------------------------------------
    // Packets.hpp
    #ifndef MEMPRO_PACKETS_H_INCLUDED
    #define MEMPRO_PACKETS_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // MemProMisc.hpp
    #ifndef MEMPRO_MEMPROMISC_H_INCLUDED
    #define MEMPRO_MEMPROMISC_H_INCLUDED //------------------------------------------------------------------------ #include <stdlib.h> #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <byteswap.h>
    #endif //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4127)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #define MEMPRO_SPINLOCK_FREE_VAL 0
    #define MEMPRO_SPINLOCK_LOCKED_VAL 1
    #define MEMPRO_YIELD_SPIN_COUNT 40
    #define MEMPRO_SLEEP_SPIN_COUNT 200 //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    inline int Min(int a, int b) { return a < b ? a : b; } //------------------------------------------------------------------------
    inline void SwapEndian(unsigned int& value)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    value = _byteswap_ulong(value);
    #else
    value = __bswap_32(value);
    #endif
    } //------------------------------------------------------------------------
    inline void SwapEndian(uint64& value)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    value = _byteswap_uint64(value);
    #else
    value = __bswap_64(value);
    #endif
    } //------------------------------------------------------------------------
    inline void SwapEndian(int64& value)
    {
    SwapEndian((uint64&)value);
    } //------------------------------------------------------------------------
    template<typename T>
    inline void SwapEndian(T& value)
    {
    MEMPRO_ASSERT(sizeof(T) == sizeof(unsigned int));
    SwapEndian((unsigned int&)value);
    } //------------------------------------------------------------------------
    inline void SwapEndianUInt64Array(void* p, int size)
    {
    MEMPRO_ASSERT(size % == );
    uint64* p_uint64 = (uint64*)p;
    uint64* p_end = p_uint64 + size/;
    while(p_uint64 != p_end)
    SwapEndian(*p_uint64++);
    } //------------------------------------------------------------------------
    // hi-res timer
    #if defined(MEMPRO_PLATFORM_WIN)
    inline uint64 GetRDTSC()
    {
    #ifdef MEMPRO64
    return __rdtsc();
    #else
    __asm
    {
    ; Flush the pipeline
    XOR eax, eax
    CPUID
    ; Get RDTSC counter in edx:eax
    RDTSC
    }
    #endif
    }
    #define GET_CLOCK_COUNT(time) time = GetRDTSC();
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif //------------------------------------------------------------------------
    inline int64 GetTime()
    {
    int64 time; #ifdef MEMPRO_WIN_BASED_PLATFORM
    GET_CLOCK_COUNT(time);
    #else
    timeval curr;
    gettimeofday(&curr, NULL);
    time = ((int64)curr.tv_sec) * + curr.tv_usec;
    #endif
    return time;
    } //------------------------------------------------------------------------
    inline int64 GetTickFrequency()
    {
    Sleep();
    int64 start = GetTime();
    Sleep();
    int64 end = GetTime();
    return end - start;
    } //------------------------------------------------------------------------
    inline void SetThreadName(unsigned int thread_id, const char* p_name)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    // see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
    const unsigned int MS_VC_EXCEPTION=0x406D1388; struct THREADNAME_INFO
    {
    unsigned int dwType; // Must be 0x1000.
    LPCSTR szName; // Pointer to name (in user addr space).
    unsigned int dwThreadID; // Thread ID (-1=caller thread).
    unsigned int dwFlags; // Reserved for future use, must be zero.
    }; // on the xbox setting thread names messes up the XDK COM API that UnrealConsole uses so check to see if they have been
    // explicitly enabled
    Sleep();
    THREADNAME_INFO ThreadNameInfo;
    ThreadNameInfo.dwType = 0x1000;
    ThreadNameInfo.szName = p_name;
    ThreadNameInfo.dwThreadID = thread_id;
    ThreadNameInfo.dwFlags = ; __try
    {
    RaiseException( MS_VC_EXCEPTION, , sizeof(ThreadNameInfo)/sizeof(ULONG_PTR), (ULONG_PTR*)&ThreadNameInfo );
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
    #else
    // not supported
    #endif
    } //------------------------------------------------------------------------
    inline void SmallFastMemCpy(void* p_dst, void* p_src, int size)
    {
    MEMPRO_ASSERT((((size_t)p_dst) & ) == );
    MEMPRO_ASSERT((((size_t)p_src) & ) == );
    MEMPRO_ASSERT((size & ) == ); unsigned int uint_count = size / sizeof(unsigned int);
    unsigned int* p_uint_dst = (unsigned int*)p_dst;
    unsigned int* p_uint_src = (unsigned int*)p_src;
    for(unsigned int i=; i<uint_count; ++i)
    *p_uint_dst++ = *p_uint_src++;
    }
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPROMISC_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    // This file contains all of te packets that can be sent to the MemPro app. //------------------------------------------------------------------------
    enum PacketType
    {
    EInvalid = 0xabcd,
    EAllocPacket,
    EFreePacket,
    ECallstackPacket,
    EPageStatePacket,
    EPageStateStartPacket, // for backwards compatibility
    EPageStateEndPacket_OLD,
    EVirtualMemStats,
    ETakeSnapshot,
    EVMemStats,
    EPageStateEndPacket,
    EDataStoreEndPacket,
    EPulsePacket,
    ERequestShutdown
    }; //------------------------------------------------------------------------
    enum MemProVersion
    {
    Version =
    }; //------------------------------------------------------------------------
    enum MemProClientFlags
    {
    SendPageData = ,
    SendPageDataWithMemory,
    EShutdownComplete
    }; //------------------------------------------------------------------------
    // value that is sent immediatley after connection to detect big endian
    enum EEndianKey
    {
    EndianKey = 0xabcdef01
    }; //------------------------------------------------------------------------
    enum Platform
    {
    Platform_Windows,
    Platform_Unix
    }; //------------------------------------------------------------------------
    struct PacketHeader
    {
    PacketType m_PacketType;
    int m_Padding;
    int64 m_Time; void SwapEndian()
    {
    MemPro::SwapEndian(m_PacketType);
    MemPro::SwapEndian(m_Time);
    }
    }; //------------------------------------------------------------------------
    struct ConnectPacket
    {
    uint64 m_Padding; // for backwards compatibility int64 m_ConnectTime;
    int64 m_TickFrequency; int m_Version;
    int m_PtrSize; Platform m_Platform;
    int m_Padding2; void SwapEndian()
    {
    MemPro::SwapEndian(m_Version);
    MemPro::SwapEndian(m_ConnectTime);
    MemPro::SwapEndian(m_TickFrequency);
    MemPro::SwapEndian(m_PtrSize);
    }
    }; //------------------------------------------------------------------------
    struct AllocPacket
    {
    uint64 m_Addr;
    uint64 m_Size;
    int m_CallstackID;
    int m_Padding; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    MemPro::SwapEndian(m_CallstackID);
    }
    }; //------------------------------------------------------------------------
    struct FreePacket
    {
    uint64 m_Addr; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    }
    }; //------------------------------------------------------------------------
    struct PageStatePacket
    {
    uint64 m_Addr;
    uint64 m_Size;
    PageState m_State;
    PageType m_Type;
    unsigned int m_Protection;
    int m_SendingMemory; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    MemPro::SwapEndian(m_State);
    MemPro::SwapEndian(m_Type);
    MemPro::SwapEndian(m_Protection);
    MemPro::SwapEndian(m_SendingMemory);
    }
    }; //------------------------------------------------------------------------
    struct VirtualMemStatsPacket
    {
    uint64 m_Reserved;
    uint64 m_Committed; void SwapEndian()
    {
    MemPro::SwapEndian(m_Reserved);
    MemPro::SwapEndian(m_Committed);
    }
    }; //------------------------------------------------------------------------
    struct IgnoreMemRangePacket
    {
    uint64 m_Addr;
    uint64 m_Size; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    }
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_PACKETS_H_INCLUDED //------------------------------------------------------------------------
    // Socket.hpp
    #ifndef MEMPRO_SOCKET_H_INCLUDED
    #define MEMPRO_SOCKET_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(push)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class SocketImp; //------------------------------------------------------------------------
    class Socket
    {
    public:
    inline Socket(); inline ~Socket(); void Disconnect(); bool Bind(const char* p_port); bool StartListening(); bool Accept(Socket& client_socket); int Receive(void* p_buffer, int size); bool Send(void* p_buffer, int size); inline bool IsValid() const { return m_Socket != INVALID_SOCKET; } private:
    bool InitialiseWSA(); void CleanupWSA(); void HandleError(); //------------------------------------------------------------------------
    // data
    SOCKET m_Socket;
    }; //------------------------------------------------------------------------
    Socket::Socket()
    : m_Socket(INVALID_SOCKET)
    {
    } //------------------------------------------------------------------------
    Socket::~Socket()
    {
    CleanupWSA();
    }
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(pop)
    #endif //------------------------------------------------------------------------
    #endif // #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_SOCKET_H_INCLUDED //------------------------------------------------------------------------
    // Thread.hpp
    #ifndef MEMPRO_THREAD_H_INCLUDED
    #define MEMPRO_THREAD_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(push)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifndef MEMPRO_WIN_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    typedef int (*ThreadMain)(void*); //------------------------------------------------------------------------
    class Thread
    {
    public:
    Thread(); void CreateThread(ThreadMain p_thread_main, void* p_param=NULL); bool IsAlive() const { return m_Alive; } private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    static unsigned long WINAPI PlatformThreadMain(void* p_param);
    #else
    static void* PlatformThreadMain(void* p_param);
    #endif //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    mutable HANDLE m_Handle;
    #else
    mutable pthread_t m_Thread;
    #endif
    mutable bool m_Alive; mutable ThreadMain mp_ThreadMain;
    mutable void* mp_Param;
    };
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(pop)
    #endif //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_THREAD_H_INCLUDED #include <new>
    #include <stdio.h>
    #include <time.h>
    #include <limits.h> #if defined(MEMPRO_PLATFORM_WIN) && !((!defined(MIDL_PASS) && defined(_M_IX86) && !defined(_M_CEE_PURE)) || defined(MemoryBarrier))
    #include <atomic>
    #endif #ifdef MEMPRO_WIN_BASED_PLATFORM
    #include <tchar.h>
    #endif //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4127)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #if !defined(WRITE_DUMP) && defined(MEMPRO_WIN_BASED_PLATFORM)
    #pragma comment(lib, "Ws2_32.lib")
    #endif //------------------------------------------------------------------------
    // if you are having problems compiling this on your platform undefine ENUMERATE_ALL_MODULES and it send info for just the main module
    #ifndef MEMPRO_PLATFORM_XBOXONE
    #define ENUMERATE_ALL_MODULES
    #endif #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM #if FRAMEPRO_TOOLSET_UE4
    #include "AllowWindowsPlatformTypes.h"
    #endif #pragma warning(push)
    #pragma warning(disable : 4091)
    #include <Dbghelp.h>
    #pragma warning(pop) #pragma comment(lib, "Dbghelp.lib") #if FRAMEPRO_TOOLSET_UE4
    #include "HideWindowsPlatformTypes.h"
    #endif
    #else
    #include <link.h>
    #endif
    #endif //------------------------------------------------------------------------
    #ifdef VMEM_STATS
    namespace VMem { void SendStatsToMemPro(void (*send_fn)(void*, int, void*), void* p_context); }
    #endif //------------------------------------------------------------------------
    //#define TEST_ENDIAN //#define PACKET_START_END_MARKERS #ifdef TEST_ENDIAN
    #define ENDIAN_TEST(a) a
    #else
    #define ENDIAN_TEST(a)
    #endif //------------------------------------------------------------------------
    // if both of these options are commented out it will use CaptureStackBackTrace (or backtrace on linux)
    //#define USE_STACKWALK64 // much slower but possibly more reliable. USE_STACKWALK64 only implemented for x86 builds.
    //#define USE_RTLVIRTUALUNWIND // reported to be faster than StackWalk64 - only available on x64 builds
    //#define USE_RTLCAPTURESTACKBACKTRACE // system version of USE_RTLVIRTUALUNWIND - only available on x64 builds #if FRAMEPRO_TOOLSET_UE4
    #define USE_RTLCAPTURESTACKBACKTRACE
    #endif //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #define THREAD_LOCAL_STORAGE __declspec(thread)
    #else
    #define THREAD_LOCAL_STORAGE __thread
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    THREAD_LOCAL_STORAGE void** g_CallstackDataTLS = NULL;
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_PLATFORM_XBOXONE
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif //------------------------------------------------------------------------
    #ifdef USE_RTLCAPTURESTACKBACKTRACE #ifndef MEMPRO64
    #error USE_RTLVIRTUALUNWIND only available on x64 builds. Please use a different stack walk function.
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    void RTLCaptureStackBackTrace(void** stack, int max_stack_size, unsigned int& hash, int& stack_size)
    {
    memset(stack, , max_stack_size* sizeof(void*));
    stack_size = ::RtlCaptureStackBackTrace(,max_stack_size-, stack, (PDWORD)&hash);
    stack[stack_size] = ;
    }
    } #endif // #ifdef USE_RTLCAPTURESTACKBACKTRACE //------------------------------------------------------------------------
    #ifdef USE_RTLVIRTUALUNWIND #ifndef MEMPRO64
    #error USE_RTLVIRTUALUNWIND only available on x64 builds. Please use a different stack walk function.
    #endif namespace MemPro
    {
    //------------------------------------------------------------------------
    __declspec(noinline) VOID VirtualUnwindStackWalk(void** stack, int max_stack_size)
    {
    CONTEXT context;
    memset(&context, , sizeof(context));
    RtlCaptureContext(&context); UNWIND_HISTORY_TABLE unwind_history_table;
    RtlZeroMemory(&unwind_history_table, sizeof(UNWIND_HISTORY_TABLE)); int frame = ;
    for (; frame < max_stack_size-; ++frame)
    {
    stack[frame] = (void*)context.Rip; ULONG64 image_base;
    PRUNTIME_FUNCTION runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, &unwind_history_table); if (!runtime_function)
    {
    // If we don't have a RUNTIME_FUNCTION, then we've encountered
    // a leaf function. Adjust the stack appropriately.
    context.Rip = (ULONG64)(*(PULONG64)context.Rsp);
    context.Rsp += ;
    }
    else
    {
    // Otherwise, call upon RtlVirtualUnwind to execute the unwind for us.
    KNONVOLATILE_CONTEXT_POINTERS nv_context;
    RtlZeroMemory(&nv_context, sizeof(KNONVOLATILE_CONTEXT_POINTERS)); PVOID handler_data;
    ULONG64 establisher_frame; RtlVirtualUnwind(
    /*UNW_FLAG_NHANDLER*/,
    image_base,
    context.Rip,
    runtime_function,
    &context,
    &handler_data,
    &establisher_frame,
    &nv_context);
    } // If we reach an RIP of zero, this means that we've walked off the end
    // of the call stack and are done.
    if (!context.Rip)
    break;
    } stack[frame] = ;
    }
    }
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    int g_MemProRefs = ; //------------------------------------------------------------------------
    const int PAGE_SIZE = ; //------------------------------------------------------------------------
    void InitialiseInternal(); //------------------------------------------------------------------------
    // MemPro will initialise on the first allocation, but this global ensures
    // that MemPro is initialised in the main module. This is sometimes necessary
    // if the first allocation comes from a dll.
    /*
    class Initialiser
    {
    public:
    Initialiser() { MemPro::Initialise(WAIT_FOR_CONNECT); }
    } g_Initialiser;
    */ //------------------------------------------------------------------------
    // port number
    #if defined(MEMPRO_PLATFORM_WIN)
    const char* g_DefaultPort = "";
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    const char* g_DefaultPort = "";
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN)
    #if (NTDDI_VERSION > NTDDI_WINXP)
    #define STACK_TRACE_SIZE 128
    #else
    #define STACK_TRACE_SIZE 62
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    #define STACK_TRACE_SIZE 128
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    // globals
    const int g_RingBufferSize = *; #ifdef MEMPRO64
    uint64 g_MaxAddr = ULLONG_MAX;
    #else
    uint64 g_MaxAddr = UINT_MAX;
    #endif //------------------------------------------------------------------------
    #ifdef WRITE_DUMP
    FILE* gp_DumpFile = NULL;
    #endif //------------------------------------------------------------------------
    uint64 ToUInt64(void* p)
    {
    #ifdef MEMPRO64
    return (uint64)p;
    #else
    unsigned int u = (unsigned int)p; // cast to uint first to avoid signed bit in casting
    return (uint64)u;
    #endif
    } //------------------------------------------------------------------------
    struct DataStorePageHeader
    {
    int m_Size;
    DataStorePageHeader* mp_Next;
    }; //------------------------------------------------------------------------
    struct CallstackCapture
    {
    void** mp_Stack;
    int m_Size;
    unsigned int m_Hash;
    }; //------------------------------------------------------------------------
    void BaseAddressLookupFunction()
    {
    } //------------------------------------------------------------------------
    class CMemPro
    {
    public:
    CMemPro(); bool Initialise(); void Shutdown(); void Disconnect(bool listen_for_new_connection); void TrackAlloc(void* p, size_t size, bool wait_for_connect); void TrackFree(void* p, bool wait_for_connect); void SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory); void TakeSnapshot(); int SendThreadMain(void* p_param); #ifndef WRITE_DUMP
    int ReceiveThreadMain(void* p_param);
    #endif int WaitForConnectionThreadMain(void* p_param); void Lock() { m_CriticalSection.Enter(); } void Release() { m_CriticalSection.Leave(); } void WaitForConnectionOnInitialise(); bool IsPaused(); void SetPaused(bool paused); private:
    static void GetStackTrace(void** stack, int& stack_size, unsigned int& hash); void SendModuleInfo(); void SendExtraModuleInfo(int64 ModuleBase); void SendString(const char* p_str); #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
    static BOOL CALLBACK EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in DWORD64 ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext);
    #else
    static BOOL CALLBACK EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in ULONG ModuleBase, __in ULONG ModuleSize,__in_opt PVOID UserContext);
    #endif
    #else
    int static EnumerateLoadedModulesCallback(struct dl_phdr_info* info, size_t size, void* data);
    #endif
    #endif
    void StoreData(const void* p_data, int size); void BlockUntilSendThreadEmpty(); void SendStoredData(); void ClearStoreData(); inline bool SendThreadStillAlive() const; void FlushRingBufferForShutdown(); void SendData(const void* p_data, int size); bool SocketSendData(const void* p_data, int size); static void StaticSendVMemStatsData(void* p_data, int size, void* p_context); void SendVMemStatsData(void* p_data, int size); void SendData(unsigned int value); inline void SendPacketHeader(PacketType value); void SendStartMarker(); void SendEndMarker(); inline void Send(bool value); template<typename T> void Send(T& value) { SendData(&value, sizeof(value)); } void Send(unsigned int value) { SendData(value); } void SendPageState(bool send_memory); void SendVMemStats(); void SendVirtualMemStats(); void** AllocateStackTraceData(); CallstackCapture CaptureCallstack(); int SendCallstack(const CallstackCapture& callstack_capture); bool WaitForConnection(); bool WaitForConnectionIfListening(); static int SendThreadMainStatic(void* p_param); static int ReceiveThreadMainStatic(void* p_param); static int WaitForConnectionThreadMainStatic(void* p_param); static int PulseThreadMainStatic(void* p_param); void PulseThreadMain(); void BlockUntilReadyToSend(); //------------------------------------------------------------------------
    // data
    #ifndef WRITE_DUMP
    Socket m_ListenSocket;
    Socket m_ClientSocket;
    #endif CallstackSet m_CallstackSet; RingBuffer m_RingBuffer;
    char m_RingBufferMem[g_RingBufferSize]; volatile bool m_Connected;
    volatile bool m_ReadyToSend; volatile bool m_InEvent; volatile bool m_Paused; Event m_StartedListeningEvent;
    Event m_WaitForConnectThreadFinishedEvent;
    Event m_SendThreadFinishedEvent;
    Event m_ReceiveThreadFinishedEvent;
    Event m_MemProReadyToShutdownEvent;
    Event m_PulseThreadFinished; volatile bool m_StartedListening;
    volatile bool m_InitialConnectionTimedOut; int m_LastPageStateSend;
    int m_PageStateInterval; int m_LastVMemStatsSend;
    int m_VMemStatsSendInterval; bool m_WaitForConnect; static const int m_DataStorePageSize = ;
    DataStorePageHeader* mp_DataStoreHead; // used to store allocs before initialised
    DataStorePageHeader* mp_DataStoreTail; Thread m_SendThread;
    Thread m_ReceiveThread;
    Thread m_PulseThread;
    Thread m_WaitForConnectionThread; bool m_FlushedRingBufferForShutdown; CriticalSection m_CriticalSection;
    CriticalSection m_DisconnectCriticalSection; int m_ModulesSent; volatile bool m_ShuttingDown; BlockAllocator<Allocator> m_BlockAllocator;
    }; //------------------------------------------------------------------------
    char g_MemProMem[sizeof(CMemPro)];
    CMemPro* gp_MemPro = NULL;
    volatile bool g_ShuttingDown = false; //------------------------------------------------------------------------
    inline CMemPro* GetMemPro()
    {
    if(!gp_MemPro)
    InitialiseInternal(); return gp_MemPro;
    } //------------------------------------------------------------------------
    CMemPro::CMemPro()
    : m_RingBuffer(m_RingBufferMem, g_RingBufferSize),
    m_Connected(false),
    m_ReadyToSend(false),
    m_InEvent(false),
    m_Paused(false),
    m_StartedListeningEvent(false, false),
    m_WaitForConnectThreadFinishedEvent(false, false),
    m_SendThreadFinishedEvent(true, false),
    m_ReceiveThreadFinishedEvent(true, false),
    m_MemProReadyToShutdownEvent(false, false),
    m_PulseThreadFinished(true, false),
    m_StartedListening(false),
    m_InitialConnectionTimedOut(false),
    m_LastPageStateSend(),
    m_PageStateInterval(),
    m_LastVMemStatsSend(),
    m_VMemStatsSendInterval(),
    m_WaitForConnect(false),
    mp_DataStoreHead(NULL),
    mp_DataStoreTail(NULL),
    m_FlushedRingBufferForShutdown(false),
    m_ModulesSent(),
    m_ShuttingDown(false)
    {
    } //------------------------------------------------------------------------
    inline unsigned int GetHash(void** p_stack, int stack_size)
    {
    #ifdef MEMPRO64
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    void** p = p_stack;
    for(int i=; i<stack_size; ++i)
    {
    uint64 key = ToUInt64(*p++);
    key = (~key) + (key << );
    key = key ^ (key >> );
    key = key * ;
    key = key ^ (key >> );
    key = key + (key << );
    key = key ^ (key >> );
    hash = hash ^ (unsigned int)key;
    } return hash;
    #else
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    for(int i=; i<stack_size; ++i)
    hash = (hash * prime) ^ (unsigned int)p_stack[i]; return hash;
    #endif
    } //------------------------------------------------------------------------
    inline unsigned int GetHashAndStackSize(void** p_stack, int& stack_size)
    {
    #ifdef MEMPRO64
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    stack_size = ;
    void** p = p_stack;
    while(*p)
    {
    uint64 key = ToUInt64(*p++);
    key = (~key) + (key << );
    key = key ^ (key >> );
    key = key * ;
    key = key ^ (key >> );
    key = key + (key << );
    key = key ^ (key >> );
    hash = hash ^ (unsigned int)key;
    ++stack_size;
    } return hash;
    #else
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    stack_size = ;
    while(p_stack[stack_size])
    {
    hash = (hash * prime) ^ (unsigned int)p_stack[stack_size];
    ++stack_size;
    } return hash;
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::GetStackTrace(void** stack, int& stack_size, unsigned int& hash)
    {
    #if defined(MEMPRO_PLATFORM_WIN)
    #if defined(USE_STACKWALK64) #ifdef MEMPRO64
    #error USE_STACKWALK64 only works in x86 builds. Please use a different stack walk funtion.
    #endif // get the context
    CONTEXT context;
    memset(&context, , sizeof(context));
    RtlCaptureContext(&context); // setup the stack frame
    STACKFRAME64 stack_frame;
    memset(&stack_frame, , sizeof(stack_frame));
    stack_frame.AddrPC.Mode = AddrModeFlat;
    stack_frame.AddrFrame.Mode = AddrModeFlat;
    stack_frame.AddrStack.Mode = AddrModeFlat;
    #ifdef MEMPRO64
    DWORD machine = IMAGE_FILE_MACHINE_IA64;
    stack_frame.AddrPC.Offset = context.Rip;
    stack_frame.AddrFrame.Offset = context.Rsp;
    stack_frame.AddrStack.Offset = context.Rbp;
    #else
    DWORD machine = IMAGE_FILE_MACHINE_I386;
    stack_frame.AddrPC.Offset = context.Eip;
    stack_frame.AddrFrame.Offset = context.Ebp;
    stack_frame.AddrStack.Offset = context.Esp;
    #endif
    HANDLE thread = GetCurrentThread(); static HANDLE process = GetCurrentProcess(); stack_size = ;
    while(StackWalk64(
    machine,
    process,
    thread,
    &stack_frame,
    &context,
    NULL,
    SymFunctionTableAccess64,
    SymGetModuleBase64,
    NULL) && stack_size < STACK_TRACE_SIZE)
    {
    void* p = (void*)(stack_frame.AddrPC.Offset);
    stack[stack_size++] = p;
    }
    hash = GetHash(stack, stack_size);
    #elif defined(USE_RTLVIRTUALUNWIND)
    MemPro::VirtualUnwindStackWalk(stack, STACK_TRACE_SIZE);
    hash = GetHashAndStackSize(stack, stack_size);
    #elif defined(USE_RTLCAPTURESTACKBACKTRACE)
    MemPro::RTLCaptureStackBackTrace(stack, STACK_TRACE_SIZE, hash, stack_size);
    #else
    CaptureStackBackTrace(, STACK_TRACE_SIZE, stack, (PDWORD)&hash);
    for(stack_size = ; stack_size<STACK_TRACE_SIZE; ++stack_size)
    if(!stack[stack_size])
    break;
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    stack_size = backtrace(stack, STACK_TRACE_SIZE);
    hash = GetHashAndStackSize(stack, stack_size);
    #else
    #error platform not defined
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::StaticSendVMemStatsData(void* p_data, int size, void* p_context)
    {
    CMemPro* p_this = (CMemPro*)p_context;
    p_this->SendVMemStatsData(p_data, size);
    } //------------------------------------------------------------------------
    void CMemPro::SendVMemStatsData(void* p_data, int size)
    {
    static char buffer[];
    MEMPRO_ASSERT(size <= (int)sizeof(buffer));
    memcpy_s(buffer, sizeof(buffer), p_data, size);
    ENDIAN_TEST(SwapEndianUInt64Array(buffer, size));
    SendData(buffer, size);
    } //------------------------------------------------------------------------
    void CMemPro::StoreData(const void* p_data, int size)
    {
    MEMPRO_ASSERT(size < m_DataStorePageSize - (int)sizeof(DataStorePageHeader)); if(!mp_DataStoreTail || mp_DataStoreTail->m_Size + size > m_DataStorePageSize)
    {
    DataStorePageHeader* p_new_page = (DataStorePageHeader*)Allocator::Alloc(m_DataStorePageSize);
    p_new_page->m_Size = sizeof(DataStorePageHeader);
    p_new_page->mp_Next = NULL; if(mp_DataStoreTail)
    mp_DataStoreTail->mp_Next = p_new_page;
    else
    mp_DataStoreHead = p_new_page; mp_DataStoreTail = p_new_page;
    } memcpy((char*)mp_DataStoreTail + mp_DataStoreTail->m_Size, p_data, size);
    mp_DataStoreTail->m_Size += size;
    } //------------------------------------------------------------------------
    void CMemPro::BlockUntilSendThreadEmpty()
    {
    // wait for the send thread to have sent all of the stored data
    while(m_Connected && m_RingBuffer.GetAllocatedRange().m_Size)
    Sleep();
    } //------------------------------------------------------------------------
    void CMemPro::SendStoredData()
    {
    if(!m_Connected)
    return; DataStorePageHeader* p_page = mp_DataStoreHead; if(p_page)
    {
    while(p_page)
    {
    DataStorePageHeader* p_next = p_page->mp_Next; SendData((char*)p_page + sizeof(DataStorePageHeader), p_page->m_Size - sizeof(DataStorePageHeader));
    Allocator::Free(p_page, m_DataStorePageSize); p_page = p_next;
    } SendPacketHeader(EDataStoreEndPacket);
    SendEndMarker();
    } #ifndef WRITE_DUMP
    BlockUntilSendThreadEmpty();
    #endif mp_DataStoreHead = mp_DataStoreTail = NULL;
    } //------------------------------------------------------------------------
    void CMemPro::ClearStoreData()
    {
    DataStorePageHeader* p_page = mp_DataStoreHead;
    while(p_page)
    {
    DataStorePageHeader* p_next = p_page->mp_Next;
    Allocator::Free(p_page, m_DataStorePageSize);
    p_page = p_next;
    } mp_DataStoreHead = mp_DataStoreTail = NULL; m_CallstackSet.Clear();
    } //------------------------------------------------------------------------
    void CMemPro::Send(bool value)
    {
    unsigned int uint_value = value ? : ;
    Send(uint_value);
    } //------------------------------------------------------------------------
    bool CMemPro::SendThreadStillAlive() const
    {
    return m_SendThread.IsAlive();
    } //------------------------------------------------------------------------
    void CMemPro::FlushRingBufferForShutdown()
    {
    if(m_FlushedRingBufferForShutdown)
    return;
    m_FlushedRingBufferForShutdown = true; RingBuffer::Range range = m_RingBuffer.GetAllocatedRange();
    while(range.m_Size)
    {
    SocketSendData(range.mp_Buffer, range.m_Size);
    range = m_RingBuffer.GetAllocatedRange();
    }
    } //------------------------------------------------------------------------
    void CMemPro::SendData(const void* p_data, int size)
    {
    MEMPRO_ASSERT((size & ) == ); if(!m_Connected)
    {
    StoreData(p_data, size);
    return;
    } if(!SendThreadStillAlive())
    {
    FlushRingBufferForShutdown();
    SocketSendData(p_data, size);
    }
    else
    {
    int bytes_to_copy = size;
    char* p_src = (char*)p_data;
    while(bytes_to_copy)
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetFreeRange();
    if(!m_Connected)
    return;
    } while(!range.m_Size);
    if(!m_Connected)
    return; int copy_size = Min(range.m_Size, bytes_to_copy);
    SmallFastMemCpy(range.mp_Buffer, p_src, copy_size);
    p_src += copy_size;
    bytes_to_copy -= copy_size; m_RingBuffer.Add(copy_size);
    }
    }
    } //------------------------------------------------------------------------
    // slightly more optimal version for sending a single uint. Because all ringbuffer
    // operations are 4 byte aligned we can be guaranteed that the uint won't be split
    // between the end and start of the buffer, we will always get it in one piece.
    void CMemPro::SendData(unsigned int value)
    {
    if(!m_Connected)
    {
    StoreData(&value, sizeof(value));
    return;
    } if(!SendThreadStillAlive())
    {
    FlushRingBufferForShutdown();
    SocketSendData(&value, sizeof(value));
    #ifdef WRITE_DUMP
    fflush(gp_DumpFile);
    #endif
    }
    else
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetFreeRange();
    if(!m_Connected)
    return;
    } while(!range.m_Size);
    if(!m_Connected)
    return; MEMPRO_ASSERT(range.m_Size >= (int)sizeof(unsigned int));
    MEMPRO_ASSERT((((size_t)range.mp_Buffer) & ) == );
    *(unsigned int*)range.mp_Buffer = value; m_RingBuffer.Add(sizeof(value));
    }
    } //------------------------------------------------------------------------
    void CMemPro::SendPacketHeader(PacketType value)
    {
    SendStartMarker(); PacketHeader header;
    header.m_PacketType = value;
    header.m_Time = GetTime(); Send(header);
    } //------------------------------------------------------------------------
    void CMemPro::SendStartMarker()
    {
    #ifdef PACKET_START_END_MARKERS
    unsigned int start_marker = 0xabcdef01;
    ENDIAN_TEST(SwapEndian(start_marker));
    Send(start_marker);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendEndMarker()
    {
    #ifdef PACKET_START_END_MARKERS
    unsigned int end_marker = 0xaabbccdd;
    ENDIAN_TEST(SwapEndian(end_marker));
    Send(end_marker);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendPageState(bool send_memory)
    {
    CriticalSectionScope lock(m_CriticalSection); SendPacketHeader(EPageStateStartPacket);
    SendEndMarker(); #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMORY_BASIC_INFORMATION info;
    memset(&info, , sizeof(info)); uint64 addr = ; HANDLE process = GetCurrentProcess(); bool found_page = false; while(addr < g_MaxAddr)
    {
    uint64 last_addr = addr; if(VirtualQueryEx(process, (void*)addr, &info, sizeof(info)) != )
    {
    if((info.State == MEM_RESERVE || info.State == MEM_COMMIT) && info.Protect != PAGE_NOACCESS)
    {
    PageState page_state;
    switch(info.State)
    {
    case MEM_RESERVE: page_state = MemPro::Reserved; break;
    case MEM_COMMIT: page_state = MemPro::Committed; break;
    default: page_state = MemPro::Committed; MEMPRO_ASSERT(false); break;
    } #if defined(MEMPRO_PLATFORM_WIN)
    PageType page_type;
    switch(info.Type)
    {
    case MEM_IMAGE: page_type = page_Image; break;
    case MEM_MAPPED: page_type = page_Mapped; break;
    case MEM_PRIVATE: page_type = page_Private; break;
    default: page_type = page_Unknown; break;
    }
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #else
    #error platform not defined
    #endif
    SendPageState(info.BaseAddress, info.RegionSize, page_state, page_type, info.Protect, send_memory);
    } addr += info.RegionSize;
    found_page = true;
    }
    else
    {
    if(!found_page)
    addr += PAGE_SIZE;
    else
    break; // VirtualQueryEx should only fail when it gets to the end, assuming it has found at least one page
    } if(addr < last_addr) // handle wrap around
    break;
    }
    #endif
    SendPacketHeader(EPageStateEndPacket); IgnoreMemRangePacket range_packet;
    range_packet.m_Addr = ToUInt64(m_RingBufferMem);
    range_packet.m_Size = sizeof(m_RingBufferMem);
    Send(range_packet); SendEndMarker();
    } //------------------------------------------------------------------------
    void CMemPro::SendVMemStats()
    {
    #ifdef VMEM_STATS
    Send(EVMemStats); int64 time = GetTime();
    Send(time); VMem::SendStatsToMemPro(StaticSendVMemStatsData, this);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendVirtualMemStats()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMORY_BASIC_INFORMATION info;
    memset(&info, , sizeof(info)); uint64 addr = ;
    size_t reserved = ;
    size_t committed = ; HANDLE process = GetCurrentProcess(); bool started = false; while(addr < g_MaxAddr)
    {
    uint64 last_addr = addr; if(VirtualQueryEx(process, (void*)addr, &info, sizeof(info)) != )
    {
    switch(info.State)
    {
    case MEM_RESERVE: reserved += info.RegionSize; break;
    case MEM_COMMIT: committed += info.RegionSize; break;
    } addr += info.RegionSize; started = true;
    }
    else
    {
    if(started)
    break; addr = (addr & (~((size_t)PAGE_SIZE-))) + PAGE_SIZE;
    } if(addr < last_addr) // handle wrap around
    break;
    } #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif
    reserved += committed; SendPacketHeader(EVirtualMemStats); VirtualMemStatsPacket packet;
    packet.m_Reserved = reserved;
    packet.m_Committed = committed;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet);
    #else
    SendPacketHeader(EVirtualMemStats); VirtualMemStatsPacket packet;
    packet.m_Reserved = ;
    packet.m_Committed = ;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet);
    #endif
    SendEndMarker();
    } //------------------------------------------------------------------------
    void** CMemPro::AllocateStackTraceData()
    {
    CriticalSectionScope lock(m_CriticalSection);
    return (void**)m_BlockAllocator.Alloc(STACK_TRACE_SIZE*sizeof(void*));
    } //------------------------------------------------------------------------
    CallstackCapture CMemPro::CaptureCallstack()
    {
    CallstackCapture callstack; callstack.mp_Stack = g_CallstackDataTLS;
    if(!callstack.mp_Stack)
    {
    callstack.mp_Stack = AllocateStackTraceData();
    g_CallstackDataTLS = callstack.mp_Stack;
    } callstack.m_Hash = ;
    callstack.m_Size = ;
    GetStackTrace(callstack.mp_Stack, callstack.m_Size, callstack.m_Hash); #ifdef USE_RTLVIRTUALUNWIND
    const int ignore_count = ;
    #else
    const int ignore_count = ;
    #endif
    callstack.m_Size -= ignore_count;
    if(callstack.m_Size <= )
    {
    callstack.mp_Stack[] = (void*)-;
    callstack.m_Size = ;
    } return callstack;
    } //------------------------------------------------------------------------
    int CMemPro::SendCallstack(const CallstackCapture& callstack_capture)
    {
    void** p_stack = callstack_capture.mp_Stack;
    int stack_size = callstack_capture.m_Size;
    int hash = callstack_capture.m_Hash; #ifdef MEMPRO64
    uint64* stack64 = (uint64*)p_stack;
    #else
    static uint64 stack64_static[STACK_TRACE_SIZE];
    for(int i=; i<stack_size; ++i)
    stack64_static[i] = ToUInt64(p_stack[i]);
    uint64* stack64 = stack64_static;
    #endif Callstack* p_callstack = m_CallstackSet.Get(stack64, stack_size, hash); if(!p_callstack)
    {
    p_callstack = m_CallstackSet.Add(stack64, stack_size, hash); SendPacketHeader(ECallstackPacket); int callstack_id = p_callstack->m_ID;
    #ifdef TEST_ENDIAN
    SwapEndian(callstack_id);
    #endif
    Send(callstack_id); int send_stack_size = stack_size;
    #ifdef TEST_ENDIAN
    for(int i=; i<stack_size; ++i) SwapEndian(stack64[i]);
    SwapEndian(send_stack_size);
    #endif
    Send(send_stack_size);
    SendData(stack64, stack_size*sizeof(uint64)); SendEndMarker();
    } return p_callstack->m_ID;
    } //------------------------------------------------------------------------
    void CMemPro::TakeSnapshot()
    {
    CriticalSectionScope lock(m_CriticalSection);
    SendPacketHeader(ETakeSnapshot);
    } //------------------------------------------------------------------------
    int CMemPro::SendThreadMainStatic(void* p_param)
    {
    return gp_MemPro->SendThreadMain(p_param);
    } //------------------------------------------------------------------------
    bool CMemPro::SocketSendData(const void* p_data, int size)
    {
    #ifdef WRITE_DUMP
    MEMPRO_ASSERT(gp_DumpFile);
    size_t result = fwrite(p_data, size, , gp_DumpFile);
    MEMPRO_ASSERT(result == );
    return true;
    #else
    return m_ClientSocket.Send((void*)p_data, size);
    #endif
    } //------------------------------------------------------------------------
    int CMemPro::SendThreadMain(void* p_param)
    {
    while(m_Connected)
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetAllocatedRange(); // timeout: check for disconnect every 100 ms
    if(!m_Connected)
    {
    m_SendThreadFinishedEvent.Set();
    return ;
    }
    } while(!range.m_Size); if(!SocketSendData(range.mp_Buffer, range.m_Size))
    {
    m_SendThreadFinishedEvent.Set();
    Disconnect(true);
    return ;
    } m_RingBuffer.Remove(range.m_Size);
    } m_SendThreadFinishedEvent.Set();
    return ;
    } //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    int CMemPro::ReceiveThreadMainStatic(void* p_param)
    {
    return gp_MemPro->ReceiveThreadMain(p_param);
    }
    #endif //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    int CMemPro::ReceiveThreadMain(void* p_param)
    {
    while(m_Connected)
    {
    unsigned int flag = ; if(m_ClientSocket.Receive(&flag, sizeof(flag)) != sizeof(flag))
    {
    m_ReceiveThreadFinishedEvent.Set();
    Disconnect(true);
    return ;
    } switch(flag)
    {
    case SendPageData: SendPageState(false/*send_memory*/); break;
    case SendPageDataWithMemory: SendPageState(true/*send memory*/); break;
    case EShutdownComplete: m_MemProReadyToShutdownEvent.Set(); break;
    }
    } m_ReceiveThreadFinishedEvent.Set();
    return ;
    }
    #endif //------------------------------------------------------------------------
    // http://www.debuginfo.com/articles/debuginfomatch.html #ifdef MEMPRO_WIN_BASED_PLATFORM
    struct CV_HEADER
    {
    int Signature;
    int Offset;
    }; struct CV_INFO_PDB20
    {
    CV_HEADER CvHeader;
    int Signature;
    int Age;
    char PdbFileName[MAX_PATH];
    }; struct CV_INFO_PDB70
    {
    int CvSignature;
    GUID Signature;
    int Age;
    char PdbFileName[MAX_PATH];
    };
    #endif void CMemPro::SendExtraModuleInfo(int64 ModuleBase)
    {
    #ifdef MEMPRO_PLATFORM_WIN
    IMAGE_DOS_HEADER* p_dos_header = (IMAGE_DOS_HEADER*)ModuleBase;
    IMAGE_NT_HEADERS* p_nt_header = (IMAGE_NT_HEADERS*)((char*)ModuleBase + p_dos_header->e_lfanew);
    IMAGE_OPTIONAL_HEADER& optional_header = p_nt_header->OptionalHeader;
    IMAGE_DATA_DIRECTORY& image_data_directory = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
    IMAGE_DEBUG_DIRECTORY* p_debug_info_array = (IMAGE_DEBUG_DIRECTORY*)(ModuleBase + image_data_directory.VirtualAddress);
    int count = image_data_directory.Size / sizeof(IMAGE_DEBUG_DIRECTORY);
    for(int i=; i<count; ++i)
    {
    if(p_debug_info_array[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
    {
    char* p_cv_data = (char*)(ModuleBase + p_debug_info_array[i].AddressOfRawData);
    if(strncmp(p_cv_data, "RSDS", ) == )
    {
    CV_INFO_PDB70* p_cv_info = (CV_INFO_PDB70*)p_cv_data;
    Send(true); // sending info
    Send(p_cv_info->Age);
    Send(p_cv_info->Signature);
    SendString(p_cv_info->PdbFileName);
    return; // returning here
    }
    else if(strncmp(p_cv_data, "NB10", ) == )
    {
    Send(true); // sending info
    CV_INFO_PDB20* p_cv_info = (CV_INFO_PDB20*)p_cv_data;
    Send(p_cv_info->Age);
    Send(p_cv_info->Signature);
    SendString(p_cv_info->PdbFileName);
    return; // returning here
    }
    }
    }
    #endif
    // failed to find info
    Send(false); // not sending info
    } //------------------------------------------------------------------------
    void CMemPro::SendString(const char* p_str)
    {
    const int max_path_len = ;
    int len = (int)strlen(p_str) + ;
    MEMPRO_ASSERT(len <= max_path_len); // round up to 4 bytes
    static char temp[max_path_len];
    memset(temp, , sizeof(temp));
    memcpy(temp, p_str, len); int rounded_len = ((int)len + ) & ~;
    Send(rounded_len); SendData(temp, rounded_len);
    } //------------------------------------------------------------------------
    #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
    // depending on your platform you may need to change PCSTR to PSTR for ModuleName
    BOOL CALLBACK CMemPro::EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in DWORD64 ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext)
    #else
    BOOL CALLBACK CMemPro::EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in ULONG ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext)
    #endif
    {
    CMemPro* p_this = (CMemPro*)UserContext; int64 module_base = ModuleBase;
    p_this->Send(module_base); p_this->SendString(ModuleName); p_this->SendExtraModuleInfo(ModuleBase); ++p_this->m_ModulesSent; return true;
    }
    #else
    int CMemPro::EnumerateLoadedModulesCallback(struct dl_phdr_info* info, size_t size, void* data)
    {
    CMemPro* p_this = (CMemPro*)data; int64 module_base = ;
    for (int j = ; j < info->dlpi_phnum; j++)
    {
    if (info->dlpi_phdr[j].p_type == PT_LOAD)
    {
    module_base = info->dlpi_addr + info->dlpi_phdr[j].p_vaddr;
    break;
    }
    } if(p_this->m_ModulesSent == )
    {
    // send the module base address
    int64 lookup_fn_marker = 0xabcdefabcdef1LL;
    p_this->Send(lookup_fn_marker); int64 module_base = (int64)BaseAddressLookupFunction; // use the address of the BaseAddressLookupFunction function so that we can work it out later
    p_this->Send(module_base); // get the module name
    char arg1[];
    char char_filename[MAX_PATH];
    sprintf(arg1, "/proc/%d/exe", getpid());
    memset(char_filename, , MAX_PATH);
    readlink(arg1, char_filename, MAX_PATH-);
    p_this->SendString(char_filename);
    }
    else
    {
    p_this->Send(module_base);
    p_this->SendString(info->dlpi_name);
    } p_this->SendExtraModuleInfo(); ++p_this->m_ModulesSent; return ;
    }
    #endif
    #endif //------------------------------------------------------------------------
    void CMemPro::SendModuleInfo()
    {
    Send(true); // indicate we are going to be sending module signatures - for backwards compatibility
    uint64 extra_module_info = 0xabcdef;
    Send(extra_module_info); m_ModulesSent = ; // if you are having problems compiling this on your platform undefine ENUMERATE_ALL_MODULES and it send info for just the main module
    #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #ifdef MEMPRO64
    EnumerateLoadedModules64(GetCurrentProcess(), EnumerateLoadedModulesCallback, this);
    #else
    EnumerateLoadedModules(GetCurrentProcess(), EnumerateLoadedModulesCallback, this);
    #endif
    #else
    dl_iterate_phdr(EnumerateLoadedModulesCallback, this);
    #endif
    #endif // if ENUMERATE_ALL_MODULES is disabled or enumeration failed for some reason, fall back
    // to getting the base address for the main module. This will always for for all platforms.
    if(m_ModulesSent == )
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    static int module = ;
    HMODULE module_handle = ;
    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&module, &module_handle); int64 module_base = (int64)module_handle;
    Send(module_base); TCHAR tchar_filename[MAX_PATH] = { };
    GetModuleFileName(NULL, tchar_filename, MAX_PATH); char char_filename[MAX_PATH]; #ifdef UNICODE
    size_t chars_converted = ;
    wcstombs_s(&chars_converted, char_filename, tchar_filename, MAX_PATH);
    #else
    strcpy_s(char_filename, tchar_filename);
    #endif SendString(char_filename); Send(false); // not sending SendExtraModuleInfo
    #else
    // let MemPro know we are sending the lookup function address, not the base address
    uint64 use_module_base_addr_marker = 0xabcdefabcdef1LL;
    Send(use_module_base_addr_marker); // send the module base address
    int64 module_base = (int64)BaseAddressLookupFunction; // use the address of the BaseAddressLookupFunction function so that we can work it out later
    Send(module_base); // send the module name
    char char_filename[MAX_PATH]; // get the module name
    char arg1[];
    sprintf(arg1, "/proc/%d/exe", getpid());
    memset(char_filename, , MAX_PATH);
    readlink(arg1, char_filename, MAX_PATH-); SendString(char_filename); Send(false); // not sending SendExtraModuleInfo
    #endif
    } uint64 terminator = ;
    Send(terminator);
    } //------------------------------------------------------------------------
    bool CMemPro::WaitForConnection()
    {
    m_CriticalSection.Enter(); #ifdef WRITE_DUMP
    OutputDebugString(_T("MemPro writing to dump file " WRITE_DUMP _T("\n")));
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    _tfopen_s(&gp_DumpFile, WRITE_DUMP, _T("wb"));
    #else
    gp_DumpFile = fopen(WRITE_DUMP, _T("wb"));
    #endif
    MEMPRO_ASSERT(gp_DumpFile); m_Connected = true; m_SendThreadFinishedEvent.Reset(); // start the sending thread
    int thread_id = ;
    m_SendThread.CreateThread(SendThreadMainStatic, &thread_id);
    SetThreadName(thread_id, "MemPro write thread");
    #else
    // start listening for connections
    if(m_ListenSocket.IsValid() && !m_ListenSocket.StartListening())
    {
    m_WaitForConnectThreadFinishedEvent.Set(); // do this before Shutdown
    Shutdown();
    m_CriticalSection.Leave();
    return false;
    } m_StartedListening = true;
    m_StartedListeningEvent.Set(); // Accept a client socket
    bool accepted = false;
    if(m_ListenSocket.IsValid())
    {
    m_CriticalSection.Leave();
    accepted = m_ListenSocket.Accept(m_ClientSocket); if(!accepted)
    {
    bool shutting_down = m_ShuttingDown;
    m_WaitForConnectThreadFinishedEvent.Set(); // do this before Shutdown
    if(!shutting_down) // check shutting down here in case CMemPro has been destructed
    {
    m_CriticalSection.Enter();
    Shutdown();
    m_CriticalSection.Leave();
    }
    return false;
    }
    } m_CriticalSection.Enter(); m_Connected = true; m_SendThreadFinishedEvent.Reset();
    m_ReceiveThreadFinishedEvent.Reset(); // start the sending thread
    int send_thread_id = ;
    m_SendThread.CreateThread(SendThreadMainStatic, &send_thread_id);
    SetThreadName(send_thread_id, "MemPro send thread"); // start the receiving thread
    int receive_thread_id = ;
    m_ReceiveThread.CreateThread(ReceiveThreadMainStatic, &receive_thread_id);
    SetThreadName(receive_thread_id, "MemPro receive thread");
    #endif
    // send the connect key
    unsigned int endian_key = (unsigned int)EndianKey;
    ENDIAN_TEST(SwapEndian(endian_key));
    Send(endian_key); // send the connect packet
    ConnectPacket connect_packet;
    connect_packet.m_Padding = 0xabcdabcd;
    connect_packet.m_Version = MemPro::Version;
    connect_packet.m_TickFrequency = GetTickFrequency();
    connect_packet.m_ConnectTime = GetTime(); connect_packet.m_PtrSize = sizeof(void*); #ifdef MEMPRO_WIN_BASED_PLATFORM
    connect_packet.m_Platform = Platform_Windows;
    #else
    connect_packet.m_Platform = Platform_Unix;
    #endif ENDIAN_TEST(connect_packet.SwapEndian());
    Send(connect_packet); SendModuleInfo(); #if defined(MEMPRO_PLATFORM_WIN)
    #if (!defined(MIDL_PASS) && defined(_M_IX86) && !defined(_M_CEE_PURE)) || defined(MemoryBarrier)
    MemoryBarrier();
    #else
    std::atomic_thread_fence(std::memory_order_seq_cst);
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    __sync_synchronize();
    #else
    #error platform not defined
    #endif SendStoredData(); m_ReadyToSend = true; m_WaitForConnectThreadFinishedEvent.Set();
    m_CriticalSection.Leave(); // start the pulse thread
    int pulse_thread_id = ;
    m_PulseThreadFinished.Reset();
    m_PulseThread.CreateThread(PulseThreadMainStatic, &pulse_thread_id);
    SetThreadName(pulse_thread_id, "MemPro pulse thread"); return true;
    } //------------------------------------------------------------------------
    int CMemPro::WaitForConnectionThreadMainStatic(void* p_param)
    {
    return gp_MemPro->WaitForConnectionThreadMain(p_param);
    } //------------------------------------------------------------------------
    int CMemPro::PulseThreadMainStatic(void* p_param)
    {
    gp_MemPro->PulseThreadMain();
    return ;
    } //------------------------------------------------------------------------
    void CMemPro::PulseThreadMain()
    {
    while(m_Connected)
    {
    {
    CriticalSectionScope lock(m_CriticalSection);
    if(!m_Connected)
    break; SendPacketHeader(EPulsePacket);
    SendEndMarker();
    } Sleep();
    } m_PulseThreadFinished.Set();
    } //------------------------------------------------------------------------
    int CMemPro::WaitForConnectionThreadMain(void* p_param)
    {
    #ifdef WRITE_DUMP
    Sleep(MEMPRO_INIT_DELAY);
    #else
    if(!m_ListenSocket.IsValid())
    {
    Sleep(MEMPRO_INIT_DELAY); bool bind_result = m_ListenSocket.Bind(g_DefaultPort); if(!bind_result)
    OutputDebugString(_T("MemPro ERROR: Failed to bind port. This usually means that another process is already running with MemPro enabled.\n"));
    MEMPRO_ASSERT(bind_result);
    if(!bind_result)
    return ;
    }
    #endif
    WaitForConnection(); return ;
    } //------------------------------------------------------------------------
    bool CMemPro::Initialise()
    {
    m_WaitForConnectionThread.CreateThread(WaitForConnectionThreadMainStatic, NULL); return true;
    } //------------------------------------------------------------------------
    void CMemPro::Shutdown()
    {
    m_ShuttingDown = true; // wait for MemPro to have handled all data
    if(m_SendThread.IsAlive())
    {
    SendPacketHeader(ERequestShutdown);
    SendEndMarker();
    m_MemProReadyToShutdownEvent.Wait( * ); // do this so that we don't start listening after the listen socket has been shutdown and deadlock
    m_CriticalSection.Leave();
    m_StartedListeningEvent.Wait();
    m_CriticalSection.Enter(); if(m_WaitForConnect)
    {
    BlockUntilReadyToSend();
    BlockUntilSendThreadEmpty();
    }
    } Disconnect(false/*listen_for_new_connection*/); m_CriticalSection.Leave();
    m_PulseThreadFinished.Wait();
    m_CriticalSection.Enter(); #ifndef WRITE_DUMP
    m_ListenSocket.Disconnect(); if(m_WaitForConnectionThread.IsAlive())
    m_WaitForConnectThreadFinishedEvent.Wait(); #ifdef MEMPRO_WIN_BASED_PLATFORM
    WSACleanup();
    #endif
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::Disconnect(bool listen_for_new_connection)
    {
    CriticalSectionScope lock(m_DisconnectCriticalSection); if(m_Connected)
    {
    m_ReadyToSend = false;
    m_Connected = false; // wait for the send thread to shutdown
    m_SendThreadFinishedEvent.Wait();
    m_SendThreadFinishedEvent.Reset(); #ifdef WRITE_DUMP
    fclose(gp_DumpFile);
    gp_DumpFile = NULL;
    #else
    // close the client socket
    m_ClientSocket.Disconnect(); // wait for the receive thread to shutdown
    m_ReceiveThreadFinishedEvent.Wait();
    m_ReceiveThreadFinishedEvent.Reset();
    #endif
    // clear stuff
    m_CallstackSet.Clear(); m_RingBuffer.Clear(); #ifndef WRITE_DUMP
    if(listen_for_new_connection)
    {
    CriticalSectionScope lock2(m_CriticalSection); // start listening for another connection
    m_ListenSocket.Disconnect();
    m_StartedListeningEvent.Reset();
    m_StartedListening = false;
    m_InitialConnectionTimedOut = false;
    m_WaitForConnectionThread.CreateThread(WaitForConnectionThreadMainStatic, NULL);
    }
    #endif
    }
    } //------------------------------------------------------------------------
    void CMemPro::BlockUntilReadyToSend()
    {
    #ifndef WRITE_DUMP
    if(m_ListenSocket.IsValid())
    {
    OutputDebugString(_T("Waiting for connection to MemPro...\n")); int64 start_time = GetTime();
    while(!m_ReadyToSend && m_ListenSocket.IsValid() &&
    (m_WaitForConnect || ((GetTime() - start_time) / (double)GetTickFrequency()) * < MEMPRO_CONNECT_TIMEOUT))
    {
    m_CriticalSection.Leave();
    Sleep();
    m_CriticalSection.Enter();
    } if(m_ReadyToSend)
    {
    OutputDebugString(_T("Connected to MemPro!\n"));
    }
    else
    {
    m_InitialConnectionTimedOut = true;
    ClearStoreData();
    OutputDebugString(_T("Failed to connect to MemPro\n"));
    }
    }
    #endif
    } //------------------------------------------------------------------------
    // return true to continue processing event (either connected or before started listening)
    bool CMemPro::WaitForConnectionIfListening()
    {
    #ifdef WRITE_DUMP
    return true;
    #else
    if(!m_ReadyToSend && !m_InitialConnectionTimedOut)
    {
    CriticalSectionScope lock(m_CriticalSection); // store data until we have started listening
    if(!m_StartedListening)
    return true; BlockUntilReadyToSend();
    } return m_ReadyToSend;
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::TrackAlloc(void* p, size_t size, bool wait_for_connect)
    {
    if(m_Paused)
    return; m_WaitForConnect = wait_for_connect; if(!WaitForConnectionIfListening())
    return; CallstackCapture callstack_capture = CaptureCallstack(); CriticalSectionScope lock(m_CriticalSection); #ifndef WRITE_DUMP
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(m_ListenSocket.IsValid())
    {
    int now = GetTickCount();
    if(now - m_LastPageStateSend > m_PageStateInterval)
    {
    SendVirtualMemStats();
    m_LastPageStateSend = now;
    } if(now - m_LastVMemStatsSend > m_VMemStatsSendInterval)
    {
    SendVMemStats();
    m_LastVMemStatsSend = now;
    }
    }
    #endif
    #endif
    if(m_InEvent)
    return;
    m_InEvent = true; int callstack_id = SendCallstack(callstack_capture); SendPacketHeader(EAllocPacket); AllocPacket packet;
    packet.m_Addr = ToUInt64(p);
    packet.m_Size = size;
    packet.m_CallstackID = callstack_id;
    packet.m_Padding = 0xef12ef12;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); SendEndMarker(); m_InEvent = false;
    } //------------------------------------------------------------------------
    void CMemPro::TrackFree(void* p, bool wait_for_connect)
    {
    if(m_Paused)
    return; m_WaitForConnect = wait_for_connect; if(!WaitForConnectionIfListening())
    return; CriticalSectionScope lock(m_CriticalSection); if(m_InEvent)
    return;
    m_InEvent = true; SendPacketHeader(EFreePacket); FreePacket packet;
    packet.m_Addr = ToUInt64(p);
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); SendEndMarker(); m_InEvent = false;
    } //------------------------------------------------------------------------
    bool CMemPro::IsPaused()
    {
    return m_Paused;
    } //------------------------------------------------------------------------
    void CMemPro::SetPaused(bool paused)
    {
    m_Paused = paused;
    } //------------------------------------------------------------------------
    void CMemPro::SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(!WaitForConnectionIfListening())
    return; SendPacketHeader(EPageStatePacket); bool send_page_mem = send_memory && page_state == Committed && (page_protection & (PAGE_NOACCESS | PAGE_EXECUTE | PAGE_GUARD)) == ; PageStatePacket packet;
    packet.m_Addr = ToUInt64(p);
    packet.m_Size = size;
    packet.m_State = page_state;
    packet.m_Type = page_type;
    packet.m_Protection = page_protection;
    packet.m_SendingMemory = send_page_mem;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); if(send_page_mem)
    {
    MEMPRO_ASSERT(!(size % PAGE_SIZE));
    char* p_page = (char*)p;
    char* p_end_page = p_page + size;
    while(p_page != p_end_page)
    {
    SendData(p_page, PAGE_SIZE);
    p_page += PAGE_SIZE;
    }
    } SendEndMarker();
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::WaitForConnectionOnInitialise()
    {
    m_WaitForConnect = true; m_StartedListeningEvent.Wait(); CriticalSectionScope lock(m_CriticalSection);
    BlockUntilReadyToSend();
    }
    } //------------------------------------------------------------------------
    void MemPro::InitialiseInternal()
    {
    if(!gp_MemPro && !g_ShuttingDown)
    {
    gp_MemPro = (CMemPro*)g_MemProMem;
    new (gp_MemPro)CMemPro();
    gp_MemPro->Initialise();
    }
    } //------------------------------------------------------------------------
    void MemPro::IncRef()
    {
    ++g_MemProRefs;
    } //------------------------------------------------------------------------
    void MemPro::DecRef()
    {
    if(--g_MemProRefs == )
    Shutdown();
    } //------------------------------------------------------------------------
    // called by the APP (not internally)
    void MemPro::Initialise(bool wait_for_connect)
    {
    InitialiseInternal(); if(wait_for_connect)
    gp_MemPro->WaitForConnectionOnInitialise();
    } //------------------------------------------------------------------------
    void MemPro::Disconnect()
    {
    if(gp_MemPro)
    {
    gp_MemPro->Lock();
    gp_MemPro->Disconnect(true);
    gp_MemPro->Release();
    }
    } //------------------------------------------------------------------------
    void MemPro::Shutdown()
    {
    if(!g_ShuttingDown)
    {
    g_ShuttingDown = true;
    if(gp_MemPro)
    {
    gp_MemPro->Lock();
    gp_MemPro->Shutdown();
    gp_MemPro->Release();
    gp_MemPro->~CMemPro();
    memset(gp_MemPro, , sizeof(CMemPro));
    gp_MemPro = NULL;
    }
    }
    } //------------------------------------------------------------------------
    void MemPro::TrackAlloc(void* p, size_t size, bool wait_for_connect)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->TrackAlloc(p, size, wait_for_connect);
    } //------------------------------------------------------------------------
    void MemPro::TrackFree(void* p, bool wait_for_connect)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->TrackFree(p, wait_for_connect);
    } //------------------------------------------------------------------------
    void MemPro::SetPaused(bool paused)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->SetPaused(paused);
    } //------------------------------------------------------------------------
    bool MemPro::IsPaused()
    {
    CMemPro* p_mempro = GetMemPro();
    return p_mempro ? p_mempro->IsPaused() : false;
    } //------------------------------------------------------------------------
    void MemPro::SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->SendPageState(p, size, page_state, page_type, page_protection, send_memory);
    } //------------------------------------------------------------------------
    void MemPro::TakeSnapshot()
    {
    if(gp_MemPro) gp_MemPro->TakeSnapshot();
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO
    //------------------------------------------------------------------------
    // MemProLib.cpp //------------------------------------------------------------------------
    namespace MemPro
    {
    int mempro_total_alloc = ; //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_XBOXONE)
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif
    }
    //------------------------------------------------------------------------
    // Socket.cpp #include <stdlib.h>
    #include <new> #ifdef MEMPRO_WIN_BASED_PLATFORM
    #include <tchar.h>
    #endif //------------------------------------------------------------------------
    #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    namespace MemPro
    {
    volatile int g_InitialiseCount = ;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::InitialiseWSA()
    {
    if(g_InitialiseCount == )
    {
    #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif #ifdef MEMPRO_WIN_BASED_PLATFORM
    // Initialize Winsock
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(,), &wsaData) != )
    {
    HandleError();
    return false;
    }
    #endif
    } ++g_InitialiseCount; return true;
    } //------------------------------------------------------------------------
    void MemPro::Socket::CleanupWSA()
    {
    --g_InitialiseCount; if(g_InitialiseCount == )
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(WSACleanup() == SOCKET_ERROR)
    HandleError();
    #endif #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif
    }
    } //------------------------------------------------------------------------
    void MemPro::Socket::Disconnect()
    {
    if(m_Socket != INVALID_SOCKET)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(shutdown(m_Socket, SD_BOTH) == SOCKET_ERROR)
    HandleError();
    #else
    if(shutdown(m_Socket, SHUT_RDWR) == SOCKET_ERROR)
    HandleError();
    #endif // loop until the socket is closed to ensure all data is sent
    unsigned int buffer = ;
    size_t ret = ;
    do { ret = recv(m_Socket, (char*)&buffer, sizeof(buffer), ); } while(ret != && ret != (size_t)SOCKET_ERROR); #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(closesocket(m_Socket) == SOCKET_ERROR)
    HandleError();
    #else
    close(m_Socket);
    #endif
    m_Socket = INVALID_SOCKET;
    }
    } //------------------------------------------------------------------------
    bool MemPro::Socket::StartListening()
    {
    MEMPRO_ASSERT(m_Socket != INVALID_SOCKET); if (listen(m_Socket, SOMAXCONN) == SOCKET_ERROR)
    {
    HandleError();
    return false;
    }
    return true;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Bind(const char* p_port)
    {
    MEMPRO_ASSERT(m_Socket == INVALID_SOCKET); if(!InitialiseWSA())
    return false; #ifdef MEMPRO_PLATFORM_WIN
    // setup the addrinfo struct
    addrinfo info;
    ZeroMemory(&info, sizeof(info));
    info.ai_family = AF_INET;
    info.ai_socktype = SOCK_STREAM;
    info.ai_protocol = IPPROTO_TCP;
    info.ai_flags = AI_PASSIVE; // Resolve the server address and port
    addrinfo* p_result_info;
    HRESULT result = getaddrinfo(NULL, p_port, &info, &p_result_info);
    if (result != )
    {
    HandleError();
    return false;
    } m_Socket = socket(
    p_result_info->ai_family,
    p_result_info->ai_socktype,
    p_result_info->ai_protocol);
    #else
    m_Socket = socket(
    AF_INET,
    SOCK_STREAM,
    IPPROTO_TCP);
    #endif if (m_Socket == INVALID_SOCKET)
    {
    #ifdef MEMPRO_PLATFORM_WIN
    freeaddrinfo(p_result_info);
    #endif
    HandleError();
    return false;
    } // Setup the TCP listening socket
    #ifdef MEMPRO_PLATFORM_WIN
    result = ::bind(m_Socket, p_result_info->ai_addr, (int)p_result_info->ai_addrlen);
    freeaddrinfo(p_result_info);
    #else
    // Bind to INADDR_ANY
    SOCKADDR_IN sa;
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = INADDR_ANY;
    int iport = atoi(p_port);
    sa.sin_port = htons(iport);
    int result = ::bind(m_Socket, (const sockaddr*)(&sa), sizeof(SOCKADDR_IN));
    #endif if (result == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return false;
    } return true;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Accept(Socket& client_socket)
    {
    MEMPRO_ASSERT(client_socket.m_Socket == INVALID_SOCKET);
    client_socket.m_Socket = accept(m_Socket, NULL, NULL);
    return client_socket.m_Socket != INVALID_SOCKET;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Send(void* p_buffer, int size)
    {
    int bytes_to_send = size;
    while(bytes_to_send != )
    {
    int bytes_sent = (int)send(m_Socket, (char*)p_buffer, bytes_to_send, );
    if(bytes_sent == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return false;
    }
    p_buffer = (char*)p_buffer + bytes_sent;
    bytes_to_send -= bytes_sent;
    } return true;
    } //------------------------------------------------------------------------
    int MemPro::Socket::Receive(void* p_buffer, int size)
    {
    int total_bytes_received = ;
    while(size)
    {
    int bytes_received = (int)recv(m_Socket, (char*)p_buffer, size, ); total_bytes_received += bytes_received; if(bytes_received == )
    {
    Disconnect();
    return bytes_received;
    }
    else if(bytes_received == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return bytes_received;
    } size -= bytes_received;
    p_buffer = (char*)p_buffer + bytes_received;
    } return total_bytes_received;
    } //------------------------------------------------------------------------
    void MemPro::Socket::HandleError()
    {
    #ifdef MEMPRO_PLATFORM_WIN
    if(WSAGetLastError() == WSAEADDRINUSE)
    {
    OutputDebugString(_T("MemPro: Network connection conflict. Please make sure that other MemPro enabled applications are shut down, or change the port in the the MemPro lib and MemPro settings.\n"));
    return;
    } TCHAR* p_buffer = NULL;
    va_list args;
    FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    WSAGetLastError(),
    ,
    (TCHAR*)&p_buffer,
    * ,
    &args); OutputDebugString(p_buffer); LocalFree(p_buffer);
    #endif
    } //------------------------------------------------------------------------
    #endif // #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP)
    //------------------------------------------------------------------------
    // Thread.cpp //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    MemPro::Thread::Thread()
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    : m_Handle(),
    m_Alive(false)
    #else
    : m_Alive(false)
    #endif
    {
    } //------------------------------------------------------------------------
    void MemPro::Thread::CreateThread(ThreadMain p_thread_main, void* p_param)
    {
    mp_ThreadMain = p_thread_main;
    mp_Param = p_param; #ifdef MEMPRO_WIN_BASED_PLATFORM
    m_Handle = ::CreateThread(NULL, , PlatformThreadMain, this, , NULL);
    #else
    pthread_create(&m_Thread, NULL, PlatformThreadMain, this);
    #endif
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    unsigned long WINAPI MemPro::Thread::PlatformThreadMain(void* p_param)
    {
    Thread* p_thread = (Thread*)p_param;
    p_thread->m_Alive = true;
    unsigned long ret = (unsigned long)p_thread->mp_ThreadMain(p_thread->mp_Param);
    p_thread->m_Alive = false;
    return ret;
    }
    #else
    void* MemPro::Thread::PlatformThreadMain(void* p_param)
    {
    Thread* p_thread = (Thread*)p_param;
    p_thread->m_Alive = true;
    p_thread->mp_ThreadMain(p_thread->mp_Param);
    p_thread->m_Alive = false;
    return NULL;
    }
    #endif //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO

    MemPro.cpp

    这两个是官方原始的1.3.7.0的代码,关于检测内存泄露比较具有研究价值;

  • 整合并入UE4的方法, 这里先只有windows和XBoxOne平台,修改后的MemPro.hpp和MemPro.cpp:
  • /*
    This software is provided 'as-is', without any express or implied warranty.
    In no event will the author(s) be held liable for any damages arising from
    the use of this software. Permission is granted to anyone to use this software for any purpose, including
    commercial applications, and to alter it and redistribute it freely, subject to
    the following restrictions: 1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution. Author: Stewart Lynch
    www.puredevsoftware.com
    slynch@puredevsoftware.com This code is released to the public domain, as explained at
    http://creativecommons.org/publicdomain/zero/1.0/ MemProLib is the library that allows the MemPro application to communicate
    with your application. ===========================================================
    SETUP
    =========================================================== * include MemPro.cpp and MemPro.hpp into your project. * Link with Dbghelp.lib and Ws2_32.lib - these are needed for the callstack trace and the network connection * Connect to your app with the MemPro
    */ //------------------------------------------------------------------------
    // MemPro.hpp
    //------------------------------------------------------------------------
    /*
    MemPro
    Version: 1.3.7.0
    */
    //------------------------------------------------------------------------
    #ifndef MEMPRO_MEMPRO_H_INCLUDED
    #define MEMPRO_MEMPRO_H_INCLUDED //------------------------------------------------------------------------
    //#define ENABLE_MEMPRO // **** enable/disable MemPro here! **** //@Virtuos[wangsongwei] disable it here
    //@Virtuos[wangsongwei] begin: add new macro ENABLE_VIRTUOS_MEMPRO_UE4 to support integrate MemPro into UE4, open it in file Build.h
    #ifdef ENABLE_VIRTUOS_MEMPRO_UE4
    #define ENABLE_MEMPRO //comment this line to disable // #if PLATFORM_XBOXONE
    // #define WAIT_FOR_CONNECT
    // #define WAIT_FOR_CONNECT true
    // #endif #endif
    //@Virtuos[wangsongwei]end //------------------------------------------------------------------------
    // macros for tracking allocs that define to nothing if disabled
    #ifdef ENABLE_MEMPRO
    #ifndef WAIT_FOR_CONNECT
    #define WAIT_FOR_CONNECT false
    #endif
    #define MEMPRO_TRACK_ALLOC(p, size) MemPro::TrackAlloc(p, size, WAIT_FOR_CONNECT)
    #define MEMPRO_TRACK_FREE(p) MemPro::TrackFree(p, WAIT_FOR_CONNECT)
    #else
    #define MEMPRO_TRACK_ALLOC(p, size) ((void)0)
    #define MEMPRO_TRACK_FREE(p) ((void)0)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    // Some platforms have problems initialising winsock from global constructors,
    // to help get around this problem MemPro waits this amount of time before
    // initialising. Allocs and freed that happen during this time are stored in
    // a temporary buffer.
    #define MEMPRO_INIT_DELAY 100 //------------------------------------------------------------------------
    // MemPro waits this long before giving up on a connection after initialisation
    #define MEMPRO_CONNECT_TIMEOUT 500
    //#define MEMPRO_CONNECT_TIMEOUT 1000 //@Virtuos[wangsongwei] define wait time out is one second, if this time is too long, it will cause x1 crash with timeout loading //------------------------------------------------------------------------
    #include <stdlib.h> //------------------------------------------------------------------------
    //#define WRITE_DUMP _T("allocs.mempro_dump") //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    enum PageState
    {
    Invalid = -,
    Free,
    Reserved,
    Committed
    }; //------------------------------------------------------------------------
    enum PageType
    {
    page_Unknown = -,
    page_Image,
    page_Mapped,
    page_Private
    }; //------------------------------------------------------------------------ // You don't need to call this directly, it is automatically called on the first allocation.
    // Only call this function if you want to be able to connect to your app before it has allocated any memory.
    // If wait_for_connect is true this function will block until the external MemPro app has connected,
    // this is useful to make sure that every single allocation is being tracked.
    void Initialise(bool wait_for_connect=false); void Disconnect(); // kick all current connections, but can accept more void Shutdown(); // free all resources, no more connections allowed void TrackAlloc(void* p, size_t size, bool wait_for_connect=false); void TrackFree(void* p, bool wait_for_connect=false); bool IsPaused(); void SetPaused(bool paused); // this is used for the realtime memory graph.
    void SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory); void TakeSnapshot(); // ignore these, for internal use only
    void IncRef();
    void DecRef();
    } //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    namespace
    {
    // if we are using sockets we need to flush the sockets on global teardown
    // This class is a trick to attempt to get mempro to shutdown after all other
    // global objects.
    class MemProGLobalScope
    {
    public:
    MemProGLobalScope() { MemPro::IncRef(); }
    ~MemProGLobalScope() { MemPro::DecRef(); }
    };
    static MemProGLobalScope g_MemProGLobalScope;
    }
    #endif //------------------------------------------------------------------------
    #ifndef ENABLE_VIRTUOS_MEMPRO_UE4//@Virtuos[wangsongwei] UE4 don't need override these new/delete/malloc/free operator here
    #ifdef OVERRIDE_NEW_DELETE #if defined(__APPLE__)
    // if you get linker errors about duplicatly defined symbols please add a unexport.txt
    // file to your build settings
    // see here: https://developer.apple.com/library/mac/technotes/tn2185/_index.html
    void* operator new(std::size_t size) throw(std::bad_alloc)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void* operator new(std::size_t size, const std::nothrow_t&) throw()
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete(void* p) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void operator delete(void* p, const std::nothrow_t&) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void* operator new[](std::size_t size) throw(std::bad_alloc)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void* operator new[](std::size_t size, const std::nothrow_t&) throw()
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete[](void* p) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void operator delete[](void* p, const std::nothrow_t&) throw()
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    }
    #else
    #include <malloc.h> void* operator new(size_t size)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete(void* p)
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    } void* operator new[](size_t size)
    {
    void* p = malloc(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void operator delete[](void* p)
    {
    MEMPRO_TRACK_FREE(p);
    free(p);
    }
    #endif #endif //------------------------------------------------------------------------
    #ifdef OVERRIDE_MALLOC_FREE #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(__WIN32__) || defined(__WINDOWS__) // NOTE: for this to work, you will need to make sure you are linking STATICALLY to the crt. eg: /MTd __declspec(restrict) __declspec(noalias) void* malloc(size_t size)
    {
    void* p = HeapAlloc(GetProcessHeap(), , size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } __declspec(restrict) __declspec(noalias) void* realloc(void *p, size_t new_size)
    {
    MEMPRO_TRACK_FREE(p);
    void* p_new = HeapReAlloc(GetProcessHeap(), , p, new_size);
    MEMPRO_TRACK_ALLOC(p_new, new_size);
    return p_new;
    } __declspec(noalias) void free(void *p)
    {
    HeapFree(GetProcessHeap(), , p);
    MEMPRO_TRACK_FREE(p);
    }
    #else
    void *malloc(int size)
    {
    void* (*ptr)(int);
    void* handle = (void*)-;
    ptr = (void*)dlsym(handle, "malloc");
    if(!ptr) abort();
    void *p = (*ptr)(size);
    MEMPRO_TRACK_ALLOC(p, size);
    return p;
    } void *realloc(void *p, int size)
    {
    MEMPRO_TRACK_FREE(p);
    void * (*ptr)(void *, int);
    void * handle = (void*) -;
    ptr = (void*)dlsym(handle, "realloc");
    if (!ptr) abort();
    void* p_new = (*ptr)(p, size);
    MEMPRO_TRACK_ALLOC(p_new, size);
    return p_new;
    } void free(void *p)
    {
    MEMPRO_TRACK_FREE(p);
    void* (*ptr)(void*);
    void* handle = (void*)-;
    ptr = (void*)dlsym(handle, "free");
    if (!ptr == NULL) abort();
    (*ptr)(alloc);
    }
    #endif
    #endif
    #endif//@Virtuos[wangsongwei] #ifndef ENABLE_VIRTUOS_MEMPRO_UE4
    //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPRO_H_INCLUDED

    MemPro.hpp

    /*
    This software is provided 'as-is', without any express or implied warranty.
    In no event will the author(s) be held liable for any damages arising from
    the use of this software. Permission is granted to anyone to use this software for any purpose, including
    commercial applications, and to alter it and redistribute it freely, subject to
    the following restrictions: 1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution. Author: Stewart Lynch
    www.puredevsoftware.com
    slynch@puredevsoftware.com This code is released to the public domain, as explained at
    http://creativecommons.org/publicdomain/zero/1.0/ MemProLib is the library that allows the MemPro application to communicate
    with your application.
    */ //@Virtuos[wangsongwei]begin: enable MemPro's original UE4 macro
    #ifdef ENABLE_VIRTUOS_MEMPRO_UE4
    #define FRAMEPRO_TOOLSET_UE4 1 //comment this line to disable UE4
    #endif
    //@Virtuos[wangsongwei]end #if FRAMEPRO_TOOLSET_UE4
    #include "CorePrivatePCH.h"
    #endif #include "MemPro.hpp" //------------------------------------------------------------------------
    // CallstackSet.cpp //------------------------------------------------------------------------
    // MemProLib.hpp
    #ifndef MEMPRO_MEMPROLIB_H_INCLUDED
    #define MEMPRO_MEMPROLIB_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    // **** The Target Platform **** // define ONE of these #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(__WIN32__) || defined(__WINDOWS__)
    #if PLATFORM_XBOXONE || defined(_XBOX_ONE) //@Virtuos[wangsongwei] also add UE4's xboxone macro
    #define MEMPRO_PLATFORM_XBOXONE
    //#elif defined(_XBOX)
    // #define MEMPRO_PLATFORM_XBOX360 //@Virtuos[wangsongwei] not Xbox360 any more
    #elif PLATFORM_WINDOWS //@Virtuos[wangsongwei]add UE4's windows macro
    #define MEMPRO_PLATFORM_WIN
    #endif
    #elif defined(__APPLE__)
    #define MEMPRO_PLATFORM_APPLE
    #else
    #define MEMPRO_PLATFORM_UNIX //@Virtuos[wangsongwei] todo, PS4 should be here
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN) || defined(MEMPRO_PLATFORM_XBOX360) || defined(MEMPRO_PLATFORM_XBOXONE)
    #define MEMPRO_WIN_BASED_PLATFORM
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_UNIX) || defined(MEMPRO_PLATFORM_APPLE)
    #define MEMPRO_UNIX_BASED_PLATFORM
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN)
    #if (defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4)
    #include "AllowWindowsPlatformTypes.h"
    #endif
    #ifndef WRITE_DUMP
    #if defined(UNICODE) && !defined(_UNICODE)
    #error for unicode builds please define both UNICODE and _UNICODE. See the FAQ for more details.
    #endif
    #if defined(AF_IPX) && !defined(_WINSOCK2API_)
    #error winsock already defined. Please include winsock2.h before including windows.h or use WIN32_LEAN_AND_MEAN. See the FAQ for more info.
    #endif
    #define WIN32_LEAN_AND_MEAN #pragma warning(push)
    #pragma warning(disable : 4668)
    #include <winsock2.h>
    #pragma warning(pop) #include <ws2tcpip.h>
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0501
    #endif
    #define WINDOWS_LEAN_AND_MEAN
    #include <windows.h>
    #include <intrin.h>
    #endif
    #if (defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4)
    #include "HideWindowsPlatformTypes.h"
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //#error Please contact slynch@puredevsoftware.com for this platform //@Virtuos[wangsongwei] I don't know what I need to do here, just annotate this line avoid compile error, maybe need include some necessary header files
    #if (defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4)
    #include "AllowXboxOnePlatformTypes.h"//@Virtuos[wangsongwei] add code support X1 version
    #endif
    #ifndef WRITE_DUMP
    //@Virtuos[wangsongwei] XboxOne should use same header file as Windows's
    #if defined(UNICODE) && !defined(_UNICODE)
    #error for unicode builds please define both UNICODE and _UNICODE. See the FAQ for more details.
    #endif
    #if defined(AF_IPX) && !defined(_WINSOCK2API_)
    #error winsock already defined. Please include winsock2.h before including windows.h or use WIN32_LEAN_AND_MEAN. See the FAQ for more info.
    #endif
    #define WIN32_LEAN_AND_MEAN #pragma warning(push)
    #pragma warning(disable : 4668)
    #include <winsock2.h>
    #pragma warning(pop) #include <ws2tcpip.h>
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0501
    #endif
    #define WINDOWS_LEAN_AND_MEAN
    #include <windows.h>
    #include <intrin.h>
    #endif
    #if (defined(FRAMEPRO_TOOLSET_UE4) && FRAMEPRO_TOOLSET_UE4)
    #include "HideXboxOnePlatformTypes.h"//@Virtuos[wangsongwei] add code support X1 version
    #endif
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)//@Virtuos[wangsongwei] PS4 should be here
    #include <execinfo.h>
    #include <inttypes.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <sys/time.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <unistd.h>
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    #if defined(_WIN64) || defined(__LP64__) || defined(__x86_64__) || defined(__ppc64__)
    #define MEMPRO64
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_XBOXONE) && !defined(MEMPRO64)
    #error Please contact slynch@puredevsoftware.com for this platform
    //@Virtuos[wangsongwei] todo
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    #define MEMPRO_ASSERT(b) if(!(b)) DebugBreak()
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    #define MEMPRO_ASSERT(b) if(!(b)) __builtin_trap()
    #else
    #error // platform not defined
    #endif //------------------------------------------------------------------------
    #define MEMPRO_STATIC_ASSERT(expr) typedef char STATIC_ASSERT_TEST[ (expr) ] //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class Allocator
    {
    public:
    #if defined(MEMPRO_PLATFORM_XBOXONE)
    //#error Please contact slynch@puredevsoftware.com for this platform
    //@Virtuos[wangsongwei]begin: XboxOne also has these function
    static void* Alloc(int size)
    {
    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
    }
    static void Free(void* p, int size)
    {
    VirtualFree(p, size, MEM_RELEASE);
    }
    //@Virtuos[wangsongwei]end
    #elif defined(MEMPRO_WIN_BASED_PLATFORM)//@Virtuos[wangsongwei] in fact xboxone also enable this macro
    static void* Alloc(int size)
    {
    return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
    }
    static void Free(void* p, int size)
    {
    VirtualFree(p, size, MEM_RELEASE);
    }
    #else
    static void* Alloc(int size) { return malloc(size); }
    static void Free(void* p, int size) { free(p); }
    #endif
    }; //------------------------------------------------------------------------
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    typedef __int64 int64;
    typedef unsigned __int64 uint64;
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    typedef long long int64;
    typedef unsigned long long uint64;
    #else
    #error
    #endif //------------------------------------------------------------------------
    // platform specific stuff
    #if defined(MEMPRO_WIN_BASED_PLATFORM)
    #define MEMPRO_FORCEINLINE FORCEINLINE
    #else
    #define MEMPRO_FORCEINLINE inline
    void memcpy_s(void* p_dst, int dst_len, void* p_src, int copy_len) { memcpy(p_dst, p_src, copy_len); }
    void Sleep(int ms) { usleep( * ms); }
    typedef int SOCKET;
    typedef int DWORD;
    enum SocketValues { INVALID_SOCKET = - };
    #ifndef UINT_MAX
    enum MaxValues { UINT_MAX = 0xffffffff };
    #endif
    void OutputDebugString(const char*) {}
    #define _T(s) s
    enum SocketErrorCodes { SOCKET_ERROR = - };
    typedef sockaddr_in SOCKADDR_IN;
    enum SystemDefines { MAX_PATH = };
    #endif
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPROLIB_H_INCLUDED //------------------------------------------------------------------------
    // CallstackSet.hpp
    #ifndef MEMPRO_CALLSTACKSET_H_INCLUDED
    #define MEMPRO_CALLSTACKSET_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    struct Callstack
    {
    uint64* mp_Stack;
    int m_ID;
    int m_Size;
    unsigned int m_Hash;
    }; //------------------------------------------------------------------------
    // A hash set collection for Callstack structures. Callstacks are added and
    // retreived using the stack address array as the key.
    // This class only allocates memory using virtual alloc/free to avoid going
    // back into the mian allocator.
    class CallstackSet
    {
    public:
    CallstackSet(); ~CallstackSet(); Callstack* Get(uint64* p_stack, int stack_size, unsigned int hash); Callstack* Add(uint64* p_stack, int stack_size, unsigned int hash); void Clear(); private:
    void Grow(); void Add(Callstack* p_callstack); //------------------------------------------------------------------------
    // data
    private:
    Callstack** mp_Data;
    unsigned int m_CapacityMask;
    int m_Count;
    int m_Capacity;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_CALLSTACKSET_H_INCLUDED //------------------------------------------------------------------------
    // BlockAllocator.hpp
    #ifndef MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED
    #define MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    // a very simple allocator tat allocated blocks of 64k of memory using the
    // templatized allocator.
    template<class TAllocator>
    class BlockAllocator
    {
    public:
    inline BlockAllocator(); inline void* Alloc(int size); inline void Free(void* p); //------------------------------------------------------------------------
    // data
    private:
    static const int m_BlockSize = *;
    void* mp_CurBlock;
    int m_CurBlockUsage;
    }; //------------------------------------------------------------------------
    template<class TAllocator>
    BlockAllocator<TAllocator>::BlockAllocator()
    : mp_CurBlock(NULL),
    m_CurBlockUsage()
    {
    } //------------------------------------------------------------------------
    template<class TAllocator>
    void* BlockAllocator<TAllocator>::Alloc(int size)
    {
    MEMPRO_ASSERT(size < m_BlockSize); if(!mp_CurBlock || size > m_BlockSize - m_CurBlockUsage)
    {
    mp_CurBlock = TAllocator::Alloc(m_BlockSize);
    MEMPRO_ASSERT(mp_CurBlock);
    m_CurBlockUsage = ;
    } void* p = (char*)mp_CurBlock + m_CurBlockUsage;
    m_CurBlockUsage += size; return p;
    } //------------------------------------------------------------------------
    template<class TAllocator>
    void BlockAllocator<TAllocator>::Free(void* p)
    {
    // do nothing
    }
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPRO_SPINLOCK_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    const int g_InitialCapacity = ; // must be a power of 2 MemPro::BlockAllocator<Allocator> g_BlockAllocator; //------------------------------------------------------------------------
    inline bool StacksMatch(MemPro::Callstack* p_callstack, uint64* p_stack, int stack_size, unsigned int hash)
    {
    if(p_callstack->m_Size != stack_size)
    return false; if(p_callstack->m_Hash != hash)
    return false; for(int i=; i<stack_size; ++i)
    if(p_callstack->mp_Stack[i] != p_stack[i])
    return false; return true;
    }
    } //------------------------------------------------------------------------
    MemPro::CallstackSet::CallstackSet()
    : mp_Data((Callstack**)Allocator::Alloc(g_InitialCapacity*sizeof(Callstack*))),
    m_CapacityMask(g_InitialCapacity-),
    m_Count(),
    m_Capacity(g_InitialCapacity)
    {
    memset(mp_Data, , g_InitialCapacity*sizeof(Callstack*));
    } //------------------------------------------------------------------------
    MemPro::CallstackSet::~CallstackSet()
    {
    Clear();
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Grow()
    {
    int old_capacity = m_Capacity;
    Callstack** p_old_data = mp_Data; // allocate a new set
    m_Capacity *= ;
    m_CapacityMask = m_Capacity - ;
    int size = m_Capacity * sizeof(Callstack*);
    mp_Data = (Callstack**)Allocator::Alloc(size);
    memset(mp_Data, , size); // transfer callstacks from old set
    m_Count = ;
    for(int i=; i<old_capacity; ++i)
    {
    Callstack* p_callstack = p_old_data[i];
    if(p_callstack)
    Add(p_callstack);
    } // release old buffer
    Allocator::Free(p_old_data, old_capacity*sizeof(Callstack*));
    } //------------------------------------------------------------------------
    MemPro::Callstack* MemPro::CallstackSet::Get(uint64* p_stack, int stack_size, unsigned int hash)
    {
    int index = hash & m_CapacityMask; while(mp_Data[index] && !StacksMatch(mp_Data[index], p_stack, stack_size, hash))
    index = (index + ) & m_CapacityMask; return mp_Data[index];
    } //------------------------------------------------------------------------
    MemPro::Callstack* MemPro::CallstackSet::Add(uint64* p_stack, int stack_size, unsigned int hash)
    {
    // grow the set if necessary
    if(m_Count > m_Capacity/)
    Grow(); // create a new callstack
    Callstack* p_callstack = (Callstack*)g_BlockAllocator.Alloc(sizeof(Callstack));
    p_callstack->m_ID = m_Count;
    p_callstack->m_Size = stack_size;
    p_callstack->mp_Stack = (uint64*)g_BlockAllocator.Alloc(stack_size*sizeof(uint64));
    p_callstack->m_Hash = hash;
    memcpy_s(p_callstack->mp_Stack, stack_size*sizeof(uint64), p_stack, stack_size*sizeof(uint64)); Add(p_callstack); return p_callstack;
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Add(Callstack* p_callstack)
    {
    // find a clear index
    int index = p_callstack->m_Hash & m_CapacityMask;
    while(mp_Data[index])
    index = (index + ) & m_CapacityMask; mp_Data[index] = p_callstack; ++m_Count;
    } //------------------------------------------------------------------------
    void MemPro::CallstackSet::Clear()
    {
    for(int i=; i<m_Capacity; ++i)
    {
    if(mp_Data[i])
    g_BlockAllocator.Free(mp_Data[i]);
    } Allocator::Free(mp_Data, m_Capacity*sizeof(Callstack*)); size_t size = g_InitialCapacity*sizeof(Callstack*);
    mp_Data = (Callstack**)Allocator::Alloc((int)size);
    memset(mp_Data, , size);
    m_CapacityMask = g_InitialCapacity-;
    m_Count = ;
    m_Capacity = g_InitialCapacity;
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO
    //------------------------------------------------------------------------
    // MemPro.cpp //------------------------------------------------------------------------
    // RingBuffer.hpp
    #ifndef MEMPRO_RINGBUFFER_H_INCLUDED
    #define MEMPRO_RINGBUFFER_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // CriticalSection.hpp
    #ifndef MEMPRO_CRITICALSECTION_H_INCLUDED
    #define MEMPRO_CRITICALSECTION_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class CriticalSection
    {
    public:
    CriticalSection()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    InitializeCriticalSection(&cs);
    #else
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&cs, &attr);
    #endif
    } ~CriticalSection()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    DeleteCriticalSection(&cs);
    #else
    pthread_mutex_destroy(&cs);
    #endif
    } void Enter()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    EnterCriticalSection(&cs);
    #else
    pthread_mutex_lock(&cs);
    #endif
    } void Leave()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    LeaveCriticalSection(&cs);
    #else
    pthread_mutex_unlock(&cs);
    #endif
    }
    private: //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    CRITICAL_SECTION cs;
    #else
    pthread_mutex_t cs;
    #endif
    }; //------------------------------------------------------------------------
    class CriticalSectionScope
    {
    public:
    CriticalSectionScope(CriticalSection& in_cs) : cs(in_cs) { cs.Enter(); }
    ~CriticalSectionScope() { cs.Leave(); }
    private:
    CriticalSectionScope(const CriticalSectionScope&);
    CriticalSectionScope& operator=(const CriticalSectionScope&);
    CriticalSection& cs;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_CRITICALSECTION_H_INCLUDED //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    // USE_INTRINSIC can also be enabled on 32bit platform, but I left it disabled because it doesn't work on XP
    #ifdef MEMPRO64
    #define USE_INTRINSIC
    #endif
    #endif #ifdef USE_INTRINSIC
    #include <intrin.h>
    #pragma intrinsic(_InterlockedCompareExchange64)
    #pragma intrinsic(_InterlockedExchangeAdd64)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // Event.hpp
    #ifndef MEMPRO_EVENT_H_INCLUDED
    #define MEMPRO_EVENT_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //--------------------------------------------------------------------
    class Event
    {
    public:
    //--------------------------------------------------------------------
    Event(bool initial_state, bool auto_reset)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    m_Handle = CreateEvent(NULL, !auto_reset, initial_state, NULL);
    #else
    pthread_cond_init(&m_Cond, NULL);
    pthread_mutex_init(&m_Mutex, NULL);
    m_Signalled = false;
    m_AutoReset = auto_reset; if(initial_state)
    Set();
    #endif
    } //--------------------------------------------------------------------
    ~Event()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    CloseHandle(m_Handle);
    #else
    pthread_mutex_destroy(&m_Mutex);
    pthread_cond_destroy(&m_Cond);
    #endif
    } //--------------------------------------------------------------------
    void Set() const
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    SetEvent(m_Handle);
    #else
    pthread_mutex_lock(&m_Mutex);
    m_Signalled = true;
    pthread_mutex_unlock(&m_Mutex);
    pthread_cond_signal(&m_Cond);
    #endif
    } //--------------------------------------------------------------------
    void Reset()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    ResetEvent(m_Handle);
    #else
    pthread_mutex_lock(&m_Mutex);
    m_Signalled = false;
    pthread_mutex_unlock(&m_Mutex);
    #endif
    } //--------------------------------------------------------------------
    int Wait(int timeout=-) const
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMPRO_STATIC_ASSERT(INFINITE == -);
    return WaitForSingleObject(m_Handle, timeout) == /*WAIT_OBJECT_0*/;
    #else
    pthread_mutex_lock(&m_Mutex); if(m_Signalled)
    {
    m_Signalled = false;
    pthread_mutex_unlock(&m_Mutex);
    return true;
    } if(timeout == -)
    {
    while(!m_Signalled)
    pthread_cond_wait(&m_Cond, &m_Mutex); if(!m_AutoReset)
    m_Signalled = false; pthread_mutex_unlock(&m_Mutex); return true;
    }
    else
    {
    timeval curr;
    gettimeofday(&curr, NULL); timespec time;
    time.tv_sec = curr.tv_sec + timeout / ;
    time.tv_nsec = (curr.tv_usec * ) + ((timeout % ) * ); pthread_cond_timedwait(&m_Cond, &m_Mutex, &time); if(m_Signalled)
    {
    if(!m_AutoReset)
    m_Signalled = false; pthread_mutex_unlock(&m_Mutex);
    return true;
    } pthread_mutex_unlock(&m_Mutex);
    return false;
    }
    #endif
    } //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    HANDLE m_Handle;
    #else
    mutable pthread_cond_t m_Cond;
    mutable pthread_mutex_t m_Mutex;
    mutable volatile bool m_Signalled;
    bool m_AutoReset;
    #endif
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_EVENT_H_INCLUDED //------------------------------------------------------------------------
    //#define USE_CRITICAL_SECTIONS //------------------------------------------------------------------------
    namespace MemPro
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #ifndef USE_INTRINSIC
    //------------------------------------------------------------------------
    MEMPRO_FORCEINLINE int64 ssInterlockedCompareExchange64(int64 volatile *dest, int64 exchange, int64 comperand)
    {
    __asm
    {
    lea esi,comperand;
    lea edi,exchange;
    mov eax,[esi];
    mov edx,[esi];
    mov ebx,[edi];
    mov ecx,[edi];
    mov esi,dest;
    lock CMPXCHG8B [esi];
    }
    } //------------------------------------------------------------------------
    MEMPRO_FORCEINLINE int64 ssInterlockedExchangeAdd64(__inout int64 volatile *Addend, __in int64 Value)
    {
    int64 Old;
    do
    {
    Old = *Addend;
    } while (ssInterlockedCompareExchange64(Addend, Old + Value, Old) != Old);
    return Old;
    } //------------------------------------------------------------------------
    #define _InterlockedCompareExchange64 ssInterlockedCompareExchange64
    #define _InterlockedExchangeAdd64 ssInterlockedExchangeAdd64
    #endif
    #else
    // no interlocked functions, so just use a critical section
    CriticalSection g_CASCritSec;
    MEMPRO_FORCEINLINE int64 _InterlockedCompareExchange64(int64 volatile *dest, int64 exchange, int64 comperand)
    {
    g_CASCritSec.Enter();
    int64 old_value = *dest;
    if(*dest == comperand)
    *dest = exchange;
    g_CASCritSec.Leave();
    return old_value;
    } MEMPRO_FORCEINLINE int64 _InterlockedExchangeAdd64(int64 volatile *Addend, int64 Value)
    {
    g_CASCritSec.Enter();
    int64 old_value = *Addend;
    *Addend += Value;
    g_CASCritSec.Leave();
    return old_value;
    }
    #endif //------------------------------------------------------------------------
    // This ring buffer is a lockless buffer, designed to be accessed by no more
    // than two threads, one thread adding to the buffer and one removing. The
    // threads first request data and then add or remove tat data. The threads
    // will sleep if there is no space to add or no data to remove. Once the
    // threads have space on the buffer the data can be added or removed.
    class RingBuffer
    {
    public:
    //------------------------------------------------------------------------
    struct Range
    {
    Range() {}
    Range(void* p, int s) : mp_Buffer(p), m_Size(s) {} void* mp_Buffer;
    int m_Size;
    }; //------------------------------------------------------------------------
    RingBuffer(char* p_buffer, int size)
    : m_Size(size),
    mp_Buffer(p_buffer),
    m_UsedRange(),
    m_BytesRemovedEvent(false, true),
    m_BytesAddedEvent(false, true)
    {
    MEMPRO_ASSERT(IsPow2(size)); #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMPRO_ASSERT((((int64)&m_UsedRange) & ) == );
    #endif #ifdef USE_CRITICAL_SECTIONS
    InitializeCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    inline bool IsPow2(int value)
    {
    return (value & (value-)) == ;
    } //------------------------------------------------------------------------
    int GetSize() const
    {
    return m_Size;
    } //------------------------------------------------------------------------
    void Lock() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    EnterCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    void Release() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    LeaveCriticalSection(&m_CriticalSection);
    #endif
    } //------------------------------------------------------------------------
    int64 GetRangeAtomic() const
    {
    #ifdef USE_CRITICAL_SECTIONS
    Lock();
    int64 range = m_UsedRange;
    Release();
    #else
    // there must be a better way to atomically read a 64 bit value.
    int64 range = _InterlockedExchangeAdd64(const_cast<int64*>(&m_UsedRange), );
    #endif
    return range;
    } //------------------------------------------------------------------------
    // return the largest free range possible
    Range GetFreeRange(int timeout=-) const
    {
    int64 range = GetRangeAtomic();
    int size = (int)(range & 0xffffffff); // wait until there is some space
    while(size == m_Size)
    {
    if(!m_BytesRemovedEvent.Wait(timeout))
    return Range(NULL, ); range = GetRangeAtomic();
    size = (int)(range & 0xffffffff);
    } int start = (int)((range >> ) & 0xffffffff); // calculate the size
    int free_start = (start + size) & (m_Size-);
    int free_size = free_start < start ? start - free_start : m_Size - free_start; return Range(mp_Buffer + free_start, free_size);
    } //------------------------------------------------------------------------
    // return the largest used range
    Range GetAllocatedRange(int timeout=-) const
    {
    int64 range = GetRangeAtomic();
    #ifdef _XBOX
    __lwsync(); // ensure that the allocated data has finished writing
    #endif
    int size = (int)(range & 0xffffffff); // wait until there is some data
    while(!size)
    {
    if(!m_BytesAddedEvent.Wait(timeout))
    return Range(NULL, ); range = GetRangeAtomic();
    size = (int)(range & 0xffffffff);
    } int start = (int)((range >> ) & 0xffffffff); // calculate the size
    int max_size = m_Size - start;
    if(size > max_size)
    size = max_size; return Range(mp_Buffer + start, size);
    } //------------------------------------------------------------------------
    // tells the ring buffer how many bytes have been copied to the allocated range
    void Add(int size)
    {
    Lock(); MEMPRO_ASSERT(size >= ); volatile int64 old_range;
    int64 new_range; do
    {
    old_range = GetRangeAtomic(); int64 used_size = (old_range) & 0xffffffff;
    used_size += size;
    new_range = (old_range & 0xffffffff00000000LL) | used_size; } while(_InterlockedCompareExchange64(&m_UsedRange, new_range, old_range) != old_range); m_BytesAddedEvent.Set(); Release();
    } //------------------------------------------------------------------------
    // tells the ring buffer how many bytes have been removed from the allocated range
    void Remove(int size)
    {
    Lock(); MEMPRO_ASSERT(size >= ); volatile int64 old_range;
    int64 new_range;
    int mask = m_Size - ; do
    {
    old_range = GetRangeAtomic(); int64 used_start = (old_range >> ) & 0xffffffff;
    int64 used_size = (old_range) & 0xffffffff;
    used_start = (used_start + size) & mask;
    used_size -= size;
    new_range = (used_start << ) | used_size; } while(_InterlockedCompareExchange64(&m_UsedRange, new_range, old_range) != old_range); m_BytesRemovedEvent.Set(); Release();
    } //------------------------------------------------------------------------
    int GetUsedBytes() const
    {
    return (int)(m_UsedRange & 0xffffffff);
    } //------------------------------------------------------------------------
    void Clear()
    {
    m_UsedRange = ;
    m_BytesRemovedEvent.Reset();
    m_BytesAddedEvent.Reset();
    } //------------------------------------------------------------------------
    // data
    private:
    int m_Size;
    char* mp_Buffer; #ifdef MEMPRO_WIN_BASED_PLATFORM
    // NOTE: this MUST be 64bit aligned
    __declspec(align()) int64 m_UsedRange; // start index is the high int, size is the low int
    #else
    int64 m_UsedRange;
    #endif #ifdef USE_CRITICAL_SECTIONS
    mutable CRITICAL_SECTION m_CriticalSection;
    #endif
    Event m_BytesRemovedEvent;
    Event m_BytesAddedEvent;
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_RINGBUFFER_H_INCLUDED //------------------------------------------------------------------------
    // Packets.hpp
    #ifndef MEMPRO_PACKETS_H_INCLUDED
    #define MEMPRO_PACKETS_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    // MemProMisc.hpp
    #ifndef MEMPRO_MEMPROMISC_H_INCLUDED
    #define MEMPRO_MEMPROMISC_H_INCLUDED //------------------------------------------------------------------------ #include <stdlib.h> #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <byteswap.h>
    #endif //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4127)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #define MEMPRO_SPINLOCK_FREE_VAL 0
    #define MEMPRO_SPINLOCK_LOCKED_VAL 1
    #define MEMPRO_YIELD_SPIN_COUNT 40
    #define MEMPRO_SLEEP_SPIN_COUNT 200 //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    inline int Min(int a, int b) { return a < b ? a : b; } //------------------------------------------------------------------------
    inline void SwapEndian(unsigned int& value)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    value = _byteswap_ulong(value);
    #else
    value = __bswap_32(value);
    #endif
    } //------------------------------------------------------------------------
    inline void SwapEndian(uint64& value)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    value = _byteswap_uint64(value);
    #else
    value = __bswap_64(value);
    #endif
    } //------------------------------------------------------------------------
    inline void SwapEndian(int64& value)
    {
    SwapEndian((uint64&)value);
    } //------------------------------------------------------------------------
    template<typename T>
    inline void SwapEndian(T& value)
    {
    MEMPRO_ASSERT(sizeof(T) == sizeof(unsigned int));
    SwapEndian((unsigned int&)value);
    } //------------------------------------------------------------------------
    inline void SwapEndianUInt64Array(void* p, int size)
    {
    MEMPRO_ASSERT(size % == );
    uint64* p_uint64 = (uint64*)p;
    uint64* p_end = p_uint64 + size/;
    while(p_uint64 != p_end)
    SwapEndian(*p_uint64++);
    } //------------------------------------------------------------------------
    // hi-res timer
    #if defined(MEMPRO_PLATFORM_WIN)
    inline uint64 GetRDTSC()
    {
    #ifdef MEMPRO64
    return __rdtsc();
    #else
    __asm
    {
    ; Flush the pipeline
    XOR eax, eax
    CPUID
    ; Get RDTSC counter in edx:eax
    RDTSC
    }
    #endif
    }
    #define GET_CLOCK_COUNT(time) time = GetRDTSC();
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin:
    //#error Please contact slynch@puredevsoftware.com for this platform
    inline uint64 GetRDTSC()
    {
    return __rdtsc();
    }
    #define GET_CLOCK_COUNT(time) time = GetRDTSC();
    //@Virtuos[wangsongwei]end
    #endif //------------------------------------------------------------------------
    inline int64 GetTime()
    {
    int64 time; #ifdef MEMPRO_WIN_BASED_PLATFORM
    GET_CLOCK_COUNT(time);
    #else
    timeval curr;
    gettimeofday(&curr, NULL);
    time = ((int64)curr.tv_sec) * + curr.tv_usec;
    #endif
    return time;
    } //------------------------------------------------------------------------
    inline int64 GetTickFrequency()
    {
    Sleep();
    int64 start = GetTime();
    Sleep();
    int64 end = GetTime();
    return end - start;
    } //------------------------------------------------------------------------
    inline void SetThreadName(unsigned int thread_id, const char* p_name)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    // see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
    const unsigned int MS_VC_EXCEPTION=0x406D1388; struct THREADNAME_INFO
    {
    unsigned int dwType; // Must be 0x1000.
    LPCSTR szName; // Pointer to name (in user addr space).
    unsigned int dwThreadID; // Thread ID (-1=caller thread).
    unsigned int dwFlags; // Reserved for future use, must be zero.
    }; // on the xbox setting thread names messes up the XDK COM API that UnrealConsole uses so check to see if they have been
    // explicitly enabled
    Sleep();
    THREADNAME_INFO ThreadNameInfo;
    ThreadNameInfo.dwType = 0x1000;
    ThreadNameInfo.szName = p_name;
    ThreadNameInfo.dwThreadID = thread_id;
    ThreadNameInfo.dwFlags = ; __try
    {
    RaiseException( MS_VC_EXCEPTION, , sizeof(ThreadNameInfo)/sizeof(ULONG_PTR), (ULONG_PTR*)&ThreadNameInfo );
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
    #else
    // not supported
    #endif
    } //------------------------------------------------------------------------
    inline void SmallFastMemCpy(void* p_dst, void* p_src, int size)
    {
    MEMPRO_ASSERT((((size_t)p_dst) & ) == );
    MEMPRO_ASSERT((((size_t)p_src) & ) == );
    MEMPRO_ASSERT((size & ) == ); unsigned int uint_count = size / sizeof(unsigned int);
    unsigned int* p_uint_dst = (unsigned int*)p_dst;
    unsigned int* p_uint_src = (unsigned int*)p_src;
    for(unsigned int i=; i<uint_count; ++i)
    *p_uint_dst++ = *p_uint_src++;
    }
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_MEMPROMISC_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    // This file contains all of te packets that can be sent to the MemPro app. //------------------------------------------------------------------------
    enum PacketType
    {
    EInvalid = 0xabcd,
    EAllocPacket,
    EFreePacket,
    ECallstackPacket,
    EPageStatePacket,
    EPageStateStartPacket, // for backwards compatibility
    EPageStateEndPacket_OLD,
    EVirtualMemStats,
    ETakeSnapshot,
    EVMemStats,
    EPageStateEndPacket,
    EDataStoreEndPacket,
    EPulsePacket,
    ERequestShutdown
    }; //------------------------------------------------------------------------
    enum MemProVersion
    {
    Version =
    }; //------------------------------------------------------------------------
    enum MemProClientFlags
    {
    SendPageData = ,
    SendPageDataWithMemory,
    EShutdownComplete
    }; //------------------------------------------------------------------------
    // value that is sent immediatley after connection to detect big endian
    enum EEndianKey
    {
    EndianKey = 0xabcdef01
    }; //------------------------------------------------------------------------
    enum Platform
    {
    Platform_Windows,
    Platform_Unix
    }; //------------------------------------------------------------------------
    struct PacketHeader
    {
    PacketType m_PacketType;
    int m_Padding;
    int64 m_Time; void SwapEndian()
    {
    MemPro::SwapEndian(m_PacketType);
    MemPro::SwapEndian(m_Time);
    }
    }; //------------------------------------------------------------------------
    struct ConnectPacket
    {
    uint64 m_Padding; // for backwards compatibility int64 m_ConnectTime;
    int64 m_TickFrequency; int m_Version;
    int m_PtrSize; Platform m_Platform;
    int m_Padding2; void SwapEndian()
    {
    MemPro::SwapEndian(m_Version);
    MemPro::SwapEndian(m_ConnectTime);
    MemPro::SwapEndian(m_TickFrequency);
    MemPro::SwapEndian(m_PtrSize);
    }
    }; //------------------------------------------------------------------------
    struct AllocPacket
    {
    uint64 m_Addr;
    uint64 m_Size;
    int m_CallstackID;
    int m_Padding; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    MemPro::SwapEndian(m_CallstackID);
    }
    }; //------------------------------------------------------------------------
    struct FreePacket
    {
    uint64 m_Addr; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    }
    }; //------------------------------------------------------------------------
    struct PageStatePacket
    {
    uint64 m_Addr;
    uint64 m_Size;
    PageState m_State;
    PageType m_Type;
    unsigned int m_Protection;
    int m_SendingMemory; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    MemPro::SwapEndian(m_State);
    MemPro::SwapEndian(m_Type);
    MemPro::SwapEndian(m_Protection);
    MemPro::SwapEndian(m_SendingMemory);
    }
    }; //------------------------------------------------------------------------
    struct VirtualMemStatsPacket
    {
    uint64 m_Reserved;
    uint64 m_Committed; void SwapEndian()
    {
    MemPro::SwapEndian(m_Reserved);
    MemPro::SwapEndian(m_Committed);
    }
    }; //------------------------------------------------------------------------
    struct IgnoreMemRangePacket
    {
    uint64 m_Addr;
    uint64 m_Size; void SwapEndian()
    {
    MemPro::SwapEndian(m_Addr);
    MemPro::SwapEndian(m_Size);
    }
    };
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_PACKETS_H_INCLUDED //------------------------------------------------------------------------
    // Socket.hpp
    #ifndef MEMPRO_SOCKET_H_INCLUDED
    #define MEMPRO_SOCKET_H_INCLUDED //------------------------------------------------------------------------ //------------------------------------------------------------------------
    #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(push)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    class SocketImp; //------------------------------------------------------------------------
    class Socket
    {
    public:
    inline Socket(); inline ~Socket(); void Disconnect(); bool Bind(const char* p_port); bool StartListening(); bool Accept(Socket& client_socket); int Receive(void* p_buffer, int size); bool Send(void* p_buffer, int size); inline bool IsValid() const { return m_Socket != INVALID_SOCKET; } private:
    bool InitialiseWSA(); void CleanupWSA(); void HandleError(); //------------------------------------------------------------------------
    // data
    SOCKET m_Socket;
    }; //------------------------------------------------------------------------
    Socket::Socket()
    : m_Socket(INVALID_SOCKET)
    {
    } //------------------------------------------------------------------------
    Socket::~Socket()
    {
    CleanupWSA();
    }
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(pop)
    #endif //------------------------------------------------------------------------
    #endif // #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_SOCKET_H_INCLUDED //------------------------------------------------------------------------
    // Thread.hpp
    #ifndef MEMPRO_THREAD_H_INCLUDED
    #define MEMPRO_THREAD_H_INCLUDED //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(push)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifndef MEMPRO_WIN_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    typedef int (*ThreadMain)(void*); //------------------------------------------------------------------------
    class Thread
    {
    public:
    Thread(); void CreateThread(ThreadMain p_thread_main, void* p_param=NULL); bool IsAlive() const { return m_Alive; } private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    static unsigned long WINAPI PlatformThreadMain(void* p_param);
    #else
    static void* PlatformThreadMain(void* p_param);
    #endif //------------------------------------------------------------------------
    // data
    private:
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    mutable HANDLE m_Handle;
    #else
    mutable pthread_t m_Thread;
    #endif
    mutable bool m_Alive; mutable ThreadMain mp_ThreadMain;
    mutable void* mp_Param;
    };
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(pop)
    #endif //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #endif // #ifndef MEMPRO_THREAD_H_INCLUDED #include <new>
    #include <stdio.h>
    #include <time.h>
    #include <limits.h> #if defined(MEMPRO_PLATFORM_WIN) && !((!defined(MIDL_PASS) && defined(_M_IX86) && !defined(_M_CEE_PURE)) || defined(MemoryBarrier))
    #include <atomic>
    #endif #ifdef MEMPRO_WIN_BASED_PLATFORM
    #include <tchar.h>
    #endif //------------------------------------------------------------------------
    // disable some warnings we are not interested in so that we can compile at warning level4
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #pragma warning(disable : 4127)
    #pragma warning(disable : 4100)
    #endif //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO //------------------------------------------------------------------------
    #if !defined(WRITE_DUMP) && defined(MEMPRO_WIN_BASED_PLATFORM)
    #pragma comment(lib, "Ws2_32.lib")
    #endif //------------------------------------------------------------------------
    // if you are having problems compiling this on your platform undefine ENUMERATE_ALL_MODULES and it send info for just the main module
    #ifndef MEMPRO_PLATFORM_XBOXONE
    #define ENUMERATE_ALL_MODULES //@Virtuos[wangsongwei] in mempro undef ENUMERATE_ALL_MODULES in xbox one platform
    #endif #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM //@Virtuos[wangsongwei] WIN BASED, mean WINDOWS, XBOXONE here #if FRAMEPRO_TOOLSET_UE4
    #if PLATFORM_WINDOWS
    #include "AllowWindowsPlatformTypes.h"
    #endif
    #if PLATFORM_XBOXONE
    #include "AllowXboxOnePlatformTypes.h"//@Virtuos[wangsongwei] add code support X1 version
    #endif
    #endif #pragma warning(push)
    #pragma warning(disable : 4091)
    #include <Dbghelp.h>
    #pragma warning(pop) #pragma comment(lib, "Dbghelp.lib") #if FRAMEPRO_TOOLSET_UE4
    #if PLATFORM_WINDOWS
    #include "HideWindowsPlatformTypes.h"
    #endif
    #if PLATFORM_XBOXONE
    #include "HideXboxOnePlatformTypes.h"//@Virtuos[wangsongwei] add code support X1 version
    #endif
    #endif
    #else
    #include <link.h>
    #endif
    #endif //------------------------------------------------------------------------
    #ifdef VMEM_STATS
    namespace VMem { void SendStatsToMemPro(void (*send_fn)(void*, int, void*), void* p_context); }
    #endif //------------------------------------------------------------------------
    //#define TEST_ENDIAN //#define PACKET_START_END_MARKERS #ifdef TEST_ENDIAN
    #define ENDIAN_TEST(a) a
    #else
    #define ENDIAN_TEST(a)
    #endif //------------------------------------------------------------------------
    // if both of these options are commented out it will use CaptureStackBackTrace (or backtrace on linux)
    //#define USE_STACKWALK64 // much slower but possibly more reliable. USE_STACKWALK64 only implemented for x86 builds.
    //#define USE_RTLVIRTUALUNWIND // reported to be faster than StackWalk64 - only available on x64 builds
    //#define USE_RTLCAPTURESTACKBACKTRACE // system version of USE_RTLVIRTUALUNWIND - only available on x64 builds #if FRAMEPRO_TOOLSET_UE4
    #define USE_RTLCAPTURESTACKBACKTRACE
    #endif //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #define THREAD_LOCAL_STORAGE __declspec(thread)
    #else
    #define THREAD_LOCAL_STORAGE __thread
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    THREAD_LOCAL_STORAGE void** g_CallstackDataTLS = NULL;
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_PLATFORM_XBOXONE
    //#error Please contact slynch@puredevsoftware.com for this platform //@Virtuos[wangsongwei] I don't know what I need to do here, just annotate this line avoid compile error
    #endif //------------------------------------------------------------------------
    #ifdef USE_RTLCAPTURESTACKBACKTRACE #ifndef MEMPRO64
    #error USE_RTLVIRTUALUNWIND only available on x64 builds. Please use a different stack walk function.
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    void RTLCaptureStackBackTrace(void** stack, int max_stack_size, unsigned int& hash, int& stack_size)
    {
    memset(stack, , max_stack_size* sizeof(void*));
    stack_size = ::RtlCaptureStackBackTrace(,max_stack_size-, stack, (PDWORD)&hash);
    stack[stack_size] = ;
    }
    } #endif // #ifdef USE_RTLCAPTURESTACKBACKTRACE //------------------------------------------------------------------------
    #ifdef USE_RTLVIRTUALUNWIND #ifndef MEMPRO64
    #error USE_RTLVIRTUALUNWIND only available on x64 builds. Please use a different stack walk function.
    #endif namespace MemPro
    {
    //------------------------------------------------------------------------
    __declspec(noinline) VOID VirtualUnwindStackWalk(void** stack, int max_stack_size)
    {
    CONTEXT context;
    memset(&context, , sizeof(context));
    RtlCaptureContext(&context); UNWIND_HISTORY_TABLE unwind_history_table;
    RtlZeroMemory(&unwind_history_table, sizeof(UNWIND_HISTORY_TABLE)); int frame = ;
    for (; frame < max_stack_size-; ++frame)
    {
    stack[frame] = (void*)context.Rip; ULONG64 image_base;
    PRUNTIME_FUNCTION runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, &unwind_history_table); if (!runtime_function)
    {
    // If we don't have a RUNTIME_FUNCTION, then we've encountered
    // a leaf function. Adjust the stack appropriately.
    context.Rip = (ULONG64)(*(PULONG64)context.Rsp);
    context.Rsp += ;
    }
    else
    {
    // Otherwise, call upon RtlVirtualUnwind to execute the unwind for us.
    KNONVOLATILE_CONTEXT_POINTERS nv_context;
    RtlZeroMemory(&nv_context, sizeof(KNONVOLATILE_CONTEXT_POINTERS)); PVOID handler_data;
    ULONG64 establisher_frame; RtlVirtualUnwind(
    /*UNW_FLAG_NHANDLER*/,
    image_base,
    context.Rip,
    runtime_function,
    &context,
    &handler_data,
    &establisher_frame,
    &nv_context);
    } // If we reach an RIP of zero, this means that we've walked off the end
    // of the call stack and are done.
    if (!context.Rip)
    break;
    } stack[frame] = ;
    }
    }
    #endif //------------------------------------------------------------------------
    namespace MemPro
    {
    //------------------------------------------------------------------------
    int g_MemProRefs = ; //------------------------------------------------------------------------
    const int PAGE_SIZE = ; //------------------------------------------------------------------------
    void InitialiseInternal(); //------------------------------------------------------------------------
    // MemPro will initialise on the first allocation, but this global ensures
    // that MemPro is initialised in the main module. This is sometimes necessary
    // if the first allocation comes from a dll.
    /*
    class Initialiser
    {
    public:
    Initialiser() { MemPro::Initialise(WAIT_FOR_CONNECT); }
    } g_Initialiser;
    */ //------------------------------------------------------------------------
    // port number
    #if defined(MEMPRO_PLATFORM_WIN)
    const char* g_DefaultPort = "";
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin: xbox one use TCP port 4600
    //#error Please contact slynch@puredevsoftware.com for this platform
    const char* g_DefaultPort = "";
    //@Virtuos[wangsongwei]end
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    const char* g_DefaultPort = "";
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_WIN)
    #if (NTDDI_VERSION > NTDDI_WINXP)
    #define STACK_TRACE_SIZE 128
    #else
    #define STACK_TRACE_SIZE 62
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin:
    //#error Please contact slynch@puredevsoftware.com for this platform
    #define STACK_TRACE_SIZE 128 //also use same size for stack trace as windows
    //@Virtuos[wangsongwei]end
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    #define STACK_TRACE_SIZE 128
    #else
    #error platform not defined
    #endif //------------------------------------------------------------------------
    // globals
    const int g_RingBufferSize = *; #ifdef MEMPRO64
    uint64 g_MaxAddr = ULLONG_MAX;
    #else
    uint64 g_MaxAddr = UINT_MAX;
    #endif //------------------------------------------------------------------------
    #ifdef WRITE_DUMP
    FILE* gp_DumpFile = NULL;
    #endif //------------------------------------------------------------------------
    uint64 ToUInt64(void* p)
    {
    #ifdef MEMPRO64
    return (uint64)p;
    #else
    unsigned int u = (unsigned int)p; // cast to uint first to avoid signed bit in casting
    return (uint64)u;
    #endif
    } //------------------------------------------------------------------------
    struct DataStorePageHeader
    {
    int m_Size;
    DataStorePageHeader* mp_Next;
    }; //------------------------------------------------------------------------
    struct CallstackCapture
    {
    void** mp_Stack;
    int m_Size;
    unsigned int m_Hash;
    }; //------------------------------------------------------------------------
    void BaseAddressLookupFunction()
    {
    } //------------------------------------------------------------------------
    class CMemPro
    {
    public:
    CMemPro(); bool Initialise(); void Shutdown(); void Disconnect(bool listen_for_new_connection); void TrackAlloc(void* p, size_t size, bool wait_for_connect); void TrackFree(void* p, bool wait_for_connect); void SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory); void TakeSnapshot(); int SendThreadMain(void* p_param); #ifndef WRITE_DUMP
    int ReceiveThreadMain(void* p_param);
    #endif int WaitForConnectionThreadMain(void* p_param); void Lock() { m_CriticalSection.Enter(); } void Release() { m_CriticalSection.Leave(); } void WaitForConnectionOnInitialise(); bool IsPaused(); void SetPaused(bool paused); private:
    static void GetStackTrace(void** stack, int& stack_size, unsigned int& hash); void SendModuleInfo(); void SendExtraModuleInfo(int64 ModuleBase); void SendString(const char* p_str); #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
    static BOOL CALLBACK EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in DWORD64 ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext);
    #else
    static BOOL CALLBACK EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in ULONG ModuleBase, __in ULONG ModuleSize,__in_opt PVOID UserContext);
    #endif
    #else
    int static EnumerateLoadedModulesCallback(struct dl_phdr_info* info, size_t size, void* data);
    #endif
    #endif
    void StoreData(const void* p_data, int size); void BlockUntilSendThreadEmpty(); void SendStoredData(); void ClearStoreData(); inline bool SendThreadStillAlive() const; void FlushRingBufferForShutdown(); void SendData(const void* p_data, int size); bool SocketSendData(const void* p_data, int size); static void StaticSendVMemStatsData(void* p_data, int size, void* p_context); void SendVMemStatsData(void* p_data, int size); void SendData(unsigned int value); inline void SendPacketHeader(PacketType value); void SendStartMarker(); void SendEndMarker(); inline void Send(bool value); template<typename T> void Send(T& value) { SendData(&value, sizeof(value)); } void Send(unsigned int value) { SendData(value); } void SendPageState(bool send_memory); void SendVMemStats(); void SendVirtualMemStats(); void** AllocateStackTraceData(); CallstackCapture CaptureCallstack(); int SendCallstack(const CallstackCapture& callstack_capture); bool WaitForConnection(); bool WaitForConnectionIfListening(); static int SendThreadMainStatic(void* p_param); static int ReceiveThreadMainStatic(void* p_param); static int WaitForConnectionThreadMainStatic(void* p_param); static int PulseThreadMainStatic(void* p_param); void PulseThreadMain(); void BlockUntilReadyToSend(); //------------------------------------------------------------------------
    // data
    #ifndef WRITE_DUMP
    Socket m_ListenSocket;
    Socket m_ClientSocket;
    #endif CallstackSet m_CallstackSet; RingBuffer m_RingBuffer;
    char m_RingBufferMem[g_RingBufferSize]; volatile bool m_Connected;
    volatile bool m_ReadyToSend; volatile bool m_InEvent; volatile bool m_Paused; Event m_StartedListeningEvent;
    Event m_WaitForConnectThreadFinishedEvent;
    Event m_SendThreadFinishedEvent;
    Event m_ReceiveThreadFinishedEvent;
    Event m_MemProReadyToShutdownEvent;
    Event m_PulseThreadFinished; volatile bool m_StartedListening;
    volatile bool m_InitialConnectionTimedOut; int m_LastPageStateSend;
    int m_PageStateInterval; int m_LastVMemStatsSend;
    int m_VMemStatsSendInterval; bool m_WaitForConnect; static const int m_DataStorePageSize = ;
    DataStorePageHeader* mp_DataStoreHead; // used to store allocs before initialised
    DataStorePageHeader* mp_DataStoreTail; Thread m_SendThread;
    Thread m_ReceiveThread;
    Thread m_PulseThread;
    Thread m_WaitForConnectionThread; bool m_FlushedRingBufferForShutdown; CriticalSection m_CriticalSection;
    CriticalSection m_DisconnectCriticalSection; int m_ModulesSent; volatile bool m_ShuttingDown; BlockAllocator<Allocator> m_BlockAllocator;
    }; //------------------------------------------------------------------------
    char g_MemProMem[sizeof(CMemPro)];
    CMemPro* gp_MemPro = NULL;
    volatile bool g_ShuttingDown = false; //------------------------------------------------------------------------
    inline CMemPro* GetMemPro()
    {
    if(!gp_MemPro)
    InitialiseInternal(); return gp_MemPro;
    } //------------------------------------------------------------------------
    CMemPro::CMemPro()
    : m_RingBuffer(m_RingBufferMem, g_RingBufferSize),
    m_Connected(false),
    m_ReadyToSend(false),
    m_InEvent(false),
    m_Paused(false),
    m_StartedListeningEvent(false, false),
    m_WaitForConnectThreadFinishedEvent(false, false),
    m_SendThreadFinishedEvent(true, false),
    m_ReceiveThreadFinishedEvent(true, false),
    m_MemProReadyToShutdownEvent(false, false),
    m_PulseThreadFinished(true, false),
    m_StartedListening(false),
    m_InitialConnectionTimedOut(false),
    m_LastPageStateSend(),
    m_PageStateInterval(),
    m_LastVMemStatsSend(),
    m_VMemStatsSendInterval(),
    m_WaitForConnect(false),
    mp_DataStoreHead(NULL),
    mp_DataStoreTail(NULL),
    m_FlushedRingBufferForShutdown(false),
    m_ModulesSent(),
    m_ShuttingDown(false)
    {
    } //------------------------------------------------------------------------
    inline unsigned int GetHash(void** p_stack, int stack_size)
    {
    #ifdef MEMPRO64
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    void** p = p_stack;
    for(int i=; i<stack_size; ++i)
    {
    uint64 key = ToUInt64(*p++);
    key = (~key) + (key << );
    key = key ^ (key >> );
    key = key * ;
    key = key ^ (key >> );
    key = key + (key << );
    key = key ^ (key >> );
    hash = hash ^ (unsigned int)key;
    } return hash;
    #else
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    for(int i=; i<stack_size; ++i)
    hash = (hash * prime) ^ (unsigned int)p_stack[i]; return hash;
    #endif
    } //------------------------------------------------------------------------
    inline unsigned int GetHashAndStackSize(void** p_stack, int& stack_size)
    {
    #ifdef MEMPRO64
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    stack_size = ;
    void** p = p_stack;
    while(*p)
    {
    uint64 key = ToUInt64(*p++);
    key = (~key) + (key << );
    key = key ^ (key >> );
    key = key * ;
    key = key ^ (key >> );
    key = key + (key << );
    key = key ^ (key >> );
    hash = hash ^ (unsigned int)key;
    ++stack_size;
    } return hash;
    #else
    const unsigned int prime = 0x01000193;
    unsigned int hash = prime;
    stack_size = ;
    while(p_stack[stack_size])
    {
    hash = (hash * prime) ^ (unsigned int)p_stack[stack_size];
    ++stack_size;
    } return hash;
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::GetStackTrace(void** stack, int& stack_size, unsigned int& hash)
    {
    #if defined(MEMPRO_PLATFORM_WIN)
    #if defined(USE_STACKWALK64) #ifdef MEMPRO64
    #error USE_STACKWALK64 only works in x86 builds. Please use a different stack walk funtion.
    #endif // get the context
    CONTEXT context;
    memset(&context, , sizeof(context));
    RtlCaptureContext(&context); // setup the stack frame
    STACKFRAME64 stack_frame;
    memset(&stack_frame, , sizeof(stack_frame));
    stack_frame.AddrPC.Mode = AddrModeFlat;
    stack_frame.AddrFrame.Mode = AddrModeFlat;
    stack_frame.AddrStack.Mode = AddrModeFlat;
    #ifdef MEMPRO64
    DWORD machine = IMAGE_FILE_MACHINE_IA64;
    stack_frame.AddrPC.Offset = context.Rip;
    stack_frame.AddrFrame.Offset = context.Rsp;
    stack_frame.AddrStack.Offset = context.Rbp;
    #else
    DWORD machine = IMAGE_FILE_MACHINE_I386;
    stack_frame.AddrPC.Offset = context.Eip;
    stack_frame.AddrFrame.Offset = context.Ebp;
    stack_frame.AddrStack.Offset = context.Esp;
    #endif
    HANDLE thread = GetCurrentThread(); static HANDLE process = GetCurrentProcess(); stack_size = ;
    while(StackWalk64(
    machine,
    process,
    thread,
    &stack_frame,
    &context,
    NULL,
    SymFunctionTableAccess64,
    SymGetModuleBase64,
    NULL) && stack_size < STACK_TRACE_SIZE)
    {
    void* p = (void*)(stack_frame.AddrPC.Offset);
    stack[stack_size++] = p;
    }
    hash = GetHash(stack, stack_size);
    #elif defined(USE_RTLVIRTUALUNWIND)
    MemPro::VirtualUnwindStackWalk(stack, STACK_TRACE_SIZE);
    hash = GetHashAndStackSize(stack, stack_size);
    #elif defined(USE_RTLCAPTURESTACKBACKTRACE)
    MemPro::RTLCaptureStackBackTrace(stack, STACK_TRACE_SIZE, hash, stack_size);
    #else
    CaptureStackBackTrace(, STACK_TRACE_SIZE, stack, (PDWORD)&hash);
    for(stack_size = ; stack_size<STACK_TRACE_SIZE; ++stack_size)
    if(!stack[stack_size])
    break;
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin: refer to XboxOneStackWalk.cpp
    //#error Please contact slynch@puredevsoftware.com for this platform
    MemPro::RTLCaptureStackBackTrace(stack, STACK_TRACE_SIZE, hash, stack_size); //in fact, in UE4 all platform should use this capture stack trace function
    //@Virtuos[wangsongwei]end
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    stack_size = backtrace(stack, STACK_TRACE_SIZE);
    hash = GetHashAndStackSize(stack, stack_size);
    #else
    #error platform not defined
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::StaticSendVMemStatsData(void* p_data, int size, void* p_context)
    {
    CMemPro* p_this = (CMemPro*)p_context;
    p_this->SendVMemStatsData(p_data, size);
    } //------------------------------------------------------------------------
    void CMemPro::SendVMemStatsData(void* p_data, int size)
    {
    static char buffer[];
    MEMPRO_ASSERT(size <= (int)sizeof(buffer));
    memcpy_s(buffer, sizeof(buffer), p_data, size);
    ENDIAN_TEST(SwapEndianUInt64Array(buffer, size));
    SendData(buffer, size);
    } //------------------------------------------------------------------------
    void CMemPro::StoreData(const void* p_data, int size)
    {
    MEMPRO_ASSERT(size < m_DataStorePageSize - (int)sizeof(DataStorePageHeader)); if(!mp_DataStoreTail || mp_DataStoreTail->m_Size + size > m_DataStorePageSize)
    {
    DataStorePageHeader* p_new_page = (DataStorePageHeader*)Allocator::Alloc(m_DataStorePageSize);
    p_new_page->m_Size = sizeof(DataStorePageHeader);
    p_new_page->mp_Next = NULL; if(mp_DataStoreTail)
    mp_DataStoreTail->mp_Next = p_new_page;
    else
    mp_DataStoreHead = p_new_page; mp_DataStoreTail = p_new_page;
    } memcpy((char*)mp_DataStoreTail + mp_DataStoreTail->m_Size, p_data, size);
    mp_DataStoreTail->m_Size += size;
    } //------------------------------------------------------------------------
    void CMemPro::BlockUntilSendThreadEmpty()
    {
    // wait for the send thread to have sent all of the stored data
    while(m_Connected && m_RingBuffer.GetAllocatedRange().m_Size)
    Sleep();
    } //------------------------------------------------------------------------
    void CMemPro::SendStoredData()
    {
    if(!m_Connected)
    return; DataStorePageHeader* p_page = mp_DataStoreHead; if(p_page)
    {
    while(p_page)
    {
    DataStorePageHeader* p_next = p_page->mp_Next; SendData((char*)p_page + sizeof(DataStorePageHeader), p_page->m_Size - sizeof(DataStorePageHeader));
    Allocator::Free(p_page, m_DataStorePageSize); p_page = p_next;
    } SendPacketHeader(EDataStoreEndPacket);
    SendEndMarker();
    } #ifndef WRITE_DUMP
    BlockUntilSendThreadEmpty();
    #endif mp_DataStoreHead = mp_DataStoreTail = NULL;
    } //------------------------------------------------------------------------
    void CMemPro::ClearStoreData()
    {
    DataStorePageHeader* p_page = mp_DataStoreHead;
    while(p_page)
    {
    DataStorePageHeader* p_next = p_page->mp_Next;
    Allocator::Free(p_page, m_DataStorePageSize);
    p_page = p_next;
    } mp_DataStoreHead = mp_DataStoreTail = NULL; m_CallstackSet.Clear();
    } //------------------------------------------------------------------------
    void CMemPro::Send(bool value)
    {
    unsigned int uint_value = value ? : ;
    Send(uint_value);
    } //------------------------------------------------------------------------
    bool CMemPro::SendThreadStillAlive() const
    {
    return m_SendThread.IsAlive();
    } //------------------------------------------------------------------------
    void CMemPro::FlushRingBufferForShutdown()
    {
    if(m_FlushedRingBufferForShutdown)
    return;
    m_FlushedRingBufferForShutdown = true; RingBuffer::Range range = m_RingBuffer.GetAllocatedRange();
    while(range.m_Size)
    {
    SocketSendData(range.mp_Buffer, range.m_Size);
    range = m_RingBuffer.GetAllocatedRange();
    }
    } //------------------------------------------------------------------------
    void CMemPro::SendData(const void* p_data, int size)
    {
    MEMPRO_ASSERT((size & ) == ); if(!m_Connected)
    {
    StoreData(p_data, size);
    return;
    } if(!SendThreadStillAlive())
    {
    FlushRingBufferForShutdown();
    SocketSendData(p_data, size);
    }
    else
    {
    int bytes_to_copy = size;
    char* p_src = (char*)p_data;
    while(bytes_to_copy)
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetFreeRange();
    if(!m_Connected)
    return;
    } while(!range.m_Size);
    if(!m_Connected)
    return; int copy_size = Min(range.m_Size, bytes_to_copy);
    SmallFastMemCpy(range.mp_Buffer, p_src, copy_size);
    p_src += copy_size;
    bytes_to_copy -= copy_size; m_RingBuffer.Add(copy_size);
    }
    }
    } //------------------------------------------------------------------------
    // slightly more optimal version for sending a single uint. Because all ringbuffer
    // operations are 4 byte aligned we can be guaranteed that the uint won't be split
    // between the end and start of the buffer, we will always get it in one piece.
    void CMemPro::SendData(unsigned int value)
    {
    if(!m_Connected)
    {
    StoreData(&value, sizeof(value));
    return;
    } if(!SendThreadStillAlive())
    {
    FlushRingBufferForShutdown();
    SocketSendData(&value, sizeof(value));
    #ifdef WRITE_DUMP
    fflush(gp_DumpFile);
    #endif
    }
    else
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetFreeRange();
    if(!m_Connected)
    return;
    } while(!range.m_Size);
    if(!m_Connected)
    return; MEMPRO_ASSERT(range.m_Size >= (int)sizeof(unsigned int));
    MEMPRO_ASSERT((((size_t)range.mp_Buffer) & ) == );
    *(unsigned int*)range.mp_Buffer = value; m_RingBuffer.Add(sizeof(value));
    }
    } //------------------------------------------------------------------------
    void CMemPro::SendPacketHeader(PacketType value)
    {
    SendStartMarker(); PacketHeader header;
    header.m_PacketType = value;
    header.m_Time = GetTime(); Send(header);
    } //------------------------------------------------------------------------
    void CMemPro::SendStartMarker()
    {
    #ifdef PACKET_START_END_MARKERS
    unsigned int start_marker = 0xabcdef01;
    ENDIAN_TEST(SwapEndian(start_marker));
    Send(start_marker);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendEndMarker()
    {
    #ifdef PACKET_START_END_MARKERS
    unsigned int end_marker = 0xaabbccdd;
    ENDIAN_TEST(SwapEndian(end_marker));
    Send(end_marker);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendPageState(bool send_memory)
    {
    CriticalSectionScope lock(m_CriticalSection); SendPacketHeader(EPageStateStartPacket);
    SendEndMarker(); #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMORY_BASIC_INFORMATION info;
    memset(&info, , sizeof(info)); uint64 addr = ; HANDLE process = GetCurrentProcess(); bool found_page = false; while(addr < g_MaxAddr)
    {
    uint64 last_addr = addr; if(VirtualQueryEx(process, (void*)addr, &info, sizeof(info)) != )
    {
    if((info.State == MEM_RESERVE || info.State == MEM_COMMIT) && info.Protect != PAGE_NOACCESS)
    {
    PageState page_state;
    switch(info.State)
    {
    case MEM_RESERVE: page_state = MemPro::Reserved; break;
    case MEM_COMMIT: page_state = MemPro::Committed; break;
    default: page_state = MemPro::Committed; MEMPRO_ASSERT(false); break;
    } #if defined(MEMPRO_PLATFORM_WIN)
    PageType page_type;
    switch(info.Type)
    {
    case MEM_IMAGE: page_type = page_Image; break;
    case MEM_MAPPED: page_type = page_Mapped; break;
    case MEM_PRIVATE: page_type = page_Private; break;
    default: page_type = page_Unknown; break;
    }
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin: xbox one should use same PageType
    //#error Please contact slynch@puredevsoftware.com for this platform
    PageType page_type;
    switch(info.Type)
    {
    case MEM_IMAGE: page_type = page_Image; break;
    case MEM_MAPPED: page_type = page_Mapped; break;
    case MEM_PRIVATE: page_type = page_Private; break;
    default: page_type = page_Unknown; break;
    }
    //@Virtuos[wangsongwei]end
    #else
    #error platform not defined
    #endif
    SendPageState(info.BaseAddress, info.RegionSize, page_state, page_type, info.Protect, send_memory);
    } addr += info.RegionSize;
    found_page = true;
    }
    else
    {
    if(!found_page)
    addr += PAGE_SIZE;
    else
    break; // VirtualQueryEx should only fail when it gets to the end, assuming it has found at least one page
    } if(addr < last_addr) // handle wrap around
    break;
    }
    #endif
    SendPacketHeader(EPageStateEndPacket); IgnoreMemRangePacket range_packet;
    range_packet.m_Addr = ToUInt64(m_RingBufferMem);
    range_packet.m_Size = sizeof(m_RingBufferMem);
    Send(range_packet); SendEndMarker();
    } //------------------------------------------------------------------------
    void CMemPro::SendVMemStats()
    {
    #ifdef VMEM_STATS
    //Send(EVMemStats);//@Virtuos[wangsongwei] error ? should use SendPacketHeader ?
    SendPacketHeader(EVMemStats);//@Virtuos[wangsongwei] test dingyifei code int64 time = GetTime();
    Send(time); VMem::SendStatsToMemPro(StaticSendVMemStatsData, this);
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::SendVirtualMemStats()
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    MEMORY_BASIC_INFORMATION info;
    memset(&info, , sizeof(info)); uint64 addr = ;
    size_t reserved = ;
    size_t committed = ; HANDLE process = GetCurrentProcess(); bool started = false; while(addr < g_MaxAddr)
    {
    uint64 last_addr = addr; if(VirtualQueryEx(process, (void*)addr, &info, sizeof(info)) != )
    {
    switch(info.State)
    {
    case MEM_RESERVE: reserved += info.RegionSize; break;
    case MEM_COMMIT: committed += info.RegionSize; break;
    } addr += info.RegionSize; started = true;
    }
    else
    {
    if(started)
    break; addr = (addr & (~((size_t)PAGE_SIZE-))) + PAGE_SIZE;
    } if(addr < last_addr) // handle wrap around
    break;
    } #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif
    reserved += committed; SendPacketHeader(EVirtualMemStats); VirtualMemStatsPacket packet;
    packet.m_Reserved = reserved;
    packet.m_Committed = committed;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet);
    #else
    SendPacketHeader(EVirtualMemStats); VirtualMemStatsPacket packet;
    packet.m_Reserved = ;
    packet.m_Committed = ;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet);
    #endif
    SendEndMarker();
    } //------------------------------------------------------------------------
    void** CMemPro::AllocateStackTraceData()
    {
    CriticalSectionScope lock(m_CriticalSection);
    return (void**)m_BlockAllocator.Alloc(STACK_TRACE_SIZE*sizeof(void*));
    } //------------------------------------------------------------------------
    CallstackCapture CMemPro::CaptureCallstack()
    {
    CallstackCapture callstack; callstack.mp_Stack = g_CallstackDataTLS;
    if(!callstack.mp_Stack)
    {
    callstack.mp_Stack = AllocateStackTraceData();
    g_CallstackDataTLS = callstack.mp_Stack;
    } callstack.m_Hash = ;
    callstack.m_Size = ;
    GetStackTrace(callstack.mp_Stack, callstack.m_Size, callstack.m_Hash); #ifdef USE_RTLVIRTUALUNWIND
    const int ignore_count = ;
    #else
    const int ignore_count = ;
    #endif
    callstack.m_Size -= ignore_count;
    if(callstack.m_Size <= )
    {
    callstack.mp_Stack[] = (void*)-;
    callstack.m_Size = ;
    } return callstack;
    } //------------------------------------------------------------------------
    int CMemPro::SendCallstack(const CallstackCapture& callstack_capture)
    {
    void** p_stack = callstack_capture.mp_Stack;
    int stack_size = callstack_capture.m_Size;
    int hash = callstack_capture.m_Hash; #ifdef MEMPRO64
    uint64* stack64 = (uint64*)p_stack;
    #else
    static uint64 stack64_static[STACK_TRACE_SIZE];
    for(int i=; i<stack_size; ++i)
    stack64_static[i] = ToUInt64(p_stack[i]);
    uint64* stack64 = stack64_static;
    #endif Callstack* p_callstack = m_CallstackSet.Get(stack64, stack_size, hash); if(!p_callstack)
    {
    p_callstack = m_CallstackSet.Add(stack64, stack_size, hash); SendPacketHeader(ECallstackPacket); int callstack_id = p_callstack->m_ID;
    #ifdef TEST_ENDIAN
    SwapEndian(callstack_id);
    #endif
    Send(callstack_id); int send_stack_size = stack_size;
    #ifdef TEST_ENDIAN
    for(int i=; i<stack_size; ++i) SwapEndian(stack64[i]);
    SwapEndian(send_stack_size);
    #endif
    Send(send_stack_size);
    SendData(stack64, stack_size*sizeof(uint64)); SendEndMarker();
    } return p_callstack->m_ID;
    } //------------------------------------------------------------------------
    void CMemPro::TakeSnapshot()
    {
    CriticalSectionScope lock(m_CriticalSection);
    SendPacketHeader(ETakeSnapshot);
    } //------------------------------------------------------------------------
    int CMemPro::SendThreadMainStatic(void* p_param)
    {
    return gp_MemPro->SendThreadMain(p_param);
    } //------------------------------------------------------------------------
    bool CMemPro::SocketSendData(const void* p_data, int size)
    {
    #ifdef WRITE_DUMP
    MEMPRO_ASSERT(gp_DumpFile);
    size_t result = fwrite(p_data, size, , gp_DumpFile);
    MEMPRO_ASSERT(result == );
    return true;
    #else
    return m_ClientSocket.Send((void*)p_data, size);
    #endif
    } //------------------------------------------------------------------------
    int CMemPro::SendThreadMain(void* p_param)
    {
    while(m_Connected)
    {
    RingBuffer::Range range;
    do {
    range = m_RingBuffer.GetAllocatedRange(); // timeout: check for disconnect every 100 ms
    if(!m_Connected)
    {
    m_SendThreadFinishedEvent.Set();
    return ;
    }
    } while(!range.m_Size); if(!SocketSendData(range.mp_Buffer, range.m_Size))
    {
    m_SendThreadFinishedEvent.Set();
    Disconnect(true);
    return ;
    } m_RingBuffer.Remove(range.m_Size);
    } m_SendThreadFinishedEvent.Set();
    return ;
    } //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    int CMemPro::ReceiveThreadMainStatic(void* p_param)
    {
    return gp_MemPro->ReceiveThreadMain(p_param);
    }
    #endif //------------------------------------------------------------------------
    #ifndef WRITE_DUMP
    int CMemPro::ReceiveThreadMain(void* p_param)
    {
    while(m_Connected)
    {
    unsigned int flag = ; if(m_ClientSocket.Receive(&flag, sizeof(flag)) != sizeof(flag))
    {
    m_ReceiveThreadFinishedEvent.Set();
    Disconnect(true);
    return ;
    } switch(flag)
    {
    case SendPageData: SendPageState(false/*send_memory*/); break;
    case SendPageDataWithMemory: SendPageState(true/*send memory*/); break;
    case EShutdownComplete: m_MemProReadyToShutdownEvent.Set(); break;
    }
    } m_ReceiveThreadFinishedEvent.Set();
    return ;
    }
    #endif //------------------------------------------------------------------------
    // http://www.debuginfo.com/articles/debuginfomatch.html #ifdef MEMPRO_WIN_BASED_PLATFORM
    struct CV_HEADER
    {
    int Signature;
    int Offset;
    }; struct CV_INFO_PDB20
    {
    CV_HEADER CvHeader;
    int Signature;
    int Age;
    char PdbFileName[MAX_PATH];
    }; struct CV_INFO_PDB70
    {
    int CvSignature;
    GUID Signature;
    int Age;
    char PdbFileName[MAX_PATH];
    };
    #endif void CMemPro::SendExtraModuleInfo(int64 ModuleBase)
    {
    #ifdef MEMPRO_PLATFORM_WIN
    IMAGE_DOS_HEADER* p_dos_header = (IMAGE_DOS_HEADER*)ModuleBase;
    IMAGE_NT_HEADERS* p_nt_header = (IMAGE_NT_HEADERS*)((char*)ModuleBase + p_dos_header->e_lfanew);
    IMAGE_OPTIONAL_HEADER& optional_header = p_nt_header->OptionalHeader;
    IMAGE_DATA_DIRECTORY& image_data_directory = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
    IMAGE_DEBUG_DIRECTORY* p_debug_info_array = (IMAGE_DEBUG_DIRECTORY*)(ModuleBase + image_data_directory.VirtualAddress);
    int count = image_data_directory.Size / sizeof(IMAGE_DEBUG_DIRECTORY);
    for(int i=; i<count; ++i)
    {
    if(p_debug_info_array[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
    {
    char* p_cv_data = (char*)(ModuleBase + p_debug_info_array[i].AddressOfRawData);
    if(strncmp(p_cv_data, "RSDS", ) == )
    {
    CV_INFO_PDB70* p_cv_info = (CV_INFO_PDB70*)p_cv_data;
    Send(true); // sending info
    Send(p_cv_info->Age);
    Send(p_cv_info->Signature);
    SendString(p_cv_info->PdbFileName);
    return; // returning here
    }
    else if(strncmp(p_cv_data, "NB10", ) == )
    {
    Send(true); // sending info
    CV_INFO_PDB20* p_cv_info = (CV_INFO_PDB20*)p_cv_data;
    Send(p_cv_info->Age);
    Send(p_cv_info->Signature);
    SendString(p_cv_info->PdbFileName);
    return; // returning here
    }
    }
    }
    #endif
    // failed to find info
    Send(false); // not sending info
    } //------------------------------------------------------------------------
    void CMemPro::SendString(const char* p_str)
    {
    const int max_path_len = ;
    int len = (int)strlen(p_str) + ;
    MEMPRO_ASSERT(len <= max_path_len); // round up to 4 bytes
    static char temp[max_path_len];
    memset(temp, , sizeof(temp));
    memcpy(temp, p_str, len); int rounded_len = ((int)len + ) & ~;
    Send(rounded_len); SendData(temp, rounded_len);
    } //------------------------------------------------------------------------
    #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #if !defined(_IMAGEHLP_SOURCE_) && defined(_IMAGEHLP64)
    // depending on your platform you may need to change PCSTR to PSTR for ModuleName
    BOOL CALLBACK CMemPro::EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in DWORD64 ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext)
    #else
    BOOL CALLBACK CMemPro::EnumerateLoadedModulesCallback(__in PCSTR ModuleName,__in ULONG ModuleBase,__in ULONG ModuleSize,__in_opt PVOID UserContext)
    #endif
    {
    CMemPro* p_this = (CMemPro*)UserContext; int64 module_base = ModuleBase;
    p_this->Send(module_base); p_this->SendString(ModuleName); p_this->SendExtraModuleInfo(ModuleBase); ++p_this->m_ModulesSent; return true;
    }
    #else
    int CMemPro::EnumerateLoadedModulesCallback(struct dl_phdr_info* info, size_t size, void* data)
    {
    CMemPro* p_this = (CMemPro*)data; int64 module_base = ;
    for (int j = ; j < info->dlpi_phnum; j++)
    {
    if (info->dlpi_phdr[j].p_type == PT_LOAD)
    {
    module_base = info->dlpi_addr + info->dlpi_phdr[j].p_vaddr;
    break;
    }
    } if(p_this->m_ModulesSent == )
    {
    // send the module base address
    int64 lookup_fn_marker = 0xabcdefabcdef1LL;
    p_this->Send(lookup_fn_marker); int64 module_base = (int64)BaseAddressLookupFunction; // use the address of the BaseAddressLookupFunction function so that we can work it out later
    p_this->Send(module_base); // get the module name
    char arg1[];
    char char_filename[MAX_PATH];
    sprintf(arg1, "/proc/%d/exe", getpid());
    memset(char_filename, , MAX_PATH);
    readlink(arg1, char_filename, MAX_PATH-);
    p_this->SendString(char_filename);
    }
    else
    {
    p_this->Send(module_base);
    p_this->SendString(info->dlpi_name);
    } p_this->SendExtraModuleInfo(); ++p_this->m_ModulesSent; return ;
    }
    #endif
    #endif //------------------------------------------------------------------------
    void CMemPro::SendModuleInfo()
    {
    Send(true); // indicate we are going to be sending module signatures - for backwards compatibility
    uint64 extra_module_info = 0xabcdef;
    Send(extra_module_info); m_ModulesSent = ; // if you are having problems compiling this on your platform undefine ENUMERATE_ALL_MODULES and it send info for just the main module
    #ifdef ENUMERATE_ALL_MODULES
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    #ifdef MEMPRO64
    EnumerateLoadedModules64(GetCurrentProcess(), EnumerateLoadedModulesCallback, this);
    #else
    EnumerateLoadedModules(GetCurrentProcess(), EnumerateLoadedModulesCallback, this);
    #endif
    #else
    dl_iterate_phdr(EnumerateLoadedModulesCallback, this);
    #endif
    #endif // if ENUMERATE_ALL_MODULES is disabled or enumeration failed for some reason, fall back
    // to getting the base address for the main module. This will always for for all platforms.
    if(m_ModulesSent == )
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    static int module = ;
    HMODULE module_handle = ;
    GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&module, &module_handle); int64 module_base = (int64)module_handle;
    Send(module_base); TCHAR tchar_filename[MAX_PATH] = { };
    GetModuleFileName(NULL, tchar_filename, MAX_PATH); char char_filename[MAX_PATH]; #ifdef UNICODE
    size_t chars_converted = ;
    wcstombs_s(&chars_converted, char_filename, tchar_filename, MAX_PATH);
    #else
    strcpy_s(char_filename, tchar_filename);
    #endif SendString(char_filename); Send(false); // not sending SendExtraModuleInfo
    #else
    // let MemPro know we are sending the lookup function address, not the base address
    uint64 use_module_base_addr_marker = 0xabcdefabcdef1LL;
    Send(use_module_base_addr_marker); // send the module base address
    int64 module_base = (int64)BaseAddressLookupFunction; // use the address of the BaseAddressLookupFunction function so that we can work it out later
    Send(module_base); // send the module name
    char char_filename[MAX_PATH]; // get the module name
    char arg1[];
    sprintf(arg1, "/proc/%d/exe", getpid());
    memset(char_filename, , MAX_PATH);
    readlink(arg1, char_filename, MAX_PATH-); SendString(char_filename); Send(false); // not sending SendExtraModuleInfo
    #endif
    } uint64 terminator = ;
    Send(terminator);
    } //------------------------------------------------------------------------
    bool CMemPro::WaitForConnection()
    {
    m_CriticalSection.Enter(); #ifdef WRITE_DUMP
    OutputDebugString(_T("MemPro writing to dump file " WRITE_DUMP _T("\n")));
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    _tfopen_s(&gp_DumpFile, WRITE_DUMP, _T("wb"));
    #else
    gp_DumpFile = fopen(WRITE_DUMP, _T("wb"));
    #endif
    MEMPRO_ASSERT(gp_DumpFile); m_Connected = true; m_SendThreadFinishedEvent.Reset(); // start the sending thread
    int thread_id = ;
    m_SendThread.CreateThread(SendThreadMainStatic, &thread_id);
    SetThreadName(thread_id, "MemPro write thread");
    #else
    // start listening for connections
    if(m_ListenSocket.IsValid() && !m_ListenSocket.StartListening())
    {
    m_WaitForConnectThreadFinishedEvent.Set(); // do this before Shutdown
    Shutdown();
    m_CriticalSection.Leave();
    return false;
    } m_StartedListening = true;
    m_StartedListeningEvent.Set(); // Accept a client socket
    bool accepted = false;
    if(m_ListenSocket.IsValid())
    {
    m_CriticalSection.Leave();
    accepted = m_ListenSocket.Accept(m_ClientSocket); if(!accepted)
    {
    bool shutting_down = m_ShuttingDown;
    m_WaitForConnectThreadFinishedEvent.Set(); // do this before Shutdown
    if(!shutting_down) // check shutting down here in case CMemPro has been destructed
    {
    m_CriticalSection.Enter();
    Shutdown();
    m_CriticalSection.Leave();
    }
    return false;
    }
    } m_CriticalSection.Enter(); m_Connected = true; m_SendThreadFinishedEvent.Reset();
    m_ReceiveThreadFinishedEvent.Reset(); // start the sending thread
    int send_thread_id = ;
    m_SendThread.CreateThread(SendThreadMainStatic, &send_thread_id);
    SetThreadName(send_thread_id, "MemPro send thread"); // start the receiving thread
    int receive_thread_id = ;
    m_ReceiveThread.CreateThread(ReceiveThreadMainStatic, &receive_thread_id);
    SetThreadName(receive_thread_id, "MemPro receive thread");
    #endif
    // send the connect key
    unsigned int endian_key = (unsigned int)EndianKey;
    ENDIAN_TEST(SwapEndian(endian_key));
    Send(endian_key); // send the connect packet
    ConnectPacket connect_packet;
    connect_packet.m_Padding = 0xabcdabcd;
    connect_packet.m_Version = MemPro::Version;
    connect_packet.m_TickFrequency = GetTickFrequency();
    connect_packet.m_ConnectTime = GetTime(); connect_packet.m_PtrSize = sizeof(void*); #ifdef MEMPRO_WIN_BASED_PLATFORM
    connect_packet.m_Platform = Platform_Windows;
    #else
    connect_packet.m_Platform = Platform_Unix;
    #endif ENDIAN_TEST(connect_packet.SwapEndian());
    Send(connect_packet); SendModuleInfo(); #if defined(MEMPRO_PLATFORM_WIN)
    #if (!defined(MIDL_PASS) && defined(_M_IX86) && !defined(_M_CEE_PURE)) || defined(MemoryBarrier)
    MemoryBarrier();
    #else
    std::atomic_thread_fence(std::memory_order_seq_cst);
    #endif
    #elif defined(MEMPRO_PLATFORM_XBOX360)
    #error Please contact slynch@puredevsoftware.com for this platform
    #elif defined(MEMPRO_PLATFORM_XBOXONE)
    //@Virtuos[wangsongwei]begin:
    //#error Please contact slynch@puredevsoftware.com for this platform
    // #if (!defined(MIDL_PASS) && defined(_M_IX86) && !defined(_M_CEE_PURE)) || defined(MemoryBarrier)
    //MemoryBarrier();
    FPlatformMisc::MemoryBarrier();//UE4's barrier
    // #else
    // std::atomic_thread_fence(std::memory_order_seq_cst);
    // #endif
    //@Virtuos[wangsongwei]end
    #elif defined(MEMPRO_UNIX_BASED_PLATFORM)
    __sync_synchronize();
    #else
    #error platform not defined
    #endif SendStoredData(); m_ReadyToSend = true; m_WaitForConnectThreadFinishedEvent.Set();
    m_CriticalSection.Leave(); // start the pulse thread
    int pulse_thread_id = ;
    m_PulseThreadFinished.Reset();
    m_PulseThread.CreateThread(PulseThreadMainStatic, &pulse_thread_id);
    SetThreadName(pulse_thread_id, "MemPro pulse thread"); return true;
    } //------------------------------------------------------------------------
    int CMemPro::WaitForConnectionThreadMainStatic(void* p_param)
    {
    return gp_MemPro->WaitForConnectionThreadMain(p_param);
    } //------------------------------------------------------------------------
    int CMemPro::PulseThreadMainStatic(void* p_param)
    {
    gp_MemPro->PulseThreadMain();
    return ;
    } //------------------------------------------------------------------------
    void CMemPro::PulseThreadMain()
    {
    while(m_Connected)
    {
    {
    CriticalSectionScope lock(m_CriticalSection);
    if(!m_Connected)
    break; SendPacketHeader(EPulsePacket);
    SendEndMarker();
    } Sleep();
    } m_PulseThreadFinished.Set();
    } //------------------------------------------------------------------------
    int CMemPro::WaitForConnectionThreadMain(void* p_param)
    {
    #ifdef WRITE_DUMP
    Sleep(MEMPRO_INIT_DELAY);
    #else
    if(!m_ListenSocket.IsValid())
    {
    Sleep(MEMPRO_INIT_DELAY); bool bind_result = m_ListenSocket.Bind(g_DefaultPort); if(!bind_result)
    OutputDebugString(_T("MemPro ERROR: Failed to bind port. This usually means that another process is already running with MemPro enabled.\n"));
    MEMPRO_ASSERT(bind_result);
    if(!bind_result)
    return ;
    }
    #endif
    WaitForConnection(); return ;
    } //------------------------------------------------------------------------
    bool CMemPro::Initialise()
    {
    m_WaitForConnectionThread.CreateThread(WaitForConnectionThreadMainStatic, NULL); return true;
    } //------------------------------------------------------------------------
    void CMemPro::Shutdown()
    {
    m_ShuttingDown = true; // wait for MemPro to have handled all data
    if(m_SendThread.IsAlive())
    {
    SendPacketHeader(ERequestShutdown);
    SendEndMarker();
    m_MemProReadyToShutdownEvent.Wait( * ); // do this so that we don't start listening after the listen socket has been shutdown and deadlock
    m_CriticalSection.Leave();
    m_StartedListeningEvent.Wait();
    m_CriticalSection.Enter(); if(m_WaitForConnect)
    {
    BlockUntilReadyToSend();
    BlockUntilSendThreadEmpty();
    }
    } Disconnect(false/*listen_for_new_connection*/); m_CriticalSection.Leave();
    m_PulseThreadFinished.Wait();
    m_CriticalSection.Enter(); #ifndef WRITE_DUMP
    m_ListenSocket.Disconnect(); if(m_WaitForConnectionThread.IsAlive())
    m_WaitForConnectThreadFinishedEvent.Wait(); #ifdef MEMPRO_WIN_BASED_PLATFORM
    WSACleanup();
    #endif
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::Disconnect(bool listen_for_new_connection)
    {
    CriticalSectionScope lock(m_DisconnectCriticalSection); if(m_Connected)
    {
    m_ReadyToSend = false;
    m_Connected = false; // wait for the send thread to shutdown
    m_SendThreadFinishedEvent.Wait();
    m_SendThreadFinishedEvent.Reset(); #ifdef WRITE_DUMP
    fclose(gp_DumpFile);
    gp_DumpFile = NULL;
    #else
    // close the client socket
    m_ClientSocket.Disconnect(); // wait for the receive thread to shutdown
    m_ReceiveThreadFinishedEvent.Wait();
    m_ReceiveThreadFinishedEvent.Reset();
    #endif
    // clear stuff
    m_CallstackSet.Clear(); m_RingBuffer.Clear(); #ifndef WRITE_DUMP
    if(listen_for_new_connection)
    {
    CriticalSectionScope lock2(m_CriticalSection); // start listening for another connection
    m_ListenSocket.Disconnect();
    m_StartedListeningEvent.Reset();
    m_StartedListening = false;
    m_InitialConnectionTimedOut = false;
    m_WaitForConnectionThread.CreateThread(WaitForConnectionThreadMainStatic, NULL);
    }
    #endif
    }
    } //------------------------------------------------------------------------
    void CMemPro::BlockUntilReadyToSend()
    {
    #ifndef WRITE_DUMP
    if(m_ListenSocket.IsValid())
    {
    OutputDebugString(_T("Waiting for connection to MemPro...\n")); int64 start_time = GetTime();
    while(!m_ReadyToSend && m_ListenSocket.IsValid() &&
    (m_WaitForConnect || ((GetTime() - start_time) / (double)GetTickFrequency()) * < MEMPRO_CONNECT_TIMEOUT))
    {
    m_CriticalSection.Leave();
    Sleep();
    m_CriticalSection.Enter();
    } if(m_ReadyToSend)
    {
    OutputDebugString(_T("Connected to MemPro!\n"));
    }
    else
    {
    m_InitialConnectionTimedOut = true;
    ClearStoreData();
    OutputDebugString(_T("Failed to connect to MemPro\n"));
    }
    }
    #endif
    } //------------------------------------------------------------------------
    // return true to continue processing event (either connected or before started listening)
    bool CMemPro::WaitForConnectionIfListening()
    {
    #ifdef WRITE_DUMP
    return true;
    #else
    if(!m_ReadyToSend && !m_InitialConnectionTimedOut)
    {
    CriticalSectionScope lock(m_CriticalSection); // store data until we have started listening
    if(!m_StartedListening)
    return true; BlockUntilReadyToSend();
    } return m_ReadyToSend;
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::TrackAlloc(void* p, size_t size, bool wait_for_connect)
    {
    if(m_Paused)
    return; m_WaitForConnect = wait_for_connect; if(!WaitForConnectionIfListening())
    return; CallstackCapture callstack_capture = CaptureCallstack(); CriticalSectionScope lock(m_CriticalSection); #ifndef WRITE_DUMP
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(m_ListenSocket.IsValid())
    {
    int now = GetTickCount();
    if(now - m_LastPageStateSend > m_PageStateInterval)
    {
    SendVirtualMemStats();
    m_LastPageStateSend = now;
    } if(now - m_LastVMemStatsSend > m_VMemStatsSendInterval)
    {
    SendVMemStats();
    m_LastVMemStatsSend = now;
    }
    }
    #endif
    #endif
    if(m_InEvent)
    return;
    m_InEvent = true; int callstack_id = SendCallstack(callstack_capture); SendPacketHeader(EAllocPacket); AllocPacket packet;
    packet.m_Addr = ToUInt64(p);
    packet.m_Size = size;
    packet.m_CallstackID = callstack_id;
    packet.m_Padding = 0xef12ef12;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); SendEndMarker(); m_InEvent = false;
    } //------------------------------------------------------------------------
    void CMemPro::TrackFree(void* p, bool wait_for_connect)
    {
    if(m_Paused)
    return; m_WaitForConnect = wait_for_connect; if(!WaitForConnectionIfListening())
    return; CriticalSectionScope lock(m_CriticalSection); if(m_InEvent)
    return;
    m_InEvent = true; SendPacketHeader(EFreePacket); FreePacket packet;
    packet.m_Addr = ToUInt64(p);
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); SendEndMarker(); m_InEvent = false;
    } //------------------------------------------------------------------------
    bool CMemPro::IsPaused()
    {
    return m_Paused;
    } //------------------------------------------------------------------------
    void CMemPro::SetPaused(bool paused)
    {
    m_Paused = paused;
    } //------------------------------------------------------------------------
    void CMemPro::SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(!WaitForConnectionIfListening())
    return; SendPacketHeader(EPageStatePacket); bool send_page_mem = send_memory && page_state == Committed && (page_protection & (PAGE_NOACCESS | PAGE_EXECUTE | PAGE_GUARD)) == ; PageStatePacket packet;
    packet.m_Addr = ToUInt64(p);
    packet.m_Size = size;
    packet.m_State = page_state;
    packet.m_Type = page_type;
    packet.m_Protection = page_protection;
    packet.m_SendingMemory = send_page_mem;
    ENDIAN_TEST(packet.SwapEndian());
    Send(packet); if(send_page_mem)
    {
    MEMPRO_ASSERT(!(size % PAGE_SIZE));
    char* p_page = (char*)p;
    char* p_end_page = p_page + size;
    while(p_page != p_end_page)
    {
    SendData(p_page, PAGE_SIZE);
    p_page += PAGE_SIZE;
    }
    } SendEndMarker();
    #endif
    } //------------------------------------------------------------------------
    void CMemPro::WaitForConnectionOnInitialise()
    {
    m_WaitForConnect = true; m_StartedListeningEvent.Wait(); CriticalSectionScope lock(m_CriticalSection);
    BlockUntilReadyToSend();
    }
    } //------------------------------------------------------------------------
    void MemPro::InitialiseInternal()
    {
    if(!gp_MemPro && !g_ShuttingDown)
    {
    gp_MemPro = (CMemPro*)g_MemProMem;
    new (gp_MemPro)CMemPro();
    gp_MemPro->Initialise();
    }
    } //------------------------------------------------------------------------
    void MemPro::IncRef()
    {
    ++g_MemProRefs;
    } //------------------------------------------------------------------------
    void MemPro::DecRef()
    {
    if(--g_MemProRefs == )
    Shutdown();
    } //------------------------------------------------------------------------
    // called by the APP (not internally)
    void MemPro::Initialise(bool wait_for_connect)
    {
    InitialiseInternal(); if(wait_for_connect)
    gp_MemPro->WaitForConnectionOnInitialise();
    } //------------------------------------------------------------------------
    void MemPro::Disconnect()
    {
    if(gp_MemPro)
    {
    gp_MemPro->Lock();
    gp_MemPro->Disconnect(true);
    gp_MemPro->Release();
    }
    } //------------------------------------------------------------------------
    void MemPro::Shutdown()
    {
    if(!g_ShuttingDown)
    {
    g_ShuttingDown = true;
    if(gp_MemPro)
    {
    gp_MemPro->Lock();
    gp_MemPro->Shutdown();
    gp_MemPro->Release();
    gp_MemPro->~CMemPro();
    memset(gp_MemPro, , sizeof(CMemPro));
    gp_MemPro = NULL;
    }
    }
    } //------------------------------------------------------------------------
    void MemPro::TrackAlloc(void* p, size_t size, bool wait_for_connect)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->TrackAlloc(p, size, wait_for_connect);
    } //------------------------------------------------------------------------
    void MemPro::TrackFree(void* p, bool wait_for_connect)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->TrackFree(p, wait_for_connect);
    } //------------------------------------------------------------------------
    void MemPro::SetPaused(bool paused)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->SetPaused(paused);
    } //------------------------------------------------------------------------
    bool MemPro::IsPaused()
    {
    CMemPro* p_mempro = GetMemPro();
    return p_mempro ? p_mempro->IsPaused() : false;
    } //------------------------------------------------------------------------
    void MemPro::SendPageState(void* p, size_t size, PageState page_state, PageType page_type, unsigned int page_protection, bool send_memory)
    {
    CMemPro* p_mempro = GetMemPro();
    if(p_mempro)
    p_mempro->SendPageState(p, size, page_state, page_type, page_protection, send_memory);
    } //------------------------------------------------------------------------
    void MemPro::TakeSnapshot()
    {
    if(gp_MemPro) gp_MemPro->TakeSnapshot();
    } //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO
    //------------------------------------------------------------------------
    // MemProLib.cpp //------------------------------------------------------------------------
    namespace MemPro
    {
    int mempro_total_alloc = ; //------------------------------------------------------------------------
    #if defined(MEMPRO_PLATFORM_XBOXONE)
    //#error Please contact slynch@puredevsoftware.com for this platform //@Virtuos[wangsongwei] I don't know what I need to do here, just annotate this line avoid compile error
    #endif
    }
    //------------------------------------------------------------------------
    // Socket.cpp #include <stdlib.h>
    #include <new> #ifdef MEMPRO_WIN_BASED_PLATFORM
    #include <tchar.h>
    #endif //------------------------------------------------------------------------
    #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP) //------------------------------------------------------------------------
    namespace MemPro
    {
    volatile int g_InitialiseCount = ;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::InitialiseWSA()
    {
    if(g_InitialiseCount == )
    {
    #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif #ifdef MEMPRO_WIN_BASED_PLATFORM
    // Initialize Winsock
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(,), &wsaData) != )
    {
    HandleError();
    return false;
    }
    #endif
    } ++g_InitialiseCount; return true;
    } //------------------------------------------------------------------------
    void MemPro::Socket::CleanupWSA()
    {
    --g_InitialiseCount; if(g_InitialiseCount == )
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(WSACleanup() == SOCKET_ERROR)
    HandleError();
    #endif #ifdef MEMPRO_PLATFORM_XBOX360
    #error Please contact slynch@puredevsoftware.com for this platform
    #endif
    }
    } //------------------------------------------------------------------------
    void MemPro::Socket::Disconnect()
    {
    if(m_Socket != INVALID_SOCKET)
    {
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(shutdown(m_Socket, SD_BOTH) == SOCKET_ERROR)
    HandleError();
    #else
    if(shutdown(m_Socket, SHUT_RDWR) == SOCKET_ERROR)
    HandleError();
    #endif // loop until the socket is closed to ensure all data is sent
    unsigned int buffer = ;
    size_t ret = ;
    do { ret = recv(m_Socket, (char*)&buffer, sizeof(buffer), ); } while(ret != && ret != (size_t)SOCKET_ERROR); #ifdef MEMPRO_WIN_BASED_PLATFORM
    if(closesocket(m_Socket) == SOCKET_ERROR)
    HandleError();
    #else
    close(m_Socket);
    #endif
    m_Socket = INVALID_SOCKET;
    }
    } //------------------------------------------------------------------------
    bool MemPro::Socket::StartListening()
    {
    MEMPRO_ASSERT(m_Socket != INVALID_SOCKET); if (listen(m_Socket, SOMAXCONN) == SOCKET_ERROR)
    {
    HandleError();
    return false;
    }
    return true;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Bind(const char* p_port)
    {
    MEMPRO_ASSERT(m_Socket == INVALID_SOCKET); if(!InitialiseWSA())
    return false; #ifdef MEMPRO_PLATFORM_WIN
    // setup the addrinfo struct
    addrinfo info;
    ZeroMemory(&info, sizeof(info));
    info.ai_family = AF_INET;
    info.ai_socktype = SOCK_STREAM;
    info.ai_protocol = IPPROTO_TCP;
    info.ai_flags = AI_PASSIVE; // Resolve the server address and port
    addrinfo* p_result_info;
    HRESULT result = getaddrinfo(NULL, p_port, &info, &p_result_info);
    if (result != )
    {
    HandleError();
    return false;
    } m_Socket = socket(
    p_result_info->ai_family,
    p_result_info->ai_socktype,
    p_result_info->ai_protocol);
    #else
    m_Socket = socket(
    AF_INET,
    SOCK_STREAM,
    IPPROTO_TCP);
    #endif if (m_Socket == INVALID_SOCKET)
    {
    #ifdef MEMPRO_PLATFORM_WIN
    freeaddrinfo(p_result_info);
    #endif
    HandleError();
    return false;
    } // Setup the TCP listening socket
    #ifdef MEMPRO_PLATFORM_WIN
    result = ::bind(m_Socket, p_result_info->ai_addr, (int)p_result_info->ai_addrlen);
    freeaddrinfo(p_result_info);
    #else
    // Bind to INADDR_ANY
    SOCKADDR_IN sa;
    sa.sin_family = AF_INET;
    sa.sin_addr.s_addr = INADDR_ANY;
    int iport = atoi(p_port);
    sa.sin_port = htons(iport);
    int result = ::bind(m_Socket, (const sockaddr*)(&sa), sizeof(SOCKADDR_IN));
    #endif if (result == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return false;
    } return true;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Accept(Socket& client_socket)
    {
    MEMPRO_ASSERT(client_socket.m_Socket == INVALID_SOCKET);
    client_socket.m_Socket = accept(m_Socket, NULL, NULL);
    return client_socket.m_Socket != INVALID_SOCKET;
    } //------------------------------------------------------------------------
    bool MemPro::Socket::Send(void* p_buffer, int size)
    {
    int bytes_to_send = size;
    while(bytes_to_send != )
    {
    int bytes_sent = (int)send(m_Socket, (char*)p_buffer, bytes_to_send, );
    if(bytes_sent == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return false;
    }
    p_buffer = (char*)p_buffer + bytes_sent;
    bytes_to_send -= bytes_sent;
    } return true;
    } //------------------------------------------------------------------------
    int MemPro::Socket::Receive(void* p_buffer, int size)
    {
    int total_bytes_received = ;
    while(size)
    {
    int bytes_received = (int)recv(m_Socket, (char*)p_buffer, size, ); total_bytes_received += bytes_received; if(bytes_received == )
    {
    Disconnect();
    return bytes_received;
    }
    else if(bytes_received == SOCKET_ERROR)
    {
    HandleError();
    Disconnect();
    return bytes_received;
    } size -= bytes_received;
    p_buffer = (char*)p_buffer + bytes_received;
    } return total_bytes_received;
    } //------------------------------------------------------------------------
    void MemPro::Socket::HandleError()
    {
    #ifdef MEMPRO_PLATFORM_WIN
    if(WSAGetLastError() == WSAEADDRINUSE)
    {
    OutputDebugString(_T("MemPro: Network connection conflict. Please make sure that other MemPro enabled applications are shut down, or change the port in the the MemPro lib and MemPro settings.\n"));
    return;
    } TCHAR* p_buffer = NULL;
    va_list args;
    FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    WSAGetLastError(),
    ,
    (TCHAR*)&p_buffer,
    * ,
    &args); OutputDebugString(p_buffer); LocalFree(p_buffer);
    #endif
    } //------------------------------------------------------------------------
    #endif // #if defined(ENABLE_MEMPRO) && !defined(WRITE_DUMP)
    //------------------------------------------------------------------------
    // Thread.cpp //------------------------------------------------------------------------
    #ifdef ENABLE_MEMPRO #ifdef MEMPRO_UNIX_BASED_PLATFORM
    #include <pthread.h>
    #endif //------------------------------------------------------------------------
    MemPro::Thread::Thread()
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    : m_Handle(),
    m_Alive(false)
    #else
    : m_Alive(false)
    #endif
    {
    } //------------------------------------------------------------------------
    void MemPro::Thread::CreateThread(ThreadMain p_thread_main, void* p_param)
    {
    mp_ThreadMain = p_thread_main;
    mp_Param = p_param; #ifdef MEMPRO_WIN_BASED_PLATFORM
    m_Handle = ::CreateThread(NULL, , PlatformThreadMain, this, , NULL);
    #else
    pthread_create(&m_Thread, NULL, PlatformThreadMain, this);
    #endif
    } //------------------------------------------------------------------------
    #ifdef MEMPRO_WIN_BASED_PLATFORM
    unsigned long WINAPI MemPro::Thread::PlatformThreadMain(void* p_param)
    {
    Thread* p_thread = (Thread*)p_param;
    p_thread->m_Alive = true;
    unsigned long ret = (unsigned long)p_thread->mp_ThreadMain(p_thread->mp_Param);
    p_thread->m_Alive = false;
    return ret;
    }
    #else
    void* MemPro::Thread::PlatformThreadMain(void* p_param)
    {
    Thread* p_thread = (Thread*)p_param;
    p_thread->m_Alive = true;
    p_thread->mp_ThreadMain(p_thread->mp_Param);
    p_thread->m_Alive = false;
    return NULL;
    }
    #endif //------------------------------------------------------------------------
    #endif // #ifdef ENABLE_MEMPRO

    MemPro.cpp

1. 将以上的hpp文件放到UE4\Engine\Source\Runtime\Core\Public\HAL,cpp文件放到UE4\Engine\Source\Runtime\Core\Private\HAL;

2. 文件Build.h末尾加上:

#if (!UE_EDITOR) && (PLATFORM_WINDOWS || PLATFORM_XBOXONE)
#define ENABLE_VIRTUOS_MEMPRO_UE4 //comment it to disable MemPro
#endif

3. 文件MallocBinned.h 加上(windows 和X1都走这个开辟文件):

 #ifdef ENABLE_VIRTUOS_MEMPRO_UE4
#include "MemPro.hpp"
#endif virtual void* Malloc( SIZE_T Size, uint32 Alignment ) override
{
... ...
#ifdef ENABLE_VIRTUOS_MEMPRO_UE4
MEMPRO_TRACK_ALLOC(Free, Size);
#endif return Free;
} virtual bool Free( void* Ptr ) override
{
if( !Ptr )
{
return true;
} #ifdef ENABLE_VIRTUOS_MEMPRO_UE4
MEMPRO_TRACK_FREE(Ptr);
#endif return PushFreeLockless(Ptr);
}

4. 如果要disable MemPro就在Build.h文件中注释掉即可;

运行方法:

当进行完以上四步后,怎样运行MemPro,X1和Windows是不同的:

------------------------------------------------------------------------------------------------

Windows版本exe利用MemPro运行:

1. 利用TCP socket传输dump数据,实时在MemPro的GUI中进行查看分析:

  打开MemPro在其GUI界面中设置好相关属性,其中包括Launch的exe路径(带".exe"),Working Dir(不带exe文件,只是路径,用于搜索与exe同名的pdb文件),启动游戏带的命令行参数(非必需),socket的ip和端口可以保持默认,默认的为(在Setting栏下查看):

    Connect IP:localhost

    Connect Port:27016

    Secondary Port:1255

  所有的设置都会保存在: C:\Users\username\AppData\Roaming\MemPro\MemPro.settings文件里面;

  然后在MemPro的GUI中点击Launch即可,其会利用Launch按钮中设定的exe和命令参数启动游戏;启动后可以“MemorySnapshot”按钮抓取dump,“Leak”分析内存泄露;

  注意,如果在MemPro正在监视你的游戏的时候关掉游戏窗口,Mempro就会自动抓取最后一个dump,在这个dump中,本来是一定泄露(“Leaked Memory”未引用的内存,未被释放)就会成为可以的泄露“Suspected memory leaked”;应该是因为进程被关掉了,那么之前的一定泄露的内存也就被系统回收了;

2. 让游戏运行过程中写出dump文件,然后关掉游戏在MemPro中分析dump:

  此种方法需要在MemPro.hpp文件中打开以下代码:

//------------------------------------------------------------------------
#define WRITE_DUMP _T("allocs.mempro_dump")//@Virtuos[wangsongwei] enable this macro to write dump instead of pass dump data by TCP socket

  默认生成的dump文件是allocs.mempro_dump, 路径在exe旁边(附近层级文件夹里面);可以通过“MemPro.exe allocs.mempro_dump”解析这个dump文件;解析前理论上应该在MemPro中设置对应的exe和working dir路径才对,这样解析的时候才能找到正确的pdb,但是发现没设置也行,估计是pdb信息都已经在解析的时候不需要了,在dump里了;

------------------------------------------------------------------------------------------------

X1版本exe利用MemPro运行:

由于MemPro本身无法远程启动X1 kit上的游戏(目前我还没确定方法),现在研究出来的X1版本的游戏和MemPro结合使用有两种方法:

1. 先启动X1上游戏,然后利用MemPro 的Connect按钮Connect上去进行解析;

  先进行相关设置:设置Launch和Connect:

  《Note --- Unreal --- MemPro (CONTINUE... ...)》

  《Note --- Unreal --- MemPro (CONTINUE... ...)》

  注意这里的ip,由于一个X1的kit开发机是有两个IP的,比如这里我的是有Tools IP是192.254.xxx.xxx,Console IP是10.0.x.xxx,这里使用的是console IP;我们团队这个IP基本不会改变,反而Tools IP经常改动,估计是IT干的事情导致的,所以用console IP以后可以不用频繁改动了;至于端口号4600是X1为TCP传输预留的端口,必须使用这个,UDP是4601;另外注意的是,我本机测试时候通过Tools IP是无法进行连接的,必须通过Console IP才能连接得上;

  配置完成,运行游戏,可以通过VS启动kit上游戏,或者利用X1的"XboxOneManager"工具都可以,等游戏在kit上启动起来,点击MemPro的Connect按钮,就可以连接上kit运行的游戏,接下来进行截取dump和分析leak都和windows平台的的一样,mempro代码会通过socket TCP传输dump但本机PC,另外解析会很慢;

  在本地测试中,利用MemPro的"Subtract Snapshots"功能可以生成新的dump,但是在leaks解析的时候Mempro会crash,可能游戏太大导致dump太大,也可能是我的代码还有点问题;

  此种方法最大的弊端是,游戏已经在kit上运行起来了,中途connect到kit上去,得到的数据都不是游戏从零启动的所有内存状态,对于随后的解析而言是不准确的;而MemPro的“MemoryGraph”里面显示的也只是自从connect上去之后的内存开辟情况,可以发现很少,因为connect之后可能开辟内存的行为就很少,而如果能够记录出游戏刚刚启动时候的所有开辟,就会是一个很大的量;因为这种泄露解析算法必须是要求所有dump数据都有,利用增量的方式来进行解析;但是对于一些streaming前后的比较,认为这种方式可能还是有点用的;

2. 离线使用MemPro,让X1游戏写入dump到kit上,而不是利用socket传输到本机PC,然后在本机上从kit上拷贝出X1的dump,利用MemPro解析这个dump:

  此种方法是官方给出的如果无法使用socket实现TCP连接的情况下的备选方案;它的好处应该是可以让游戏从头开始跑的时候就开始记录数据,这就解决了上面中途connect上去,丢失游戏刚启动的时候的内存开辟数据无法截取到的问题;

  

  关于从X1 kit上拷贝下来文件,简单的方法可以利用XBoxOne Manager来查看文件夹目录;或者利用命令行命令:

  xbapp list:列出connect的kit上的所有app;

  xbdir {MyTitle_1.0.0.0_neutral__8wekyb3d8bbwe}:\  或者

  xbdir /X:/title  XG:\ 来在文件夹层级之间切换

  xbcp xbcp source [target] [/A[[:]attributes]] [/B] [/S[[:]levels]] [/X[:]address [+<sessionkey>][/title]] 用于拷贝文件到本机

3. 在本机利用批处理文件启动MemPro的同时启动X1上的游戏,MemPro

  思路是,现在MemPro中配置好相关的设置,这些设置会存储在C:\Users\username\AppData\Roaming\MemPro\MemPro.settings,理想情况下,我们利用某个命令行参数指定给MemPro.exe就应该可以完成按照这个配置文件connect对应的exe,然后我们利用X1的XDK中自带xbapp.exe在本机远程启动kit上的游戏,由于二者行为几乎没有多少时间差,这样就几乎在kit上游戏启动时候就connect上去了,就几乎能够抓到游戏启动开始后的所有的内存开辟行为;

  相关的xbapp指令有:

@echo off
set IP=
set /p IP=Please input the IP address of the xboxone you want to connect:
set path=%DurangoXDK%\bin\
xbconnect %IP%
pause @echo off
Echo Need connect to XboxOne first, then run this bat!!!
set path=%DurangoXDK%\bin\
xbapp.exe deploy "New folder (2)" /v
pause @echo off
Echo Need connect to XboxOne first, then run this bat!!!
set path=%DurangoXDK%\bin\
xbapp.exe launch xxx_xxxxxxxxxxxx!yyyy -LoadSavedGame=C1_006.bsg
pause
rem xxxxx is your game id, yyyy is your game name without ".exe"

  实验发现,此思路不可行,主要是没找到MemPro.exe可以跟哪个参数直接通过命令行进行connect到某个exe或者launch某个exe,可能本来就没这个功能;此方案暂时流产;

===============================================================================================================================================================

如果在VS中运行时候挂在以下代码里面(这种情况点击“Launch”也会挂掉):

    int CMemPro::WaitForConnectionThreadMain(void* p_param)
{
#ifdef WRITE_DUMP
Sleep(MEMPRO_INIT_DELAY);
#else
if(!m_ListenSocket.IsValid())
{
Sleep(MEMPRO_INIT_DELAY); bool bind_result = m_ListenSocket.Bind(g_DefaultPort); if(!bind_result)
OutputDebugString(_T("MemPro ERROR: Failed to bind port. This usually means that another process is already running with MemPro enabled.\n"));
MEMPRO_ASSERT(bind_result);
if(!bind_result)
return ;
}
#endif
WaitForConnection(); return ;
}

按照提示是因为已经有了一个mempro在运行,这时候在任务管理器里面kill掉process “cmd. exe*32”;当开始运行mempro的时候会自动启动,如果上次没有正常关闭,该进程不会自动结束,导致下次使用mempro crash(点击“Launch”按钮crash多半是这个原因);

================================================================================================================================================================

其他:

如果在Unreal里面包含windows的头文件:

Where we need access to the Windows types in engine, we wrap the include in:

#include "AllowWindowsPlatformTypes.h"

#include "MyWindowsStuff.h"

#include "HideWindowsPlatformTypes.h"

-------------------------------------------------------------------------------------------------------

如上文中的代码:

        void *malloc(int size)
{
void* (*ptr)(int);
void* handle = (void*)-;
ptr = (void*)dlsym(handle, "malloc");
if(!ptr) abort();
void *p = (*ptr)(size);
MEMPRO_TRACK_ALLOC(p, size);
return p;
}

其中dlsym根据动态链接库操作句柄与符号,返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。这里获取系统的malloc函数指针,然后利用函数地址调用它,这样的方法确保调用的malloc确实是系统的,而不是被别人重载的;

-------------------------------------------------------------------------------------------------------

上一篇:mysql 查看最大连接数 设置最大连接数


下一篇:break与continue的区别