threading.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. //
  2. // libtgvoip is free and unencumbered public domain software.
  3. // For more information, see http://unlicense.org or the UNLICENSE file
  4. // you should have received with this source code distribution.
  5. //
  6. #ifndef __THREADING_H
  7. #define __THREADING_H
  8. #include <functional>
  9. #if defined(_POSIX_THREADS) || defined(_POSIX_VERSION) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
  10. #include <pthread.h>
  11. #include <semaphore.h>
  12. #include <sched.h>
  13. #include <unistd.h>
  14. #if defined(__APPLE__)
  15. #include "os/darwin/DarwinSpecific.h"
  16. #elif defined(__FreeBSD__) || defined(__OpenBSD__)
  17. #include <pthread_np.h>
  18. #endif
  19. namespace tgvoip{
  20. class Mutex{
  21. public:
  22. Mutex(){
  23. pthread_mutex_init(&mtx, NULL);
  24. }
  25. ~Mutex(){
  26. pthread_mutex_destroy(&mtx);
  27. }
  28. void Lock(){
  29. pthread_mutex_lock(&mtx);
  30. }
  31. void Unlock(){
  32. pthread_mutex_unlock(&mtx);
  33. }
  34. pthread_mutex_t* NativeHandle(){
  35. return &mtx;
  36. }
  37. private:
  38. Mutex(const Mutex& other);
  39. pthread_mutex_t mtx;
  40. };
  41. class Thread{
  42. public:
  43. Thread(std::function<void()> entry) : entry(entry){
  44. name=NULL;
  45. thread=0;
  46. }
  47. virtual ~Thread(){
  48. }
  49. void Start(){
  50. if(pthread_create(&thread, NULL, Thread::ActualEntryPoint, this)==0){
  51. valid=true;
  52. }
  53. }
  54. void Join(){
  55. if(valid)
  56. pthread_join(thread, NULL);
  57. }
  58. void SetName(const char* name){
  59. this->name=name;
  60. }
  61. void SetMaxPriority(){
  62. #ifdef __APPLE__
  63. maxPriority=true;
  64. #endif
  65. }
  66. static void Sleep(double seconds){
  67. usleep((useconds_t)(seconds*1000000.0));
  68. }
  69. bool IsCurrent(){
  70. return pthread_equal(thread, pthread_self())!=0;
  71. }
  72. private:
  73. static void* ActualEntryPoint(void* arg){
  74. Thread* self=reinterpret_cast<Thread*>(arg);
  75. if(self->name){
  76. #if defined(__linux__) || defined(__FreeBSD__)
  77. pthread_setname_np(self->thread, self->name);
  78. #elif defined(__OpenBSD__)
  79. pthread_set_name_np(self->thread, self->name);
  80. #elif defined(__APPLE__)
  81. pthread_setname_np(self->name);
  82. if(self->maxPriority){
  83. DarwinSpecific::SetCurrentThreadPriority(DarwinSpecific::THREAD_PRIO_USER_INTERACTIVE);
  84. }
  85. #endif
  86. }
  87. self->entry();
  88. return NULL;
  89. }
  90. std::function<void()> entry;
  91. pthread_t thread;
  92. const char* name;
  93. #ifdef __APPLE__
  94. bool maxPriority=false;
  95. #endif
  96. bool valid=false;
  97. };
  98. }
  99. #ifdef __APPLE__
  100. #include <dispatch/dispatch.h>
  101. namespace tgvoip{
  102. class Semaphore{
  103. public:
  104. Semaphore(unsigned int maxCount, unsigned int initValue){
  105. sem = dispatch_semaphore_create(initValue);
  106. }
  107. ~Semaphore(){
  108. #if ! __has_feature(objc_arc)
  109. dispatch_release(sem);
  110. #endif
  111. }
  112. void Acquire(){
  113. dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  114. }
  115. void Release(){
  116. dispatch_semaphore_signal(sem);
  117. }
  118. void Acquire(int count){
  119. for(int i=0;i<count;i++)
  120. Acquire();
  121. }
  122. void Release(int count){
  123. for(int i=0;i<count;i++)
  124. Release();
  125. }
  126. private:
  127. dispatch_semaphore_t sem;
  128. };
  129. }
  130. #else
  131. namespace tgvoip{
  132. class Semaphore{
  133. public:
  134. Semaphore(unsigned int maxCount, unsigned int initValue){
  135. sem_init(&sem, 0, initValue);
  136. }
  137. ~Semaphore(){
  138. sem_destroy(&sem);
  139. }
  140. void Acquire(){
  141. sem_wait(&sem);
  142. }
  143. void Release(){
  144. sem_post(&sem);
  145. }
  146. void Acquire(int count){
  147. for(int i=0;i<count;i++)
  148. Acquire();
  149. }
  150. void Release(int count){
  151. for(int i=0;i<count;i++)
  152. Release();
  153. }
  154. private:
  155. sem_t sem;
  156. };
  157. }
  158. #endif
  159. #elif defined(_WIN32)
  160. #define TGVOIP_WIN32_THREADING
  161. #include <Windows.h>
  162. #include <assert.h>
  163. namespace tgvoip{
  164. class Mutex{
  165. public:
  166. Mutex(){
  167. #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
  168. InitializeCriticalSection(&section);
  169. #else
  170. InitializeCriticalSectionEx(&section, 0, 0);
  171. #endif
  172. }
  173. ~Mutex(){
  174. DeleteCriticalSection(&section);
  175. }
  176. void Lock(){
  177. EnterCriticalSection(&section);
  178. }
  179. void Unlock(){
  180. LeaveCriticalSection(&section);
  181. }
  182. private:
  183. Mutex(const Mutex& other);
  184. CRITICAL_SECTION section;
  185. };
  186. class Thread{
  187. public:
  188. Thread(std::function<void()> entry) : entry(entry){
  189. name=NULL;
  190. thread=NULL;
  191. }
  192. ~Thread(){
  193. }
  194. void Start(){
  195. thread=CreateThread(NULL, 0, Thread::ActualEntryPoint, this, 0, &id);
  196. }
  197. void Join(){
  198. if(!thread)
  199. return;
  200. #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
  201. WaitForSingleObject(thread, INFINITE);
  202. #else
  203. WaitForSingleObjectEx(thread, INFINITE, false);
  204. #endif
  205. CloseHandle(thread);
  206. }
  207. void SetName(const char* name){
  208. this->name=name;
  209. }
  210. void SetMaxPriority(){
  211. SetThreadPriority(thread, THREAD_PRIORITY_HIGHEST);
  212. }
  213. static void Sleep(double seconds){
  214. ::Sleep((DWORD)(seconds*1000));
  215. }
  216. bool IsCurrent(){
  217. return id==GetCurrentThreadId();
  218. }
  219. private:
  220. static const DWORD MS_VC_EXCEPTION=0x406D1388;
  221. #pragma pack(push,8)
  222. typedef struct tagTHREADNAME_INFO
  223. {
  224. DWORD dwType; // Must be 0x1000.
  225. LPCSTR szName; // Pointer to name (in user addr space).
  226. DWORD dwThreadID; // Thread ID (-1=caller thread).
  227. DWORD dwFlags; // Reserved for future use, must be zero.
  228. } THREADNAME_INFO;
  229. #pragma pack(pop)
  230. static DWORD WINAPI ActualEntryPoint(void* arg){
  231. Thread* self=reinterpret_cast<Thread*>(arg);
  232. if(self->name){
  233. THREADNAME_INFO info;
  234. info.dwType=0x1000;
  235. info.szName=self->name;
  236. info.dwThreadID=-1;
  237. info.dwFlags=0;
  238. __try{
  239. RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
  240. }__except(EXCEPTION_EXECUTE_HANDLER){}
  241. }
  242. self->entry();
  243. return 0;
  244. }
  245. std::function<void()> entry;
  246. HANDLE thread;
  247. DWORD id;
  248. const char* name;
  249. };
  250. class Semaphore{
  251. public:
  252. Semaphore(unsigned int maxCount, unsigned int initValue){
  253. #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
  254. h=CreateSemaphore(NULL, initValue, maxCount, NULL);
  255. #else
  256. h=CreateSemaphoreEx(NULL, initValue, maxCount, NULL, 0, SEMAPHORE_ALL_ACCESS);
  257. assert(h);
  258. #endif
  259. }
  260. ~Semaphore(){
  261. CloseHandle(h);
  262. }
  263. void Acquire(){
  264. #if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
  265. WaitForSingleObject(h, INFINITE);
  266. #else
  267. WaitForSingleObjectEx(h, INFINITE, false);
  268. #endif
  269. }
  270. void Release(){
  271. ReleaseSemaphore(h, 1, NULL);
  272. }
  273. void Acquire(int count){
  274. for(int i=0;i<count;i++)
  275. Acquire();
  276. }
  277. void Release(int count){
  278. ReleaseSemaphore(h, count, NULL);
  279. }
  280. private:
  281. HANDLE h;
  282. };
  283. }
  284. #else
  285. #error "No threading implementation for your operating system"
  286. #endif
  287. namespace tgvoip{
  288. class MutexGuard{
  289. public:
  290. MutexGuard(Mutex &mutex) : mutex(mutex) {
  291. mutex.Lock();
  292. }
  293. ~MutexGuard(){
  294. mutex.Unlock();
  295. }
  296. private:
  297. Mutex &mutex;
  298. };
  299. }
  300. #endif //__THREADING_H