/* * Copyright: JessMA Open Source (ldcsaa@gmail.com) * * Author : Bruce Liang * Website : https://github.com/ldcsaa * Project : https://github.com/ldcsaa/HP-Socket * Blog : http://www.cnblogs.com/ldcsaa * Wiki : http://www.oschina.net/p/hp-socket * QQ Group : 44636872, 75375912 * * 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. */ #pragma once #include "hpsocket/GlobalDef.h" #include "hpsocket/GlobalErrno.h" #include "SysHelper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #if !defined(__ANDROID__) typedef atomic_ulong atomic_tid; #define FPRINTLN(fd, fmt, ...) fprintf((fd), fmt "\n", ##__VA_ARGS__) #else typedef atomic_long atomic_tid; #if defined(stdout) #undef stdout #endif #if defined(stderr) #undef stderr #endif #define stdout nullptr #define stderr nullptr #define FPRINTLN(fd, fmt, ...) printf(fmt "\n", ##__VA_ARGS__) #endif #define PRINTLN(fmt, ...) FPRINTLN(stdout, fmt, ##__VA_ARGS__) #if defined(DEBUG) && defined(DEBUG_TRACE) #define TRACE(fmt, ...) PRINTLN("> TRC (0x%zX, %d) " fmt, (SIZE_T)SELF_THREAD_ID, SELF_NATIVE_THREAD_ID, ##__VA_ARGS__) #define ASSERT(expr) ((expr) ? TRUE : (::PrintStackTrace(), assert(FALSE), FALSE)) #else #define TRACE(fmt, ...) #define ASSERT(expr) assert(expr) #endif #define VERIFY(expr) ((expr) ? TRUE : (::PrintStackTrace(), ERROR_ABORT2(ERROR_VERIFY_CHECK), FALSE)) #define ASSERT_IS_NO_ERROR(expr) ASSERT(IS_NO_ERROR(expr)) #define VERIFY_IS_NO_ERROR(expr) VERIFY(IS_NO_ERROR(expr)) #define ENSURE(expr) VERIFY(expr) #define ENSURE_IS_NO_ERROR(expr) VERIFY_IS_NO_ERROR(expr) #define TEMP_FAILURE_RETRY_INT(exp) ((int)TEMP_FAILURE_RETRY(exp)) #define NO_EINTR TEMP_FAILURE_RETRY #define NO_EINTR_INT TEMP_FAILURE_RETRY_INT #define CHECK_IS_OK(expr) {if(IS_NOT_OK(expr)) return FALSE;} #define CHECK_ERROR_FD(fd) {if(IS_INVALID_FD(fd)) return FALSE;} #define CHECK_ERROR_INVOKE(expr) {if(!IS_NO_ERROR(expr)) return FALSE;} #define CHECK_ERROR_CODE(rs) {if(!IS_NO_ERROR(rs)) {::SetLastError(rs); return FALSE;}} #define CHECK_ERROR(expr, code) {if(!(expr)) {::SetLastError(code); return FALSE;}} #define CHECK_EINVAL(expr) CHECK_ERROR(expr, ERROR_INVALID_PARAMETER) #define ASSERT_CHECK_ERROR(expr, code) {ASSERT(expr); CHECK_ERROR(expr, code);} #define ASSERT_CHECK_EINVAL(expr) {ASSERT(expr); CHECK_EINVAL(expr);} #define SUCCEEDED(rs) IS_NO_ERROR(rs) #define FAILED(rs) (!SUCCEEDED(rs)) #define IS_OK(rs) ((BOOL)(rs)) #define IS_NOT_OK(rs) (!IS_OK(rs)) #define IS_ERROR(code) (::GetLastError() == (code)) #define CONTINUE_IF_ERROR(code) {if(IS_ERROR(code)) continue;} #define BREAK_IF_ERROR(code) {if(IS_ERROR(code)) break;} #define IS_WOULDBLOCK_ERROR() IS_ERROR(ERROR_WOULDBLOCK) #define CONTINUE_WOULDBLOCK_ERROR() CONTINUE_IF_ERROR(ERROR_WOULDBLOCK) #define BREAK_WOULDBLOCK_ERROR() BREAK_IF_ERROR(ERROR_WOULDBLOCK) #define IS_IO_PENDING_ERROR() IS_ERROR(ERROR_IO_PENDING) #define CONTINUE_IO_PENDING_ERROR() CONTINUE_IF_ERROR(ERROR_IO_PENDING) #define BREAK_IO_PENDING_ERROR() BREAK_IF_ERROR(ERROR_IO_PENDING) #define IS_INTR_ERROR() IS_ERROR(ERROR_INTR) #define CONTINUE_INTR_ERROR() CONTINUE_IF_ERROR(ERROR_INTR) #define BREAK_INTR_ERROR() BREAK_IF_ERROR(ERROR_INTR) #define EqualMemory(dest, src, len) (!memcmp((dest), (src), (len))) #define MoveMemory(dest, src, len) memmove((dest), (src), (len)) #define CopyMemory(dest, src, len) memcpy((dest), (src), (len)) #define FillMemory(dest, len, ch) memset((dest), (ch), (len)) #define ZeroMemory(dest, len) FillMemory((dest), (len), 0) #define ZeroObject(obj) ZeroMemory((&(obj)), sizeof(obj)) inline void SetLastError(int code) {errno = code;} inline int GetLastError() {return errno;} inline LPCSTR GetErrorStr(int code) {return strerror(code);} inline LPCSTR GetLastErrorStr() {return GetErrorStr(errno);} inline void PrintError(LPCSTR subject) {perror(subject);} #define EXECUTE_RESET_ERROR(expr) (::SetLastError(0), (expr)) #define EXECUTE_RESTORE_ERROR(expr) {int __le_ = ::GetLastError(); (expr); ::SetLastError(__le_);} #define EXECUTE_RESTORE_ERROR_RT(T, expr)\ ({int __le_ = ::GetLastError(); T __rs_ = (expr); ::SetLastError(__le_); __rs_;}) #define ENSURE_ERROR(def_code) ({int __le_ = ::GetLastError(); if(__le_ == NO_ERROR) __le_ = (def_code); __le_;}) #define ENSURE_ERROR_CANCELLED ENSURE_ERROR(ERROR_CANCELLED) #define TRIGGER(expr) EXECUTE_RESET_ERROR((expr)) #define _msize(p) malloc_usable_size(p) #define CreateLocalObjects(T, n) ((T*)alloca(sizeof(T) * (n))) #define CreateLocalObject(T) CreateLocalObjects(T, 1) #define CallocObjects(T, n) ((T*)calloc((n), sizeof(T))) #define MALLOC(T, n) ((T*)malloc(sizeof(T) * (n))) #define REALLOC(T, p, n) ((T*)realloc((PVOID)(p), sizeof(T) * (n))) #define FREE(p) free((PVOID)(p)) #define CALLOC(n, s) calloc((n), (s)) #define InterlockedExchangeAdd(p, n) __atomic_fetch_add((p), (n), memory_order_seq_cst) #define InterlockedExchangeSub(p, n) __atomic_fetch_sub((p), (n), memory_order_seq_cst) #define InterlockedAdd(p, n) __atomic_add_fetch((p), (n), memory_order_seq_cst) #define InterlockedSub(p, n) __atomic_sub_fetch((p), (n), memory_order_seq_cst) #define InterlockedIncrement(p) InterlockedAdd((p), 1) #define InterlockedDecrement(p) InterlockedSub((p), 1) #define ERROR_EXIT2(code, err) EXIT((code), (err), __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ERROR__EXIT2(code, err) _EXIT((code), (err), __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ERROR_ABORT2(err) ABORT((err), __FILE__, __LINE__, __PRETTY_FUNCTION__) #define ERROR_EXIT(code) ERROR_EXIT2((code), -1) #define ERROR__EXIT(code) ERROR__EXIT2((code), -1) #define ERROR_ABORT() ERROR_ABORT2(-1) #define IS_VALID_FD(fd) ((fd) != INVALID_FD) #define IS_INVALID_FD(fd) (!IS_VALID_FD(fd)) #define IS_VALID_PVOID(pv) ((pv) != INVALID_PVOID) #define IS_INVALID_PVOID(pv) (!IS_VALID_PVOID(pv)) #define TO_PVOID(v) ((PVOID)(UINT_PTR)(v)) #define FROM_PVOID(T, pv) ((T)(UINT_PTR)(pv)) #define IS_NULL(v) ((v) == nullptr) #define IS_NOT_NULL(v) (!IS_NULL(v)) #define stricmp strcasecmp #define strnicmp strncasecmp #define wcsicmp wcscasecmp #define wcsnicmp wcsncasecmp #ifdef _UNICODE #define tstrchr wcschr #define tstrrchr wcsrchr #define tstrstr wcsstr #define tstrpbrk wcspbrk #define tstrtok wcstok #define stscanf swscanf #define tstrlen wcslen #define tstrcpy wcscpy #define tstrcmp wcscmp #define tstricmp wcsicmp #define tstrncpy wcsncpy #define tstrncmp wcsncmp #define tstrnicmp wcsnicmp #define tstrspn wcsspn #define tstrcspn wcscspn #define wsprintf swprintf #else #define tstrchr strchr #define tstrrchr strrchr #define tstrstr strstr #define tstrpbrk strpbrk #define tstrtok strtok_r #define stscanf sscanf #define tstrlen strlen #define tstrcpy strcpy #define tstrcmp strcmp #define tstricmp stricmp #define tstrncpy strncpy #define tstrncmp strncmp #define tstrnicmp strnicmp #define tstrspn strspn #define tstrcspn strcspn #define wsprintf sprintf #endif inline const char* StrChr(const char* s, char c) {return strchr(s, c);} inline const char* StrRChr(const char* s, char c) {return strrchr(s, c);} inline const char* StrStr(const char* h, const char* n) {return strstr(h, n);} inline const char* StrPBrk(const char* s, const char* a) {return strpbrk(s, a);} inline const wchar_t* StrChr(const wchar_t* s, wchar_t c) {return wcschr(s, c);} inline const wchar_t* StrRChr(const wchar_t* s, wchar_t c) {return wcsrchr(s, c);} inline const wchar_t* StrStr(const wchar_t* h, const wchar_t* n) {return wcsstr(h, n);} inline const wchar_t* StrPBrk(const wchar_t* s, const wchar_t* a) {return wcspbrk(s, a);} inline LPSTR StrSep2(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n") {LPSTR lpTok; while((lpTok = strsep(lpStr, lpDelim)) != nullptr && lpTok[0] == 0); return lpTok;} inline LPSTR TrimLeft(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n") {while((*lpStr)[0] != 0 && ::StrChr(lpDelim, (*lpStr)[0]) != nullptr) ++(*lpStr); return (*lpStr);} inline LPSTR TrimRitht(LPSTR* lpStr, LPCSTR lpDelim = " \t\r\n") { LPSTR lpEnd = (*lpStr) + strlen(*lpStr) - 1; LPSTR lpCur = lpEnd; while(lpCur >= (*lpStr) && ::StrChr(lpDelim, lpCur[0]) != nullptr) --lpCur; if(lpCur != lpEnd) lpCur[1] = 0; return (*lpStr); } inline BOOL IsStrEmptyA(LPCSTR lpsz) {return (lpsz == nullptr || lpsz[0] == 0);} inline BOOL IsStrEmptyW(LPCWSTR lpsz) {return (lpsz == nullptr || lpsz[0] == 0);} inline BOOL IsStrNotEmptyA(LPCSTR lpsz) {return !IsStrEmptyA(lpsz);} inline BOOL IsStrNotEmptyW(LPCWSTR lpsz){return !IsStrEmptyW(lpsz);} inline LPCSTR SafeStrA(LPCSTR lpsz) {return (lpsz != nullptr) ? lpsz : "";} inline LPCWSTR SafeStrW(LPCWSTR lpsz) {return (lpsz != nullptr) ? lpsz : L"";} #ifdef _UNICODE #define IsStrEmpty(lpsz) IsStrEmptyW(lpsz) #define IsStrNotEmpty(lpsz) IsStrNotEmptyW(lpsz) #define SafeStr(lpsz) SafeStrW(lpsz) #else #define IsStrEmpty(lpsz) IsStrEmptyA(lpsz) #define IsStrNotEmpty(lpsz) IsStrNotEmptyA(lpsz) #define SafeStr(lpsz) SafeStrA(lpsz) #endif inline int lstrlen(LPCTSTR p) {return (int)tstrlen(p);} inline LPTSTR lstrcpy(LPTSTR d, LPCTSTR s) {return tstrcpy(d, s);} inline LPTSTR lstrncpy(LPTSTR d, LPCTSTR s, size_t n) {return tstrncpy(d, s, n);} inline int lstrcmp(LPCTSTR s1, LPCTSTR s2) {return tstrcmp(s1, s2);} inline int lstrncmp(LPCTSTR s1, LPCTSTR s2, size_t n) {return tstrncmp(s1, s2, n);} inline int lstricmp(LPCTSTR s1, LPCTSTR s2) {return tstricmp(s1, s2);} inline int lstrnicmp(LPCTSTR s1, LPCTSTR s2, size_t n) {return tstrnicmp(s1, s2, n);} inline int lstrspn(LPCTSTR s, LPCTSTR accept) {return (int)tstrspn(s, accept);} inline int lstrcspn(LPCTSTR s, LPCTSTR accept) {return (int)tstrcspn(s, accept);} template char (&_ArraySizeHelper(T(&arr)[N]))[N]; template char (&_ArraySizeHelper(const T(&arr)[N]))[N]; #define ARRAY_SIZE(arr) (sizeof(_ArraySizeHelper(arr))) #ifndef _countof #define _countof(arr) ARRAY_SIZE(arr) #endif #ifndef __countof #define __countof(arr) ARRAY_SIZE(arr) #endif #define THREAD_YIELD_CYCLE 63 #define THREAD_SWITCH_CYCLE 4095 inline void YieldThread(UINT i = THREAD_YIELD_CYCLE) { if((i & THREAD_SWITCH_CYCLE) == THREAD_SWITCH_CYCLE) ::SwitchToThread(); else if((i & THREAD_YIELD_CYCLE) == THREAD_YIELD_CYCLE) ::YieldProcessor(); } INT WaitFor(DWORD dwMillSecond, DWORD dwSecond = 0, BOOL bExceptThreadInterrupted = FALSE); INT Sleep(DWORD dwMillSecond, DWORD dwSecond = 0, BOOL bExceptThreadInterrupted = FALSE); __time64_t _time64(time_t* ptm = nullptr); __time64_t _mkgmtime64(tm* ptm); tm* _gmtime64(tm* ptm, __time64_t* pt); DWORD TimeGetTime(); ULLONG TimeGetTime64(); DWORD GetTimeGap32(DWORD dwOriginal, DWORD dwCurrent = 0); ULLONG GetTimeGap64(ULLONG ullOriginal, ULONGLONG ullCurrent = 0); LLONG TimevalToMillisecond(const timeval& tv); timeval& MillisecondToTimeval(LLONG ms, timeval& tv); LLONG TimespecToMillisecond(const timespec& ts); timespec& MillisecondToTimespec(LLONG ms, timespec& ts); timeval& GetFutureTimeval(LLONG ms, timeval& tv, struct timezone* ptz = nullptr); timespec& GetFutureTimespec(LLONG ms, timespec& ts, clockid_t clkid = CLOCK_MONOTONIC); FD CreateTimer(LLONG llInterval, LLONG llStart = -1, BOOL bRealTimeClock = FALSE); BOOL ReadTimer(FD tmr, ULLONG* pVal = nullptr, BOOL* pRs = nullptr); BOOL fcntl_SETFL(FD fd, INT fl, BOOL bSet = TRUE); void PrintStackTrace(); void EXIT(int iExitCode = 0, int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr); void _EXIT(int iExitCode = 0, int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr); void ABORT(int iErrno = -1, LPCSTR lpszFile = nullptr, int iLine = 0, LPCSTR lpszFunc = nullptr, LPCSTR lpszTitle = nullptr); /* 工作线程名称最大长度 */ #define MAX_THREAD_NAME_LENGTH 15 BOOL SetSequenceThreadName(THR_ID tid, LPCTSTR lpszPrefix, volatile UINT& vuiSeq); BOOL SetThreadName(THR_ID tid, LPCTSTR lpszPrefix, UINT uiSequence); BOOL SetThreadName(THR_ID tid, LPCTSTR lpszName); template::value>> inline bool IS_INFINITE(T v) { return v == (T)INFINITE; } template::value>> inline bool IS_HAS_ERROR(T v) { return v == (T)HAS_ERROR; } template::value>> inline bool IS_NO_ERROR(T v) { return v == (T)NO_ERROR; } template inline T InterlockedCompareExchange(volatile T* _Tgt, T _Value, T _Exp, BOOL _bWeek = FALSE, memory_order m1 = memory_order_seq_cst, memory_order m2 = memory_order_seq_cst) { __atomic_compare_exchange_n(_Tgt, &_Exp, _Value, _bWeek, m1, m2); return _Exp; } template, decay_t>::value && is_same, decay_t>::value>> inline V* InterlockedCompareExchangePointer(volatile T** _Tgt, V* _Value, E* _Exp, BOOL _bWeek = FALSE, memory_order m1 = memory_order_seq_cst, memory_order m2 = memory_order_seq_cst) { return (V*)(ULONG_PTR)InterlockedCompareExchange((volatile ULONG_PTR*)(volatile PVOID*)_Tgt, (ULONG_PTR)(PVOID)_Value, (ULONG_PTR)(PVOID)_Exp, _bWeek, m1, m2); } template inline T* ConstructObject(T* p, A&& ... args) { return new (p) T(forward(args) ...); } template inline void DestructObject(T* p) { p->T::~T(); } template, decay_t>::value>> inline void CopyPlainObject(T1* p1, const T2* p2) { CopyMemory(p1, p2, sizeof(T1)); } template::value && (is_same::value || is_same::value)>> C* _n_2_c(T value, C* lpszDest, int radix) { static const C* dig = "0123456789abcdefghijklmnopqrstuvwxyz"; bool neg = false; if(is_signed::value && value < 0) { value = -value; neg = true; } int n = 0; do { lpszDest[n++] = dig[value % radix]; value /= radix; } while(value); if(neg) lpszDest[n++] = '-'; lpszDest[n] = 0; C c, *p, *q; for(p = lpszDest, q = p + n - 1; p < q; ++p, --q) c = *p, *p = *q, *q = c; return lpszDest; } #define itoa(v, p, r) _n_2_c((v), (p), (r)) #define ltoa(v, p, r) _n_2_c((v), (p), (r)) #define lltoa(v, p, r) _n_2_c((v), (p), (r)) #define uitoa(v, p, r) _n_2_c((v), (p), (r)) #define ultoa(v, p, r) _n_2_c((v), (p), (r)) #define ulltoa(v, p, r) _n_2_c((v), (p), (r)) #define itow(v, p, r) _n_2_c((v), (p), (r)) #define ltow(v, p, r) _n_2_c((v), (p), (r)) #define lltow(v, p, r) _n_2_c((v), (p), (r)) #define uitow(v, p, r) _n_2_c((v), (p), (r)) #define ultow(v, p, r) _n_2_c((v), (p), (r)) #define ulltow(v, p, r) _n_2_c((v), (p), (r)) #define HEX_CHAR_TO_VALUE(c) (c <= '9' ? c - '0' : (c <= 'F' ? c - 'A' + 0x0A : c - 'a' + 0X0A)) #define HEX_DOUBLE_CHAR_TO_VALUE(pc) ((BYTE)(((HEX_CHAR_TO_VALUE(*(pc))) << 4) | (HEX_CHAR_TO_VALUE(*((pc) + 1))))) #define HEX_VALUE_TO_CHAR(n) (n <= 9 ? n + '0' : (n <= 'F' ? n + 'A' - 0X0A : n + 'a' - 0X0A)) #define HEX_VALUE_TO_DOUBLE_CHAR(pc, n) {*(pc) = (BYTE)HEX_VALUE_TO_CHAR((n >> 4)); *((pc) + 1) = (BYTE)HEX_VALUE_TO_CHAR((n & 0X0F));}