unix_threads.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*=============================================================================|
  2. | PROJECT SNAP7 1.3.0 |
  3. |==============================================================================|
  4. | Copyright (C) 2013, 2015 Davide Nardella |
  5. | All rights reserved. |
  6. |==============================================================================|
  7. | SNAP7 is free software: you can redistribute it and/or modify |
  8. | it under the terms of the Lesser GNU General Public License as published by |
  9. | the Free Software Foundation, either version 3 of the License, or |
  10. | (at your option) any later version. |
  11. | |
  12. | It means that you can distribute your commercial software linked with |
  13. | SNAP7 without the requirement to distribute the source code of your |
  14. | application and without the requirement that your application be itself |
  15. | distributed under LGPL. |
  16. | |
  17. | SNAP7 is distributed in the hope that it will be useful, |
  18. | but WITHOUT ANY WARRANTY; without even the implied warranty of |
  19. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
  20. | Lesser GNU General Public License for more details. |
  21. | |
  22. | You should have received a copy of the GNU General Public License and a |
  23. | copy of Lesser GNU General Public License along with Snap7. |
  24. | If not, see http://www.gnu.org/licenses/ |
  25. |==============================================================================|
  26. | |
  27. | Posix Threads support (Linux, FreeBSD) |
  28. | |
  29. |=============================================================================*/
  30. #ifndef unix_threads_h
  31. #define unix_threads_h
  32. //---------------------------------------------------------------------------
  33. #include "snap_platform.h"
  34. #include "snap_sysutils.h"
  35. #include <semaphore.h>
  36. #include <pthread.h>
  37. //---------------------------------------------------------------------------
  38. class TSnapCriticalSection
  39. {
  40. private:
  41. pthread_mutex_t mx;
  42. // int result;
  43. public:
  44. TSnapCriticalSection()
  45. {
  46. /*
  47. This would be the best code, but very often it causes a segmentation fault in many
  48. unix systems (the problem seems to be pthread_mutexattr_destroy()).
  49. So, to avoid problems in future kernel/libc release, we use the "safe" default.
  50. pthread_mutexattr_t mxAttr;
  51. pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE);
  52. pthread_mutex_init(&mx, &mxAttr);
  53. pthread_mutexattr_destroy(&mxAttr);
  54. */
  55. pthread_mutex_init(&mx, 0);
  56. };
  57. ~TSnapCriticalSection()
  58. {
  59. pthread_mutex_destroy(&mx);
  60. };
  61. void Enter()
  62. {
  63. pthread_mutex_lock(&mx);
  64. };
  65. void Leave()
  66. {
  67. pthread_mutex_unlock(&mx);
  68. };
  69. bool TryEnter()
  70. {
  71. return pthread_mutex_trylock(&mx) == 0;
  72. };
  73. };
  74. typedef TSnapCriticalSection *PSnapCriticalSection;
  75. //---------------------------------------------------------------------------
  76. const longword WAIT_OBJECT_0 = 0x00000000L;
  77. const longword WAIT_ABANDONED = 0x00000080L;
  78. const longword WAIT_TIMEOUT = 0x00000102L;
  79. const longword WAIT_FAILED = 0xFFFFFFFFL;
  80. class TSnapEvent
  81. {
  82. private:
  83. pthread_cond_t CVariable;
  84. pthread_mutex_t Mutex;
  85. bool AutoReset;
  86. bool State;
  87. public:
  88. TSnapEvent(bool ManualReset)
  89. {
  90. AutoReset = !ManualReset;
  91. if (pthread_cond_init(&CVariable, 0) == 0)
  92. pthread_mutex_init(&Mutex, 0);
  93. State = false;
  94. }
  95. ~TSnapEvent()
  96. {
  97. pthread_cond_destroy(&CVariable);
  98. pthread_mutex_destroy(&Mutex);
  99. };
  100. void Set()
  101. {
  102. pthread_mutex_lock(&Mutex);
  103. State = true;
  104. if (AutoReset)
  105. pthread_cond_signal(&CVariable);
  106. else
  107. pthread_cond_broadcast(&CVariable);
  108. pthread_mutex_unlock(&Mutex);
  109. };
  110. void Reset()
  111. {
  112. pthread_mutex_lock(&Mutex);
  113. State = false;
  114. pthread_mutex_unlock(&Mutex);
  115. }
  116. longword WaitForever()
  117. {
  118. pthread_mutex_lock(&Mutex);
  119. while (!State) // <-- to avoid spurious wakeups
  120. pthread_cond_wait(&CVariable, &Mutex);
  121. if (AutoReset)
  122. State = false;
  123. pthread_mutex_unlock(&Mutex);
  124. return WAIT_OBJECT_0;
  125. };
  126. longword WaitFor(int64_t Timeout)
  127. {
  128. longword Result = WAIT_OBJECT_0;
  129. if (Timeout == 0)
  130. Timeout = 1; // 0 is not allowed
  131. if (Timeout > 0)
  132. {
  133. pthread_mutex_lock(&Mutex);
  134. if (!State)
  135. {
  136. timespec ts;
  137. timeval tv;
  138. gettimeofday(&tv, NULL);
  139. uint64_t nsecs = ((uint64_t) tv.tv_sec) * 1000000000 +
  140. Timeout * 1000000 +
  141. ((uint64_t) tv.tv_usec) * 1000;
  142. ts.tv_sec = nsecs / 1000000000;
  143. ts.tv_nsec = (nsecs - ((uint64_t) ts.tv_sec) * 1000000000);
  144. do {
  145. Result = pthread_cond_timedwait(&CVariable, &Mutex, &ts);
  146. if (Result == ETIMEDOUT)
  147. Result = WAIT_TIMEOUT;
  148. } while (Result == 0 && !State);
  149. }
  150. else
  151. if (AutoReset) // take the ownership
  152. State = false;
  153. pthread_mutex_unlock(&Mutex);
  154. return Result;
  155. }
  156. else // Timeout<0
  157. return WaitForever();
  158. };
  159. };
  160. typedef TSnapEvent *PSnapEvent;
  161. //---------------------------------------------------------------------------
  162. class TSnapThread
  163. {
  164. private:
  165. pthread_t th;
  166. bool FCreateSuspended;
  167. void ThreadCreate();
  168. void ThreadJoin()
  169. {
  170. pthread_join(th, 0);
  171. };
  172. void ThreadKill()
  173. {
  174. pthread_cancel(th);
  175. };
  176. longword ThreadWait(uint64_t Timeout)
  177. {
  178. longword Elapsed = SysGetTick();
  179. while (!Closed && !(DeltaTime(Elapsed) > Timeout))
  180. SysSleep(100);
  181. if (Closed)
  182. return WAIT_OBJECT_0;
  183. else
  184. return WAIT_TIMEOUT;
  185. };
  186. protected:
  187. bool Started;
  188. public:
  189. bool Terminated;
  190. bool Closed;
  191. bool FreeOnTerminate;
  192. TSnapThread();
  193. virtual ~TSnapThread();
  194. virtual void Execute()
  195. {
  196. };
  197. void Start();
  198. void Terminate();
  199. void Kill();
  200. void Join();
  201. longword WaitFor(uint64_t Timeout);
  202. };
  203. typedef TSnapThread *PSnapThread;
  204. //---------------------------------------------------------------------------
  205. #endif // unix_threads_h