From a6647904278598da2857fd06c1f7987f4940a9e9 Mon Sep 17 00:00:00 2001 From: thejinchao Date: Thu, 11 Apr 2019 18:15:18 -0500 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0windows.c=E8=8C=83=E4=BE=8B?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- samples/windows.c/CMakeLists.txt | 20 ++ samples/windows.c/TestMain.cpp | 375 +++++++++++++++++++++++ samples/windows.c/axtrace.win.c | 490 +++++++++++++++++++++++++++++++ samples/windows.c/axtrace.win.h | 117 ++++++++ samples/windows.c/ctpl.h | 251 ++++++++++++++++ 5 files changed, 1253 insertions(+) create mode 100644 samples/windows.c/CMakeLists.txt create mode 100644 samples/windows.c/TestMain.cpp create mode 100644 samples/windows.c/axtrace.win.c create mode 100644 samples/windows.c/axtrace.win.h create mode 100644 samples/windows.c/ctpl.h diff --git a/samples/windows.c/CMakeLists.txt b/samples/windows.c/CMakeLists.txt new file mode 100644 index 0000000..73e3cf1 --- /dev/null +++ b/samples/windows.c/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required (VERSION 3.1) +project(AxTrace4.Test) + +set(TEST_SOURCES + TestMain.cpp +) + +set(TEST_AXTRACE_C_SOURCES + axtrace.win.c + axtrace.win.h +) + + +add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) + +ADD_EXECUTABLE(Windows.C + ${TEST_SOURCES} + ${TEST_AXTRACE_C_SOURCES} +) + diff --git a/samples/windows.c/TestMain.cpp b/samples/windows.c/TestMain.cpp new file mode 100644 index 0000000..63882fb --- /dev/null +++ b/samples/windows.c/TestMain.cpp @@ -0,0 +1,375 @@ +#include +#include +#include "ctpl.h" +#include "axtrace.win.h" + +//-------------------------------------------------------------------------------------------- +struct AxTraceRequest +{ + void operator()(int id) + { + axlog(AXT_TRACE, "[%d]%s", id, message.c_str()); + } + + std::string message; + + AxTraceRequest(const char* msg) : message(msg) {} +}; + +//-------------------------------------------------------------------------------------------- +struct AxValueRequest +{ + void operator()(int id) + { + axvalue(AXV_STR_UTF16, m_strName.c_str(), m_strValue.c_str()); + } + + std::string m_strName; + std::wstring m_strValue; + + AxValueRequest(const char* szValueName, const wchar_t* wszVlaue) :m_strName(szValueName), m_strValue(wszVlaue) {} +}; + +double rand_number(double r1, double r2) +{ + double min = r1 < r2 ? r1 : r2; + double range = abs(r1 - r2); + return rand()*range / RAND_MAX + min; +} + +//-------------------------------------------------------------------------------------------- +int main(int argc, char* argv[]) +{ + printf("============= AxTrace4 Test(C++) ================\n"); + srand((unsigned int)::time(0)); + + //-------------------------- + { + printf("AxTrace Test\n"); + system("pause"); + + //test AxTrace + axlog(AXT_TRACE, "-=-=-=-=-=-= Hello,World -=-=-=-=-=-=-=-=-=-"); + axlog(AXT_TRACE, "中文字符+Ascii"); + axlog(AXT_TRACE, "MultiLineTest\nLine1:第一行\nLine2:第二行\nLine%d:第三行", 3); + + //test axlog type + axlog(AXT_DEBUG, "DEBUG: This is a debug message"); + axlog(AXT_INFO, "INFO: This is a info message"); + axlog(AXT_WARN, "WARN: This is a warning message"); + axlog(AXT_ERROR, "ERROR: This is a error message"); + axlog(AXT_FATAL, "FATAL: This is a fatal message"); + } + //-------------------------- + { + printf("AxTrace Pressure Test\n"); + system("pause"); + + int blank_Count = 0; + int step = 1; + int MAX_BLANK_COUNT = 50; + + axlog(AXT_TRACE, ""); + for (int i = 0; i<500; i++) + { + char szTemp[1024] = { 0 }; + + int j = 0; + for (j = 0; j= MAX_BLANK_COUNT) step = -1; + if (blank_Count <= 0)step = 1; + + szTemp[j++] = L'*'; + szTemp[j++] = 0; + + axlog(AXT_TRACE, szTemp); + } + axlog(AXT_TRACE, ""); + } + + //-------------------------- + { + printf("AxTrace Multithread Pressure Test\n"); + system("pause"); + + ctpl::thread_pool tp(std::thread::hardware_concurrency()); + + int blank_Count = 0; + int step = 1; + int MAX_BLANK_COUNT = 50; + + for (int i = 0; i < 500; i++) + { + char szTemp[1024] = { 0 }; + + int j = 0; + for (j = 0; j < blank_Count; j++) szTemp[j] = L' '; + + blank_Count += step; + if (blank_Count >= MAX_BLANK_COUNT) step = -1; + if (blank_Count <= 0)step = 1; + + szTemp[j++] = L'*'; + szTemp[j++] = 0; + + tp.push(AxTraceRequest(szTemp)); + } + + } + + //-------------------------- + { + printf("AxValue Test\n"); + system("pause"); + + #define AXVALUE(name, ex, type, out_type, value) name=value; axvalue(type, #name ex, &name); printf(#name ex "=" out_type "\n", value); + + char int_8 = 0; + AXVALUE(int_8, "_0", AXV_INT8, "%d", 0); + AXVALUE(int_8, "_MIN", AXV_INT8, "%d", SCHAR_MIN); + AXVALUE(int_8, "_MAX", AXV_INT8, "%d", SCHAR_MAX); + + unsigned int uint_8 = 0; + AXVALUE(uint_8, "_MIN", AXV_UINT8, "%d", 0); + AXVALUE(uint_8, "_MAX", AXV_UINT8, "%d", UCHAR_MAX); + + short int_16 = 0; + AXVALUE(int_16, "_0", AXV_INT16, "%d", 0); + AXVALUE(int_16, "_MIN", AXV_INT16, "%d", SHRT_MIN); + AXVALUE(int_16, "_MAX", AXV_INT16, "%d", SHRT_MAX); + + unsigned short uint_16 = 0; + AXVALUE(uint_16, "_MIN", AXV_UINT16, "%d", 0); + AXVALUE(uint_16, "_MAX", AXV_UINT16, "%d", USHRT_MAX); + + int int_32 = 8; + AXVALUE(int_32, "_0", AXV_INT32, "%d", 0); + AXVALUE(int_32, "_MIN", AXV_INT32, "%d", INT_MIN); + AXVALUE(int_32, "_MAX", AXV_INT32, "%d", INT_MAX); + + unsigned int uint_32 = 0; + AXVALUE(uint_32, "_MIN", AXV_UINT32, "%d", 0); + AXVALUE(uint_32, "_MAX", AXV_UINT32, "%u", UINT_MAX); + + __int64 int_64 = 0; + AXVALUE(int_64, "_0", AXV_INT64, "%I64d", 0i64); + AXVALUE(int_64, "_MIN", AXV_INT64, "%I64d", LLONG_MIN); + AXVALUE(int_64, "_MAX", AXV_INT64, "%I64d", LLONG_MAX); + + unsigned __int64 uint_64 = 0; + AXVALUE(uint_64, "_MIN", AXV_UINT64, "%I64u", 0i64); + AXVALUE(uint_64, "_MAX", AXV_UINT64, "%I64u", ULLONG_MAX); + + float float_32 = 0.f; + AXVALUE(float_32, "_0", AXV_FLOAT32, "%f", 0.f); + AXVALUE(float_32, "_MAX", AXV_FLOAT32, "%e", FLT_MAX); + AXVALUE(float_32, "_MIN", AXV_FLOAT32, "%e", FLT_MIN); + + double double_64 = 0.0; + AXVALUE(double_64, "_0", AXV_FLOAT64, "%f", 0.0); + AXVALUE(double_64, "_MAX", AXV_FLOAT64, "%e", DBL_MAX); + AXVALUE(double_64, "_MIN", AXV_FLOAT64, "%e", DBL_MIN); + + const char* pszString = "String 汉字(ACP)"; + axvalue(AXV_STR_ACP, "String_ACP", pszString); + + const char* pszString_UTF8 = "String \xE6\xB1\x89\xE5\xAD\x97(UTF8)"; //String 汉字(utf8) + axvalue(AXV_STR_UTF8, "String_UTF8", pszString_UTF8); + + const wchar_t* wszString = L"String 汉字(UTF16)"; + axvalue(AXV_STR_UTF16, "String_UTF16", wszString); + + } + + //-------------------------- + { + printf("AxValue Pressure Test\n"); + system("pause"); + + int start_blank = 0; + int start_step = 1; + int MAX_BLANK_COUNT = 50; + + for (int i = 0; i < 100; i++) + { + axvalue(AXV_INT32, "start_blank", &start_blank); + + int blank_Count = start_blank; + int step = start_step; + + for (int j = 0; j < 50; j++) + { + wchar_t wszTemp[1024] = { 0 }; + + int k = 0; + for (k = 0; k < blank_Count; k++) wszTemp[k] = L' '; + + blank_Count += step; + if (blank_Count >= MAX_BLANK_COUNT) step = -1; + if (blank_Count <= 0)step = 1; + + wszTemp[k++] = L'*'; + wszTemp[k++] = 0; + + char value_name[32] = { 0 }; + _snprintf(value_name, 32, "Value_%02d", j); + axvalue(AXV_STR_UTF16, value_name, wszTemp); + } + + start_blank += start_step; + if (start_blank >= MAX_BLANK_COUNT) start_step = -1; + if (start_blank <= 0) start_step = 1; + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + } + + { + ctpl::thread_pool tp(std::thread::hardware_concurrency()); + + int start_blank = 0; + int start_step = 1; + int MAX_BLANK_COUNT = 50; + + for (int i = 0; i<500; i++) + { + axvalue(AXV_INT32, "start_blank_multiThread", &start_blank); + int blank_Count = start_blank; + int step = start_step; + + for (int j = 0; j<50; j++) + { + wchar_t wszTemp[1024] = { 0 }; + + int k = 0; + for (k = 0; k= MAX_BLANK_COUNT) step = -1; + if (blank_Count <= 0)step = 1; + + wszTemp[k++] = L'*'; + wszTemp[k++] = 0; + + char value_name[32] = { 0 }; + _snprintf(value_name, 32, "Value_%02d", j); + + tp.push(AxValueRequest(value_name, wszTemp)); + } + + start_blank += start_step; + if (start_blank >= MAX_BLANK_COUNT) start_step = -1; + if (start_blank <= 0) start_step = 1; + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + } + + { + printf("AxMap2D Test\n"); + system("pause"); + + const int ACTOR_COUNTS = 100; + const int MOVE_COUNTS = 200; + + const double MAP_LEFT = -260.0; + const double MAP_TOP = 256.0; + const double MAP_RIGHT = 256.0; + const double MAP_BOTTOM = -256.0; + const double MOVE_STEP = 2.0; + const double PI = 3.14159265; + + double MAP_WIDTH = MAP_RIGHT - MAP_LEFT; + double MAP_HEIGHT = MAP_BOTTOM - MAP_TOP; + + struct Actor + { + double sx, sy; + double tx, ty; + + double x, y; + double dir; + + double current_distance(void) const { + return sqrt((x - sx)*(x - sx) + (y - sy)*(y - sy)); + } + double remain_distance(void) const { + return sqrt((x - tx)*(x - tx) + (y - ty)*(y - ty)); + } + }; + + Actor allActors[ACTOR_COUNTS]; + + std::function _selectNextTarget = [&](Actor& actor) { + do { + actor.tx = rand_number(MAP_LEFT, MAP_RIGHT); + actor.ty = rand_number(MAP_TOP, MAP_BOTTOM); + } while (actor.remain_distance()< MOVE_STEP*10); + actor.sx = actor.x; + actor.sy = actor.y; + actor.dir = atan2(actor.ty-actor.sy, actor.tx-actor.sx); + }; + + for (int i = 0; i < ACTOR_COUNTS; i++) + { + Actor& actor = allActors[i]; + + actor.sx = actor.x = rand_number(MAP_LEFT, MAP_RIGHT); + actor.sy = actor.y = rand_number(MAP_TOP, MAP_BOTTOM); + _selectNextTarget(actor); + } + + for (int i = 0; i < MOVE_COUNTS; i++) + { + ax2d_begin_scene("test", MAP_LEFT, MAP_TOP, MAP_RIGHT, MAP_BOTTOM, "{\"gridSize\":[32.0,32.0], \"gridPoint\":[-256.0, 256.0]}"); + + for (int j = 0; j < ACTOR_COUNTS; j++) + { + Actor& actor = allActors[j]; + + ax2d_actor("test", 100 + j, actor.x, actor.y, actor.dir, 0); + + if (actor.remain_distance() <= MOVE_STEP) { + _selectNextTarget(actor); + } + + if ((rand() % 10) > 5) { + double distance = actor.current_distance() + MOVE_STEP; + actor.x = actor.sx + distance * cos(actor.dir); + actor.y = actor.sy + distance * sin(actor.dir); + } + } + ax2d_end_scene("test"); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + system("pause"); + + for (int i = 0; i < ACTOR_COUNTS; i++) + { + char temp[256] = { 0 }; + double gridPointX = -256.0; + double gridPointY = 2560; + _snprintf(temp, 256, "{\"gridSize\":[32.0,32.0], \"gridPoint\":[%f,%f]}", gridPointX+i, gridPointY-i); + + ax2d_begin_scene("test", MAP_LEFT * 2, MAP_TOP * 2, MAP_RIGHT * 2, MAP_BOTTOM * 2, temp); + for (int j = 0; j < ACTOR_COUNTS-i; j++) + { + Actor& actor = allActors[j]; + ax2d_actor("test", 100 + j, actor.x, actor.y, actor.dir, 0); + } + ax2d_end_scene("test"); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + + } + + //-------------------------- + printf("DONE!\n"); + system("pause"); +} + diff --git a/samples/windows.c/axtrace.win.c b/samples/windows.c/axtrace.win.c new file mode 100644 index 0000000..836c1e5 --- /dev/null +++ b/samples/windows.c/axtrace.win.c @@ -0,0 +1,490 @@ +/*************************************************** + + AXIA|Trace3 + + (C) Copyright Jean(www.thecodeway.com). 2013 +***************************************************/ + +#include "axtrace.win.h" + +#if defined(_MSC_VER) +#include +#include +#include +#include +#pragma comment(lib, "ws2_32.lib") +#endif + +/*---------------------------------------------------------------------------------------------*/ +#define DEFAULT_AXTRACE_SERVER_IP "127.0.0.1" +#define DEFAULT_AXTRACE_SERVER_PORT (1978) +#define AXTRACE_MAX_TRACE_STRING_LENGTH (0x8000) +#define AXTRACE_MAX_VALUENAME_LENGTH (128) +#define AXTRACE_MAX_VALUE_LENGTH (1024) +#define AXTRACE_MAX_SCENE_NAME_LENGTH (128) +#define AXTRACE_MAX_SCENE_DEFINE_LENGTH (2048) + +#define AXTRACE_CMD_TYPE_LOG (1) +#define AXTRACE_CMD_TYPE_VALUE (2) +#define AXTRACE_CMD_TYPE_2D_BEGIN_SCENE (3) +#define AXTRACE_CMD_TYPE_2D_ACTOR (4) +#define AXTRACE_CMD_TYPE_2D_END_SCENE (5) + +/*---------------------------------------------------------------------------------------------*/ +/* AxTrace Global data */ +typedef struct +{ + int is_init_succ; /* 0 means not, 1 means yes*/ + struct sockaddr_in address; /* axtrace server address */ + SOCKET sfd; /* socket file desc*/ +} axtrace_contex_s; + +/*---------------------------------------------------------------------------------------------*/ +#pragma pack(push) +#pragma pack(1) +/* axtrace communication data struct*/ +typedef struct +{ + unsigned short length; /* length */ + unsigned char flag; /* magic flag, always 'A' */ + unsigned char type; /* command type AXTRACE_CMD_TYPE_* */ + unsigned int pid; /* process id*/ + unsigned int tid; /* thread id*/ +} axtrace_head_s; + +/* axtrace log data struct*/ +typedef struct +{ + axtrace_head_s head; /* common head */ + unsigned int log_type; /* trace style AXT_* */ + unsigned short code_page; /* code page */ + unsigned short length; /* trace string length */ + + /* [trace string data with '\0' ended] */ +} axtrace_log_s; + +typedef struct +{ + axtrace_head_s head; /* common head */ + unsigned int value_type; /* value type AXV_* */ + unsigned short name_len; /* length of value name */ + unsigned short value_len; /* length of value */ + + /* [name buf with '\0' ended]*/ + /* [value buf] */ +} axtrace_value_s; + +typedef struct +{ + axtrace_head_s head; /* common head */ + double left; /* left of scene*/ + double top; /* top of scene*/ + double right; /* right of scene*/ + double bottom; /* bottom of scene*/ + unsigned short name_len; /* length of scene name */ + unsigned short define_len; /* length of scene define */ + + /* [scene name buf with '\0' ended]*/ + /* [scene define buf with '\0' ended]*/ +} axtrace_2d_begin_scene_s; + +typedef struct +{ + axtrace_head_s head; /* common head */ + __int64 actor_id; /* id of actor */ + double x; /* position (x)*/ + double y; /* position (y)*/ + double dir; /* direction */ + unsigned int style; /* user define style */ + unsigned short name_len; /* length of scene name */ + + /* [scene name buf with '\0' ended]*/ +} axtrace_2d_actor_s; + +typedef struct +{ + axtrace_head_s head; /* common head */ + unsigned short name_len; /* length of scene name */ + + /* [scene name buf with '\0' ended]*/ +} axtrace_2d_end_scene_s; + +#pragma pack(pop) + +/*---------------------------------------------------------------------------------------------*/ +static axtrace_contex_s* _axtrace_try_init(const char* server_ip, unsigned short server_port) +{ + axtrace_contex_s* ctx = (axtrace_contex_s*)LocalAlloc(LPTR, sizeof(axtrace_contex_s)); + if (ctx == 0) + { + //TODO: fatal error, should stop the process + return 0; + } + memset(ctx, 0, sizeof (axtrace_contex_s)); + + WSADATA wsadata; + WSAStartup(MAKEWORD(2, 1), &wsadata); + + ctx->address.sin_family = AF_INET; + ctx->address.sin_port = htons(server_port != 0 ? server_port : DEFAULT_AXTRACE_SERVER_PORT); + if (0 == InetPtonA(AF_INET, + server_ip ? server_ip : DEFAULT_AXTRACE_SERVER_IP, + &(ctx->address.sin_addr))) + { + return ctx; + } + + /* connect to axtrace server*/ + ctx->sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + /* TODO: create non-blocking socket, so we can save some time when connect to server */ + + /* set SO_LINGER off, make sure all data in send buf can be sended */ + struct linger linger_; + linger_.l_onoff = 0; + linger_.l_linger = 0; + setsockopt(ctx->sfd, SOL_SOCKET, SO_LINGER, (const void*)&linger_, sizeof(linger_)); + + /* connect to server */ + if (connect(ctx->sfd, (const struct sockaddr*)&(ctx->address), sizeof(struct sockaddr_in)) == SOCKET_ERROR) + { + closesocket(ctx->sfd); + return ctx; + } + + /* init success */ + ctx->is_init_succ = 1; + return ctx; +} + +/*---------------------------------------------------------------------------------------------*/ +static axtrace_contex_s* _axtrace_get_thread_contex(const char* server_ip, unsigned short server_port) +{ + static __declspec(thread) axtrace_contex_s* s_the_thread_data = 0; + + if (s_the_thread_data != 0) { + /* already try init in this thread */ + return (s_the_thread_data->is_init_succ != 0) ? s_the_thread_data : 0; + } + + /* try init */ + s_the_thread_data = _axtrace_try_init(server_ip, server_port); + return (s_the_thread_data->is_init_succ != 0) ? s_the_thread_data : 0; +} + +/*---------------------------------------------------------------------------------------------*/ +void axlog(unsigned int log_type, const char *format, ...) +{ + axtrace_contex_s* ctx; + va_list ptr = 0; + HRESULT hr; + size_t contents_byte_size, final_length; + int send_len; + + /* buf for send , call send() once*/ + char buf[sizeof(axtrace_log_s) + AXTRACE_MAX_TRACE_STRING_LENGTH] = { 0 }; + axtrace_log_s* trace_head = (axtrace_log_s*)(buf); + char* trace_string = (char*)(buf + sizeof(axtrace_log_s)); + + /* is init ok? */ + ctx = _axtrace_get_thread_contex(0, 0); + if (ctx == 0) return; + + /* Create String Contents*/ + va_start(ptr, format); + hr = StringCbVPrintfA(trace_string, AXTRACE_MAX_TRACE_STRING_LENGTH, format, ptr); + va_end(ptr); + /* failed ?*/ + if (FAILED(hr)) return; + + /** get string length*/ + hr = StringCbLengthA(trace_string, AXTRACE_MAX_TRACE_STRING_LENGTH - 1, &contents_byte_size); + /* failed ?*/ + if (FAILED(hr)) return; + + /* add '\0' ended */ + contents_byte_size += 1; + + /* fill the trace head data */ + final_length = sizeof(axtrace_log_s)+contents_byte_size; + + trace_head->head.length = (unsigned short)(final_length); + trace_head->head.flag = 'A'; + trace_head->head.type = AXTRACE_CMD_TYPE_LOG; + trace_head->head.pid = GetCurrentProcessId(); + trace_head->head.tid = GetCurrentThreadId(); + + trace_head->log_type = log_type; + trace_head->code_page = ATC_ACP; + trace_head->length = (unsigned short)contents_byte_size; + + /* send to axtrace server*/ + send_len = send(ctx->sfd, buf, (int)final_length, MSG_DONTROUTE); + + /*TODO: check result, may be reconnect to server */ + return; +} + +/*---------------------------------------------------------------------------------------------*/ +static HRESULT _get_value_length(unsigned int value_type, const void* value, size_t* length) +{ + HRESULT hr; + size_t l; + + switch (value_type) + { + case AXV_INT8: case AXV_UINT8: *length = 1; return S_OK; + case AXV_INT16: case AXV_UINT16: *length = 2; return S_OK; + case AXV_INT32: case AXV_UINT32: *length = 4; return S_OK; + case AXV_INT64: case AXV_UINT64: *length = 8; return S_OK; + case AXV_FLOAT32: *length = 4; return S_OK; + case AXV_FLOAT64: *length = 8; return S_OK; + case AXV_STR_ACP: case AXV_STR_UTF8: + { + hr = StringCbLengthA((const char*)value, AXTRACE_MAX_VALUE_LENGTH - 1, &l); + if (FAILED(hr)) return hr; + *length = l + 1; + return S_OK; + } + case AXV_STR_UTF16: + { + hr = StringCbLengthW((const wchar_t*)value, AXTRACE_MAX_VALUE_LENGTH - 1, &l); + if (FAILED(hr)) return hr; + *length = l + 2; + return S_OK; + } + default: break; + } + return E_FAIL; +} + +/*---------------------------------------------------------------------------------------------*/ +void axvalue(unsigned int value_type, const char* value_name, const void* value) +{ + axtrace_contex_s* ctx; + HRESULT hr; + size_t value_name_length; + size_t value_length; + int send_len; + size_t final_length; + + /* buf for send , call send() once*/ + char buf[sizeof(axtrace_value_s) + AXTRACE_MAX_VALUENAME_LENGTH + AXTRACE_MAX_VALUE_LENGTH] = { 0 }; + axtrace_value_s* trace_head = (axtrace_value_s*)(buf); + char* value_name_buf = (char*)(buf + sizeof(axtrace_value_s)); + + /* is init ok? */ + ctx = _axtrace_get_thread_contex(0, 0); + if (ctx == 0) return; + + /** get value name length*/ + if (value_name == 0) return; + hr = StringCbLengthA(value_name, AXTRACE_MAX_VALUENAME_LENGTH - 1, &value_name_length); + if (FAILED(hr)) return; + /* add '\0' ended */ + value_name_length += 1; + if (value_name_length <= 0 || value_name_length >= AXTRACE_MAX_VALUENAME_LENGTH) return; + + if (value == 0) return; + hr = _get_value_length(value_type, value, &value_length); + if (FAILED(hr)) return; + if (value_length <= 0 || value_length >= AXTRACE_MAX_VALUE_LENGTH) return; + + /*calc final length */ + final_length = sizeof(axtrace_value_s) + value_name_length + value_length; + + trace_head->head.length = (unsigned short)(final_length); + trace_head->head.flag = 'A'; + trace_head->head.type = AXTRACE_CMD_TYPE_VALUE; + trace_head->head.pid = GetCurrentProcessId(); + trace_head->head.tid = GetCurrentThreadId(); + + trace_head->value_type = value_type; + trace_head->name_len = (unsigned short)value_name_length; + trace_head->value_len = (unsigned short)value_length; + + /* fill the value data */ + memcpy(value_name_buf, value_name, value_name_length); + memcpy(value_name_buf + value_name_length, value, value_length); + + /* send to axtrace server*/ + send_len = send(ctx->sfd, buf, (int)final_length, MSG_DONTROUTE); + + /*TODO: check result, may be reconnect to server */ + return; + +} + +/*---------------------------------------------------------------------------------------------*/ +void ax2d_begin_scene(const char* scene_name, double left, double top, double right, double bottom, const char* scene_define) +{ + axtrace_contex_s* ctx; + HRESULT hr; + size_t scene_name_size, scene_define_size, final_length; + int send_len; + + /* buf for send , call send() once*/ + char buf[sizeof(axtrace_2d_begin_scene_s) + AXTRACE_MAX_SCENE_NAME_LENGTH + AXTRACE_MAX_SCENE_DEFINE_LENGTH] = { 0 }; + axtrace_2d_begin_scene_s* trace_head = (axtrace_2d_begin_scene_s*)(buf); + char* _name = (char*)(buf + sizeof(axtrace_2d_begin_scene_s)); + + /* is init ok? */ + ctx = _axtrace_get_thread_contex(0, 0); + if (ctx == 0) return; + + /* copy scene name */ + hr = StringCbCopyA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH, scene_name); + /* failed ?*/ + if (FAILED(hr)) return; + + /** get string length*/ + hr = StringCbLengthA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH - 1, &scene_name_size); + /* failed ?*/ + if (FAILED(hr)) return; + if (scene_name_size <= 0 || scene_name_size >= AXTRACE_MAX_SCENE_NAME_LENGTH) return; + + /* add '\0' ended */ + scene_name_size += 1; + + /* to scene define point */ + if (scene_define != 0) { + _name = (char*)(buf + sizeof(axtrace_2d_begin_scene_s) + scene_name_size); + + /* copy scene define */ + hr = StringCbCopyA(_name, AXTRACE_MAX_SCENE_DEFINE_LENGTH, scene_define); + /* failed ?*/ + if (FAILED(hr)) return; + + /** get string length*/ + hr = StringCbLengthA(_name, AXTRACE_MAX_SCENE_DEFINE_LENGTH - 1, &scene_define_size); + /* failed ?*/ + if (FAILED(hr)) return; + if (scene_name_size >= AXTRACE_MAX_SCENE_DEFINE_LENGTH) return; + + /* add '\0' ended */ + scene_define_size += 1; + } + else { + scene_define_size = 0; + } + + final_length = sizeof(axtrace_2d_begin_scene_s) + scene_name_size + scene_define_size; + + trace_head->head.length = (unsigned short)(final_length); + trace_head->head.flag = 'A'; + trace_head->head.type = AXTRACE_CMD_TYPE_2D_BEGIN_SCENE; + trace_head->head.pid = GetCurrentProcessId(); + trace_head->head.tid = GetCurrentThreadId(); + + trace_head->left = left; + trace_head->top = top; + trace_head->right = right; + trace_head->bottom = bottom; + trace_head->name_len = (unsigned short)scene_name_size; + trace_head->define_len = (unsigned short)scene_define_size; + + /* send to axtrace server*/ + send_len = send(ctx->sfd, buf, (int)final_length, MSG_DONTROUTE); + + /*TODO: check result, may be reconnect to server */ + return; +} + +/*---------------------------------------------------------------------------------------------*/ +void ax2d_actor(const char* scene_name, __int64 actor_id, double x, double y, double dir, unsigned int actor_style) +{ + axtrace_contex_s* ctx; + HRESULT hr; + size_t scene_name_size, final_length; + int send_len; + + /* buf for send , call send() once*/ + char buf[sizeof(axtrace_2d_actor_s) + AXTRACE_MAX_SCENE_NAME_LENGTH] = { 0 }; + axtrace_2d_actor_s* trace_head = (axtrace_2d_actor_s*)(buf); + char* _name = (char*)(buf + sizeof(axtrace_2d_actor_s)); + + /* is init ok? */ + ctx = _axtrace_get_thread_contex(0, 0); + if (ctx == 0) return; + + /* copy scene name */ + hr = StringCbCopyA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH, scene_name); + /* failed ?*/ + if (FAILED(hr)) return; + + /** get string length*/ + hr = StringCbLengthA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH - 1, &scene_name_size); + /* failed ?*/ + if (FAILED(hr)) return; + + /* add '\0' ended */ + scene_name_size += 1; + + final_length = sizeof(axtrace_2d_actor_s) + scene_name_size; + + trace_head->head.length = (unsigned short)(final_length); + trace_head->head.flag = 'A'; + trace_head->head.type = AXTRACE_CMD_TYPE_2D_ACTOR; + trace_head->head.pid = GetCurrentProcessId(); + trace_head->head.tid = GetCurrentThreadId(); + + trace_head->actor_id = actor_id; + trace_head->x = x; + trace_head->y = y; + trace_head->dir = dir; + trace_head->style = actor_style; + trace_head->name_len = (unsigned short)scene_name_size; + + /* send to axtrace server*/ + send_len = send(ctx->sfd, buf, (int)final_length, MSG_DONTROUTE); + + /*TODO: check result, may be reconnect to server */ + return; +} + +/*---------------------------------------------------------------------------------------------*/ +void ax2d_end_scene(const char* scene_name) +{ + axtrace_contex_s* ctx; + HRESULT hr; + size_t scene_name_size, final_length; + int send_len; + + /* buf for send , call send() once*/ + char buf[sizeof(axtrace_2d_end_scene_s) + AXTRACE_MAX_SCENE_NAME_LENGTH] = { 0 }; + axtrace_2d_end_scene_s* trace_head = (axtrace_2d_end_scene_s*)(buf); + char* _name = (char*)(buf + sizeof(axtrace_2d_end_scene_s)); + + /* is init ok? */ + ctx = _axtrace_get_thread_contex(0, 0); + if (ctx == 0) return; + + /* copy scene name */ + hr = StringCbCopyA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH, scene_name); + /* failed ?*/ + if (FAILED(hr)) return; + + /** get string length*/ + hr = StringCbLengthA(_name, AXTRACE_MAX_SCENE_NAME_LENGTH - 1, &scene_name_size); + /* failed ?*/ + if (FAILED(hr)) return; + + /* add '\0' ended */ + scene_name_size += 1; + + final_length = sizeof(axtrace_2d_end_scene_s) + scene_name_size; + + trace_head->head.length = (unsigned short)(final_length); + trace_head->head.flag = 'A'; + trace_head->head.type = AXTRACE_CMD_TYPE_2D_END_SCENE; + trace_head->head.pid = GetCurrentProcessId(); + trace_head->head.tid = GetCurrentThreadId(); + + trace_head->name_len = (unsigned short)scene_name_size; + + /* send to axtrace server*/ + send_len = send(ctx->sfd, buf, (int)final_length, MSG_DONTROUTE); + + /*TODO: check result, may be reconnect to server */ + return; +} diff --git a/samples/windows.c/axtrace.win.h b/samples/windows.c/axtrace.win.h new file mode 100644 index 0000000..5268344 --- /dev/null +++ b/samples/windows.c/axtrace.win.h @@ -0,0 +1,117 @@ +/* +axia|trace4 +Copyright(C) thecodeway.com +*/ +#ifndef __AXIA_TRACE_WINDOWS_INCLUDE__ +#define __AXIA_TRACE_WINDOWS_INCLUDE__ + +#ifdef __cplusplus +#define AXTRACE_EXTERN_C extern "C" +#else +#define AXTRACE_EXTERN_C extern +#endif + +#define AXT_TRACE (0) +#define AXT_DEBUG (1) +#define AXT_INFO (2) +#define AXT_WARN (3) +#define AXT_ERROR (4) +#define AXT_FATAL (5) +#define AXT_USERDEF (10) + +#define ATC_ACP (0) //Default Windows ANSI code page. +#define ATC_UTF8 (1) //Unicode 8 +#define ATC_UTF16 (2) //Unicode 16 + +#define AXV_INT8 (0) +#define AXV_UINT8 (1) +#define AXV_INT16 (2) +#define AXV_UINT16 (3) +#define AXV_INT32 (4) +#define AXV_UINT32 (5) +#define AXV_INT64 (6) +#define AXV_UINT64 (7) +#define AXV_FLOAT32 (8) +#define AXV_FLOAT64 (9) +#define AXV_STR_ACP (10) +#define AXV_STR_UTF8 (11) +#define AXV_STR_UTF16 (12) +#define AXV_USER_DEF (100) + + +/* for UNICODE Application */ +#if !defined(_WCHAR_T_DEFINED) +/* +*Typically, wchar_t is defined when you use /Zc:wchar_t or +*when typedef unsigned short wchar_t; is executed in code. +*/ +typedef unsigned short wchar_t; +#endif + +/* +* send a log message to axtrace server +* @param log_type is one of AXT_*** value, +* @param format is the message described with system current codec +* +* sample: axlog(AXT_TRACE, "hello,world! I'm %s", name); +*/ +AXTRACE_EXTERN_C void axlog(unsigned int log_type, const char *format, ...); + +/* +* watch a value +* @param value_type is one of AXV_*** value, +* @param value_name is the name of value, ended with '\0' +* @param value is the memory address of value, the size of value is decided by value_type +*/ +AXTRACE_EXTERN_C void axvalue(unsigned int value_type, const char* value_name, const void* value); + + +/** +* begin draw a 2d scene + +left right ++----------------------------+ top +| | +| | +| | +| | +| | ++----------------------------+ bottom + +@param scene_name the name of scene(id) +@param x_min left of scene +@param y_min top of scene +@param x_max right of scene +@param y_max bottom of scene +@param scene_define extra define of scene, It's json object +*/ +AXTRACE_EXTERN_C void ax2d_begin_scene(const char* scene_name, double left, double top, double right, double bottom, const char* scene_define); + +/* +create/update a actor in the scene + ++-------------+--------------+ +| ^ | +| | y | +| x v | ++<----------> O | +| | +| | ++----------------------------+ + +@param scene_name the name of scene(id) +@param actor_id actor id +@param x actor position(x) +@param y actor position(y) +@param dir actor direction(0~2pi) +@param actor_style user define style +*/ +AXTRACE_EXTERN_C void ax2d_actor(const char* scene_name, __int64 actor_id, double x, double y, double dir, unsigned int actor_style); + +/* +draw all acotrs between ax2d_begin_scene and ax2d_end_scene +@param scene_name the name of scene(id) +*/ +AXTRACE_EXTERN_C void ax2d_end_scene(const char* scene_name); + +#endif diff --git a/samples/windows.c/ctpl.h b/samples/windows.c/ctpl.h new file mode 100644 index 0000000..8468526 --- /dev/null +++ b/samples/windows.c/ctpl.h @@ -0,0 +1,251 @@ +/********************************************************* +* +* Copyright (C) 2014 by Vitaliy Vitsentiy +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*********************************************************/ + + +#ifndef __ctpl_stl_thread_pool_H__ +#define __ctpl_stl_thread_pool_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +// thread pool to run user's functors with signature +// ret func(int id, other_params) +// where id is the index of the thread that runs the functor +// ret is some return type + + +namespace ctpl { + + namespace detail { + template + class Queue { + public: + bool push(T const & value) { + std::unique_lock lock(this->mutex); + this->q.push(value); + return true; + } + // deletes the retrieved element, do not use for non integral types + bool pop(T & v) { + std::unique_lock lock(this->mutex); + if (this->q.empty()) + return false; + v = this->q.front(); + this->q.pop(); + return true; + } + bool empty() { + std::unique_lock lock(this->mutex); + return this->q.empty(); + } + private: + std::queue q; + std::mutex mutex; + }; + } + + class thread_pool { + + public: + + thread_pool() { this->init(); } + thread_pool(int nThreads) { this->init(); this->resize(nThreads); } + + // the destructor waits for all the functions in the queue to be finished + ~thread_pool() { + this->stop(true); + } + + // get the number of running threads in the pool + int size() { return static_cast(this->threads.size()); } + + // number of idle threads + int n_idle() { return this->nWaiting; } + std::thread & get_thread(int i) { return *this->threads[i]; } + + // change the number of threads in the pool + // should be called from one thread, otherwise be careful to not interleave, also with this->stop() + // nThreads must be >= 0 + void resize(int nThreads) { + if (!this->isStop && !this->isDone) { + int oldNThreads = static_cast(this->threads.size()); + if (oldNThreads <= nThreads) { // if the number of threads is increased + this->threads.resize(nThreads); + this->flags.resize(nThreads); + + for (int i = oldNThreads; i < nThreads; ++i) { + this->flags[i] = std::make_shared>(false); + this->set_thread(i); + } + } + else { // the number of threads is decreased + for (int i = oldNThreads - 1; i >= nThreads; --i) { + *this->flags[i] = true; // this thread will finish + this->threads[i]->detach(); + } + { + // stop the detached threads that were waiting + std::unique_lock lock(this->mutex); + this->cv.notify_all(); + } + this->threads.resize(nThreads); // safe to delete because the threads are detached + this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals + } + } + } + + // empty the queue + void clear_queue() { + std::function * _f; + while (this->q.pop(_f)) + delete _f; // empty the queue + } + + // pops a functional wrapper to the original function + std::function pop() { + std::function * _f = nullptr; + this->q.pop(_f); + std::unique_ptr> func(_f); // at return, delete the function even if an exception occurred + std::function f; + if (_f) + f = *_f; + return f; + } + + // wait for all computing threads to finish and stop all threads + // may be called asynchronously to not pause the calling thread while waiting + // if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions + void stop(bool isWait = false) { + if (!isWait) { + if (this->isStop) + return; + this->isStop = true; + for (int i = 0, n = this->size(); i < n; ++i) { + *this->flags[i] = true; // command the threads to stop + } + this->clear_queue(); // empty the queue + } + else { + if (this->isDone || this->isStop) + return; + this->isDone = true; // give the waiting threads a command to finish + } + { + std::unique_lock lock(this->mutex); + this->cv.notify_all(); // stop all waiting threads + } + for (int i = 0; i < static_cast(this->threads.size()); ++i) { // wait for the computing threads to finish + if (this->threads[i]->joinable()) + this->threads[i]->join(); + } + // if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads + // therefore delete them here + this->clear_queue(); + this->threads.clear(); + this->flags.clear(); + } + + template + auto push(F && f, Rest&&... rest) ->std::future { + auto pck = std::make_shared>( + std::bind(std::forward(f), std::placeholders::_1, std::forward(rest)...) + ); + auto _f = new std::function([pck](int id) { + (*pck)(id); + }); + this->q.push(_f); + std::unique_lock lock(this->mutex); + this->cv.notify_one(); + return pck->get_future(); + } + + // run the user's function that excepts argument int - id of the running thread. returned value is templatized + // operator returns std::future, where the user can get the result and rethrow the catched exceptins + template + auto push(F && f) ->std::future { + auto pck = std::make_shared>(std::forward(f)); + auto _f = new std::function([pck](int id) { + (*pck)(id); + }); + this->q.push(_f); + std::unique_lock lock(this->mutex); + this->cv.notify_one(); + return pck->get_future(); + } + + + private: + + // deleted + thread_pool(const thread_pool &);// = delete; + thread_pool(thread_pool &&);// = delete; + thread_pool & operator=(const thread_pool &);// = delete; + thread_pool & operator=(thread_pool &&);// = delete; + + void set_thread(int i) { + std::shared_ptr> flag(this->flags[i]); // a copy of the shared ptr to the flag + auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() { + std::atomic & _flag = *flag; + std::function * _f; + bool isPop = this->q.pop(_f); + while (true) { + while (isPop) { // if there is anything in the queue + std::unique_ptr> func(_f); // at return, delete the function even if an exception occurred + (*_f)(i); + if (_flag) + return; // the thread is wanted to stop, return even if the queue is not empty yet + else + isPop = this->q.pop(_f); + } + // the queue is empty here, wait for the next command + std::unique_lock lock(this->mutex); + ++this->nWaiting; + this->cv.wait(lock, [this, &_f, &isPop, &_flag]() { isPop = this->q.pop(_f); return isPop || this->isDone || _flag; }); + --this->nWaiting; + if (!isPop) + return; // if the queue is empty and this->isDone == true or *flag then return + } + }; + this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique() + } + + void init() { this->nWaiting = 0; this->isStop = false; this->isDone = false; } + + std::vector> threads; + std::vector>> flags; + detail::Queue *> q; + std::atomic isDone; + std::atomic isStop; + std::atomic nWaiting; // how many threads are waiting + + std::mutex mutex; + std::condition_variable cv; + }; + +} + +#endif // __ctpl_stl_thread_pool_H__ \ No newline at end of file