Thread.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. *
  5. * (c) ZeroTier, Inc.
  6. * https://www.zerotier.com/
  7. */
  8. #ifndef ZT_THREAD_HPP
  9. #define ZT_THREAD_HPP
  10. #include "../node/Constants.hpp"
  11. #include <stdexcept>
  12. #ifdef __WINDOWS__
  13. #include "../node/Mutex.hpp"
  14. #include <string.h>
  15. #include <windows.h>
  16. #include <winsock2.h>
  17. namespace ZeroTier {
  18. template <typename C> static DWORD WINAPI ___zt_threadMain(LPVOID lpParam)
  19. {
  20. try {
  21. ((C*)lpParam)->threadMain();
  22. }
  23. catch (...) {
  24. }
  25. return 0;
  26. }
  27. class Thread {
  28. public:
  29. Thread()
  30. {
  31. _th = NULL;
  32. _tid = 0;
  33. }
  34. template <typename C> static inline Thread start(C* instance)
  35. {
  36. Thread t;
  37. t._th = CreateThread(NULL, 0, &___zt_threadMain<C>, (LPVOID)instance, 0, &t._tid);
  38. if (t._th == NULL)
  39. throw std::runtime_error("CreateThread() failed");
  40. return t;
  41. }
  42. static inline void join(const Thread& t)
  43. {
  44. if (t._th != NULL) {
  45. for (;;) {
  46. DWORD ec = STILL_ACTIVE;
  47. GetExitCodeThread(t._th, &ec);
  48. if (ec == STILL_ACTIVE)
  49. WaitForSingleObject(t._th, 1000);
  50. else
  51. break;
  52. }
  53. }
  54. }
  55. static inline void sleep(unsigned long ms)
  56. {
  57. Sleep((DWORD)ms);
  58. }
  59. // Not available on *nix platforms
  60. static inline void cancelIO(const Thread& t)
  61. {
  62. #if ! defined(__MINGW32__) && ! defined(__MINGW64__) // CancelSynchronousIo not available in MSYS2
  63. if (t._th != NULL)
  64. CancelSynchronousIo(t._th);
  65. #endif
  66. }
  67. inline operator bool() const
  68. {
  69. return (_th != NULL);
  70. }
  71. private:
  72. HANDLE _th;
  73. DWORD _tid;
  74. };
  75. } // namespace ZeroTier
  76. #else
  77. #include <pthread.h>
  78. #include <stdio.h>
  79. #include <stdlib.h>
  80. #include <string.h>
  81. #include <unistd.h>
  82. namespace ZeroTier {
  83. template <typename C> static void* ___zt_threadMain(void* instance)
  84. {
  85. try {
  86. ((C*)instance)->threadMain();
  87. }
  88. catch (...) {
  89. }
  90. return (void*)0;
  91. }
  92. /**
  93. * A thread identifier, and static methods to start and join threads
  94. */
  95. class Thread {
  96. public:
  97. Thread()
  98. {
  99. memset(this, 0, sizeof(Thread));
  100. }
  101. Thread(const Thread& t)
  102. {
  103. memcpy(this, &t, sizeof(Thread));
  104. }
  105. inline Thread& operator=(const Thread& t)
  106. {
  107. memcpy(this, &t, sizeof(Thread));
  108. return *this;
  109. }
  110. /**
  111. * Start a new thread
  112. *
  113. * @param instance Instance whose threadMain() method gets called by new thread
  114. * @return Thread identifier
  115. * @throws std::runtime_error Unable to create thread
  116. * @tparam C Class containing threadMain()
  117. */
  118. template <typename C> static inline Thread start(C* instance)
  119. {
  120. Thread t;
  121. pthread_attr_t tattr;
  122. pthread_attr_init(&tattr);
  123. // This corrects for systems with abnormally small defaults (musl) and also
  124. // shrinks the stack on systems with large defaults to save a bit of memory.
  125. pthread_attr_setstacksize(&tattr, ZT_THREAD_MIN_STACK_SIZE);
  126. if (pthread_create(&t._tid, &tattr, &___zt_threadMain<C>, instance)) {
  127. pthread_attr_destroy(&tattr);
  128. throw std::runtime_error("pthread_create() failed, unable to create thread");
  129. }
  130. else {
  131. t._started = true;
  132. pthread_attr_destroy(&tattr);
  133. }
  134. return t;
  135. }
  136. /**
  137. * Join to a thread, waiting for it to terminate (does nothing on null Thread values)
  138. *
  139. * @param t Thread to join
  140. */
  141. static inline void join(const Thread& t)
  142. {
  143. if (t._started)
  144. pthread_join(t._tid, (void**)0);
  145. }
  146. /**
  147. * Sleep the current thread
  148. *
  149. * @param ms Number of milliseconds to sleep
  150. */
  151. static inline void sleep(unsigned long ms)
  152. {
  153. usleep(ms * 1000);
  154. }
  155. inline operator bool() const
  156. {
  157. return (_started);
  158. }
  159. private:
  160. pthread_t _tid;
  161. volatile bool _started;
  162. };
  163. } // namespace ZeroTier
  164. #endif // __WINDOWS__ / !__WINDOWS__
  165. #endif