FuncHelper.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*
  2. * Copyright: JessMA Open Source (ldcsaa@gmail.com)
  3. *
  4. * Author : Bruce Liang
  5. * Website : https://github.com/ldcsaa
  6. * Project : https://github.com/ldcsaa/HP-Socket
  7. * Blog : http://www.cnblogs.com/ldcsaa
  8. * Wiki : http://www.oschina.net/p/hp-socket
  9. * QQ Group : 44636872, 75375912
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. #include "FuncHelper.h"
  24. #include "Thread.h"
  25. #include <ctype.h>
  26. #include <sched.h>
  27. #include <sys/time.h>
  28. #include <sys/select.h>
  29. #include <sys/timerfd.h>
  30. #if !defined(__ANDROID__)
  31. #include <sys/timeb.h>
  32. #include <execinfo.h>
  33. #ifdef __GNUC__
  34. #include <cxxabi.h>
  35. #endif
  36. #endif
  37. INT WaitFor(DWORD dwMillSecond, DWORD dwSecond, BOOL bExceptThreadInterrupted)
  38. {
  39. timeval tv {(time_t)dwSecond, (suseconds_t)(dwMillSecond * 1000)};
  40. if(bExceptThreadInterrupted)
  41. return NO_EINTR_EXCEPT_THR_INTR_INT(select(0, nullptr, nullptr, nullptr, &tv));
  42. return NO_EINTR_INT(select(0, nullptr, nullptr, nullptr, &tv));
  43. }
  44. INT Sleep(DWORD dwMillSecond, DWORD dwSecond, BOOL bExceptThreadInterrupted)
  45. {
  46. timespec ts_req = {(time_t)dwSecond, (long)(dwMillSecond * 1000000)};
  47. timespec ts_rem = ts_req;
  48. INT rs = NO_ERROR;
  49. while(IS_HAS_ERROR(rs = nanosleep(&ts_req, &ts_rem)))
  50. {
  51. if(!IS_INTR_ERROR())
  52. break;
  53. else
  54. {
  55. if(bExceptThreadInterrupted && ::IsThreadInterrupted())
  56. break;
  57. }
  58. ts_req = ts_rem;
  59. }
  60. return rs;
  61. }
  62. __time64_t _time64(time_t* ptm)
  63. {
  64. return (__time64_t)time(ptm);
  65. }
  66. __time64_t _mkgmtime64(tm* ptm)
  67. {
  68. return (__time64_t)timegm(ptm);
  69. }
  70. tm* _gmtime64(tm* ptm, __time64_t* pt)
  71. {
  72. time_t t = (time_t)(*pt);
  73. return gmtime_r(&t, ptm);
  74. }
  75. DWORD TimeGetTime()
  76. {
  77. return (DWORD)TimeGetTime64();
  78. }
  79. ULLONG TimeGetTime64()
  80. {
  81. #if !defined(__ANDROID__)
  82. timeb tb;
  83. if(ftime(&tb) == NO_ERROR)
  84. return (((ULLONG)(tb.time)) * 1000 + tb.millitm);
  85. #else
  86. timespec ts;
  87. if(clock_gettime(CLOCK_MONOTONIC, &ts) == NO_ERROR)
  88. return (((ULLONG)(ts.tv_sec)) * 1000 + ts.tv_nsec / 1000000);
  89. #endif
  90. return 0ull;
  91. }
  92. DWORD GetTimeGap32(DWORD dwOriginal, DWORD dwCurrent)
  93. {
  94. if(dwCurrent == 0)
  95. dwCurrent = ::TimeGetTime();
  96. return dwCurrent - dwOriginal;
  97. }
  98. ULLONG GetTimeGap64(ULLONG ullOriginal, ULONGLONG ullCurrent)
  99. {
  100. if(ullCurrent == 0)
  101. ullCurrent = ::TimeGetTime64();
  102. return ullCurrent - ullOriginal;
  103. }
  104. LLONG TimevalToMillisecond(const timeval& tv)
  105. {
  106. return tv.tv_sec * 1000 + tv.tv_usec / 1000;
  107. }
  108. timeval& MillisecondToTimeval(LLONG ms, timeval& tv)
  109. {
  110. tv.tv_sec = (time_t)(ms / 1000);
  111. tv.tv_usec = (suseconds_t)((ms % 1000) * 1000);
  112. return tv;
  113. }
  114. LLONG TimespecToMillisecond(const timespec& ts)
  115. {
  116. return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
  117. }
  118. timespec& MillisecondToTimespec(LLONG ms, timespec& ts)
  119. {
  120. ts.tv_sec = (time_t)(ms / 1000);
  121. ts.tv_nsec = (long)((ms % 1000) * 1000000);
  122. return ts;
  123. }
  124. timeval& GetFutureTimeval(LLONG ms, timeval& tv, struct timezone* ptz)
  125. {
  126. gettimeofday(&tv, ptz);
  127. tv.tv_sec += (time_t)(ms / 1000);
  128. tv.tv_usec += (suseconds_t)((ms % 1000) * 1000);
  129. return tv;
  130. }
  131. timespec& GetFutureTimespec(LLONG ms, timespec& ts, clockid_t clkid)
  132. {
  133. clock_gettime(clkid, &ts);
  134. ts.tv_sec += (time_t)(ms / 1000);
  135. ts.tv_nsec += (long)((ms % 1000) * 1000000);
  136. return ts;
  137. }
  138. FD CreateTimer(LLONG llInterval, LLONG llStart, BOOL bRealTimeClock)
  139. {
  140. ASSERT_CHECK_EINVAL(llInterval >= 0L);
  141. if(llStart < 0)
  142. llStart = llInterval;
  143. FD fdTimer = timerfd_create((bRealTimeClock ? CLOCK_REALTIME : CLOCK_MONOTONIC), TFD_NONBLOCK | TFD_CLOEXEC);
  144. itimerspec its;
  145. ::MillisecondToTimespec(llStart, its.it_value);
  146. ::MillisecondToTimespec(llInterval, its.it_interval);
  147. if(IS_HAS_ERROR(timerfd_settime(fdTimer, 0, &its, nullptr)))
  148. {
  149. close(fdTimer);
  150. fdTimer = INVALID_FD;
  151. }
  152. return fdTimer;
  153. }
  154. BOOL ReadTimer(FD tmr, ULLONG* pVal, BOOL* pRs)
  155. {
  156. static const SSIZE_T SIZE = sizeof(ULLONG);
  157. if(pVal == nullptr)
  158. pVal = CreateLocalObject(ULLONG);
  159. if(pRs == nullptr)
  160. pRs = CreateLocalObject(BOOL);
  161. if(read(tmr, pVal, SIZE) == SIZE)
  162. *pRs = TRUE;
  163. else
  164. {
  165. *pRs = FALSE;
  166. if(!IS_WOULDBLOCK_ERROR())
  167. return FALSE;
  168. }
  169. return TRUE;
  170. }
  171. BOOL fcntl_SETFL(FD fd, INT fl, BOOL bSet)
  172. {
  173. int val = fcntl(fd, F_GETFL);
  174. if(IS_HAS_ERROR(val))
  175. return FALSE;
  176. val = bSet ? (val | fl) : (val & (~fl));
  177. return IS_NO_ERROR(fcntl(fd, F_SETFL , val));
  178. }
  179. void PrintStackTrace()
  180. {
  181. #if !defined(__ANDROID__)
  182. const int MAX_SIZE = 51;
  183. void* arr[MAX_SIZE];
  184. int size = backtrace(arr, MAX_SIZE);
  185. char** messages = backtrace_symbols(arr, size);
  186. for(int i = 1; i < size && messages != nullptr; i++)
  187. {
  188. char* mangled_name = nullptr;
  189. char* offset_end = nullptr;
  190. const char* offset_begin = nullptr;
  191. for(char* p = messages[i]; *p; ++p)
  192. {
  193. if(*p == '(')
  194. {
  195. mangled_name = p;
  196. }
  197. else if(*p == '+')
  198. {
  199. offset_begin = p;
  200. }
  201. else if(*p == ')')
  202. {
  203. offset_end = p;
  204. break;
  205. }
  206. }
  207. if(mangled_name && offset_end && mangled_name < offset_end)
  208. {
  209. *mangled_name++ = 0;
  210. *offset_end++ = 0;
  211. if(offset_begin == nullptr)
  212. offset_begin = "";
  213. else
  214. *(char*)offset_begin++ = 0;
  215. while(*offset_end == ' ')
  216. ++offset_end;
  217. #ifdef __GNUC__
  218. int status;
  219. char* real_name = abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status);
  220. if(status == 0)
  221. FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], real_name, offset_begin, offset_end);
  222. else
  223. FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], mangled_name, offset_begin, offset_end);
  224. if(real_name != nullptr)
  225. free(real_name);
  226. #else
  227. FPRINTLN(stderr, " -> [%02d] %s : (%s+%s) %s", i, messages[i], mangled_name, offset_begin, offset_end);
  228. #endif
  229. }
  230. else
  231. {
  232. FPRINTLN(stderr, " -> [%02d] %s", i, messages[i]);
  233. }
  234. }
  235. free(messages);
  236. #endif
  237. }
  238. void __EXIT_FN_(void (*fn)(int), LPCSTR lpszFnName, int* lpiExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
  239. {
  240. if(iErrno >= 0)
  241. SetLastError(iErrno);
  242. else
  243. iErrno = GetLastError();
  244. if(!lpszTitle)
  245. {
  246. lpszTitle = CreateLocalObjects(char, 64);
  247. if(lpiExitCode)
  248. sprintf((LPSTR)lpszTitle, "(#%d, 0x%zX) > %s(%d) [%d]", SELF_PROCESS_ID, (SIZE_T)SELF_THREAD_ID, lpszFnName, *lpiExitCode, iErrno);
  249. else
  250. sprintf((LPSTR)lpszTitle, "(#%d, 0x%zX) > %s() [%d]", SELF_PROCESS_ID, (SIZE_T)SELF_THREAD_ID, lpszFnName, iErrno);
  251. }
  252. if(lpszFile && iLine > 0)
  253. FPRINTLN(stderr, "%s : %s\n => %s (%d) : %s", lpszTitle, strerror(iErrno), lpszFile, iLine, lpszFunc ? lpszFunc : "");
  254. else
  255. FPRINTLN(stderr, "%s : %s", lpszTitle, strerror(iErrno));
  256. if(lpiExitCode)
  257. fn(*lpiExitCode);
  258. else
  259. ((void (*)())fn)();
  260. }
  261. void EXIT(int iExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
  262. {
  263. __EXIT_FN_(exit, "exit", &iExitCode, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
  264. }
  265. void _EXIT(int iExitCode, int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
  266. {
  267. __EXIT_FN_(_exit, "_exit", &iExitCode, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
  268. }
  269. void ABORT(int iErrno, LPCSTR lpszFile, int iLine, LPCSTR lpszFunc, LPCSTR lpszTitle)
  270. {
  271. __EXIT_FN_((void (*)(int))abort, "abort", nullptr, iErrno, lpszFile, iLine, lpszFunc, lpszTitle);
  272. }
  273. BOOL SetSequenceThreadName(THR_ID tid, LPCTSTR lpszPrefix, volatile UINT& vuiSeq)
  274. {
  275. UINT uiSequence = InterlockedIncrement(&vuiSeq);
  276. return SetThreadName(tid, lpszPrefix, uiSequence);
  277. }
  278. BOOL SetThreadName(THR_ID tid, LPCTSTR lpszPrefix, UINT uiSequence)
  279. {
  280. int iMaxSeqLength = (int)(MAX_THREAD_NAME_LENGTH - lstrlen(lpszPrefix));
  281. ASSERT(iMaxSeqLength > 0);
  282. if(iMaxSeqLength <= 0)
  283. {
  284. ::SetLastError(ERROR_OUT_OF_RANGE);
  285. return FALSE;
  286. }
  287. ULONGLONG uiDiv = 1;
  288. for(int i = 0; i < iMaxSeqLength; i++)
  289. uiDiv *= 10;
  290. uiSequence = (UINT)(uiSequence % uiDiv);
  291. CString strName;
  292. strName.Format(_T("%s%u"), lpszPrefix, uiSequence);
  293. return SetThreadName(tid, strName);
  294. }
  295. BOOL SetThreadName(THR_ID tid, LPCTSTR lpszName)
  296. {
  297. ASSERT(lstrlen(lpszName) <= MAX_THREAD_NAME_LENGTH);
  298. if(tid == 0)
  299. tid = SELF_THREAD_ID;
  300. int rs = pthread_setname_np(tid, CT2A(lpszName));
  301. CHECK_ERROR_CODE(rs)
  302. return TRUE;
  303. }