Thread.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2019 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Ian Craggs - initial implementation
  15. * Ian Craggs, Allan Stockdill-Mander - async client updates
  16. * Ian Craggs - bug #415042 - start Linux thread as disconnected
  17. * Ian Craggs - fix for bug #420851
  18. * Ian Craggs - change MacOS semaphore implementation
  19. * Ian Craggs - fix for clock #284
  20. *******************************************************************************/
  21. /**
  22. * @file
  23. * \brief Threading related functions
  24. *
  25. * Used to create platform independent threading functions
  26. */
  27. #include "Thread.h"
  28. #if defined(THREAD_UNIT_TESTS)
  29. #define NOSTACKTRACE
  30. #endif
  31. #include "Log.h"
  32. #include "StackTrace.h"
  33. #undef malloc
  34. #undef realloc
  35. #undef free
  36. #if !defined(WIN32) && !defined(WIN64)
  37. #include <errno.h>
  38. #include <unistd.h>
  39. #include <sys/time.h>
  40. #include <fcntl.h>
  41. #include <stdio.h>
  42. #include <sys/stat.h>
  43. #include <limits.h>
  44. #endif
  45. #include <stdlib.h>
  46. #include "OsWrapper.h"
  47. /**
  48. * Start a new thread
  49. * @param fn the function to run, must be of the correct signature
  50. * @param parameter pointer to the function parameter, can be NULL
  51. * @return the new thread
  52. */
  53. thread_type Thread_start(thread_fn fn, void* parameter)
  54. {
  55. #if defined(WIN32) || defined(WIN64)
  56. thread_type thread = NULL;
  57. #else
  58. thread_type thread = 0;
  59. pthread_attr_t attr;
  60. #endif
  61. FUNC_ENTRY;
  62. #if defined(WIN32) || defined(WIN64)
  63. thread = CreateThread(NULL, 0, fn, parameter, 0, NULL);
  64. #else
  65. pthread_attr_init(&attr);
  66. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  67. if (pthread_create(&thread, &attr, fn, parameter) != 0)
  68. thread = 0;
  69. pthread_attr_destroy(&attr);
  70. #endif
  71. FUNC_EXIT;
  72. return thread;
  73. }
  74. /**
  75. * Create a new mutex
  76. * @return the new mutex
  77. */
  78. mutex_type Thread_create_mutex(void)
  79. {
  80. mutex_type mutex = NULL;
  81. int rc = 0;
  82. FUNC_ENTRY;
  83. #if defined(WIN32) || defined(WIN64)
  84. mutex = CreateMutex(NULL, 0, NULL);
  85. if (mutex == NULL)
  86. rc = GetLastError();
  87. #else
  88. mutex = malloc(sizeof(pthread_mutex_t));
  89. rc = pthread_mutex_init(mutex, NULL);
  90. #endif
  91. FUNC_EXIT_RC(rc);
  92. return mutex;
  93. }
  94. /**
  95. * Lock a mutex which has alrea
  96. * @return completion code, 0 is success
  97. */
  98. int Thread_lock_mutex(mutex_type mutex)
  99. {
  100. int rc = -1;
  101. /* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
  102. #if defined(WIN32) || defined(WIN64)
  103. /* WaitForSingleObject returns WAIT_OBJECT_0 (0), on success */
  104. rc = WaitForSingleObject(mutex, INFINITE);
  105. #else
  106. rc = pthread_mutex_lock(mutex);
  107. #endif
  108. return rc;
  109. }
  110. /**
  111. * Unlock a mutex which has already been locked
  112. * @param mutex the mutex
  113. * @return completion code, 0 is success
  114. */
  115. int Thread_unlock_mutex(mutex_type mutex)
  116. {
  117. int rc = -1;
  118. /* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
  119. #if defined(WIN32) || defined(WIN64)
  120. /* if ReleaseMutex fails, the return value is 0 */
  121. if (ReleaseMutex(mutex) == 0)
  122. rc = GetLastError();
  123. else
  124. rc = 0;
  125. #else
  126. rc = pthread_mutex_unlock(mutex);
  127. #endif
  128. return rc;
  129. }
  130. /**
  131. * Destroy a mutex which has already been created
  132. * @param mutex the mutex
  133. */
  134. void Thread_destroy_mutex(mutex_type mutex)
  135. {
  136. int rc = 0;
  137. FUNC_ENTRY;
  138. #if defined(WIN32) || defined(WIN64)
  139. rc = CloseHandle(mutex);
  140. #else
  141. rc = pthread_mutex_destroy(mutex);
  142. free(mutex);
  143. #endif
  144. FUNC_EXIT_RC(rc);
  145. }
  146. /**
  147. * Get the thread id of the thread from which this function is called
  148. * @return thread id, type varying according to OS
  149. */
  150. thread_id_type Thread_getid(void)
  151. {
  152. #if defined(WIN32) || defined(WIN64)
  153. return GetCurrentThreadId();
  154. #else
  155. return pthread_self();
  156. #endif
  157. }
  158. /**
  159. * Create a new semaphore
  160. * @return the new condition variable
  161. */
  162. sem_type Thread_create_sem(void)
  163. {
  164. sem_type sem = NULL;
  165. int rc = 0;
  166. FUNC_ENTRY;
  167. #if defined(WIN32) || defined(WIN64)
  168. sem = CreateEvent(
  169. NULL, /* default security attributes */
  170. FALSE, /* manual-reset event? */
  171. FALSE, /* initial state is nonsignaled */
  172. NULL /* object name */
  173. );
  174. #if 0
  175. sem = CreateSemaphore(
  176. NULL, /* default security attributes */
  177. 0, /* initial count - non signaled */
  178. 1, /* maximum count */
  179. NULL /* unnamed semaphore */
  180. );
  181. #endif
  182. #elif defined(OSX)
  183. sem = dispatch_semaphore_create(0L);
  184. rc = (sem == NULL) ? -1 : 0;
  185. #else
  186. sem = malloc(sizeof(sem_t));
  187. rc = sem_init(sem, 0, 0);
  188. #endif
  189. FUNC_EXIT_RC(rc);
  190. return sem;
  191. }
  192. /**
  193. * Wait for a semaphore to be posted, or timeout.
  194. * @param sem the semaphore
  195. * @param timeout the maximum time to wait, in milliseconds
  196. * @return completion code
  197. */
  198. int Thread_wait_sem(sem_type sem, int timeout)
  199. {
  200. /* sem_timedwait is the obvious call to use, but seemed not to work on the Viper,
  201. * so I've used trywait in a loop instead. Ian Craggs 23/7/2010
  202. */
  203. int rc = -1;
  204. #if !defined(WIN32) && !defined(WIN64) && !defined(OSX)
  205. #define USE_TRYWAIT
  206. #if defined(USE_TRYWAIT)
  207. int i = 0;
  208. useconds_t interval = 10000; /* 10000 microseconds: 10 milliseconds */
  209. int count = (1000 * timeout) / interval; /* how many intervals in timeout period */
  210. #else
  211. struct timespec ts;
  212. #endif
  213. #endif
  214. FUNC_ENTRY;
  215. #if defined(WIN32) || defined(WIN64)
  216. /* returns 0 (WAIT_OBJECT_0) on success, non-zero (WAIT_TIMEOUT) if timeout occurred */
  217. rc = WaitForSingleObject(sem, timeout < 0 ? 0 : timeout);
  218. if (rc == WAIT_TIMEOUT)
  219. rc = ETIMEDOUT;
  220. #elif defined(OSX)
  221. /* returns 0 on success, non-zero if timeout occurred */
  222. rc = (int)dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeout*1000000L));
  223. if (rc != 0)
  224. rc = ETIMEDOUT;
  225. #elif defined(USE_TRYWAIT)
  226. while (++i < count && (rc = sem_trywait(sem)) != 0)
  227. {
  228. if (rc == -1 && ((rc = errno) != EAGAIN))
  229. {
  230. rc = 0;
  231. break;
  232. }
  233. usleep(interval); /* microseconds - .1 of a second */
  234. }
  235. #else
  236. /* We have to use CLOCK_REALTIME rather than MONOTONIC for sem_timedwait interval.
  237. * Does this make it susceptible to system clock changes?
  238. * The intervals are small enough, and repeated, that I think it's not an issue.
  239. */
  240. if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
  241. {
  242. ts.tv_sec += timeout;
  243. rc = sem_timedwait(sem, &ts);
  244. }
  245. #endif
  246. FUNC_EXIT_RC(rc);
  247. return rc;
  248. }
  249. /**
  250. * Check to see if a semaphore has been posted, without waiting
  251. * The semaphore will be unchanged, if the return value is false.
  252. * The semaphore will have been decremented, if the return value is true.
  253. * @param sem the semaphore
  254. * @return 0 (false) or 1 (true)
  255. */
  256. int Thread_check_sem(sem_type sem)
  257. {
  258. #if defined(WIN32) || defined(WIN64)
  259. /* if the return value is not 0, the semaphore will not have been decremented */
  260. return WaitForSingleObject(sem, 0) == WAIT_OBJECT_0;
  261. #elif defined(OSX)
  262. /* if the return value is not 0, the semaphore will not have been decremented */
  263. return dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0;
  264. #else
  265. /* If the call was unsuccessful, the state of the semaphore shall be unchanged,
  266. * and the function shall return a value of -1 */
  267. return sem_trywait(sem) == 0;
  268. #endif
  269. }
  270. /**
  271. * Post a semaphore
  272. * @param sem the semaphore
  273. * @return 0 on success
  274. */
  275. int Thread_post_sem(sem_type sem)
  276. {
  277. int rc = 0;
  278. FUNC_ENTRY;
  279. #if defined(WIN32) || defined(WIN64)
  280. if (SetEvent(sem) == 0)
  281. rc = GetLastError();
  282. #elif defined(OSX)
  283. rc = (int)dispatch_semaphore_signal(sem);
  284. #else
  285. int val;
  286. int rc1 = sem_getvalue(sem, &val);
  287. if (val == 0 && sem_post(sem) == -1)
  288. rc = errno;
  289. #endif
  290. FUNC_EXIT_RC(rc);
  291. return rc;
  292. }
  293. /**
  294. * Destroy a semaphore which has already been created
  295. * @param sem the semaphore
  296. */
  297. int Thread_destroy_sem(sem_type sem)
  298. {
  299. int rc = 0;
  300. FUNC_ENTRY;
  301. #if defined(WIN32) || defined(WIN64)
  302. rc = CloseHandle(sem);
  303. #elif defined(OSX)
  304. dispatch_release(sem);
  305. #else
  306. rc = sem_destroy(sem);
  307. free(sem);
  308. #endif
  309. FUNC_EXIT_RC(rc);
  310. return rc;
  311. }
  312. #if !defined(WIN32) && !defined(WIN64)
  313. /**
  314. * Create a new condition variable
  315. * @return the condition variable struct
  316. */
  317. cond_type Thread_create_cond(void)
  318. {
  319. cond_type condvar = NULL;
  320. pthread_condattr_t attr;
  321. int rc = 0;
  322. FUNC_ENTRY;
  323. pthread_condattr_init(&attr);
  324. #if 0
  325. /* in theory, a monotonic clock should be able to be used. However on at least
  326. * one system reported, even though setclock() reported success, it didn't work.
  327. */
  328. if ((rc = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) == 0)
  329. use_clock_monotonic = 1;
  330. else
  331. Log(LOG_ERROR, -1, "Error %d calling pthread_condattr_setclock(CLOCK_MONOTONIC)", rc);
  332. #endif
  333. condvar = malloc(sizeof(cond_type_struct));
  334. rc = pthread_cond_init(&condvar->cond, &attr);
  335. rc = pthread_mutex_init(&condvar->mutex, NULL);
  336. FUNC_EXIT_RC(rc);
  337. return condvar;
  338. }
  339. /**
  340. * Signal a condition variable
  341. * @return completion code
  342. */
  343. int Thread_signal_cond(cond_type condvar)
  344. {
  345. int rc = 0;
  346. FUNC_ENTRY;
  347. pthread_mutex_lock(&condvar->mutex);
  348. rc = pthread_cond_signal(&condvar->cond);
  349. pthread_mutex_unlock(&condvar->mutex);
  350. FUNC_EXIT_RC(rc);
  351. return rc;
  352. }
  353. /**
  354. * Wait with a timeout (seconds) for condition variable
  355. * @return 0 for success, ETIMEDOUT otherwise
  356. */
  357. int Thread_wait_cond(cond_type condvar, int timeout)
  358. {
  359. int rc = 0;
  360. struct timespec cond_timeout;
  361. FUNC_ENTRY;
  362. clock_gettime(CLOCK_REALTIME, &cond_timeout);
  363. cond_timeout.tv_sec += timeout;
  364. pthread_mutex_lock(&condvar->mutex);
  365. rc = pthread_cond_timedwait(&condvar->cond, &condvar->mutex, &cond_timeout);
  366. pthread_mutex_unlock(&condvar->mutex);
  367. FUNC_EXIT_RC(rc);
  368. return rc;
  369. }
  370. /**
  371. * Destroy a condition variable
  372. * @return completion code
  373. */
  374. int Thread_destroy_cond(cond_type condvar)
  375. {
  376. int rc = 0;
  377. rc = pthread_mutex_destroy(&condvar->mutex);
  378. rc = pthread_cond_destroy(&condvar->cond);
  379. free(condvar);
  380. return rc;
  381. }
  382. #endif
  383. #if defined(THREAD_UNIT_TESTS)
  384. #if defined(WIN32) || defined(_WINDOWS)
  385. #define mqsleep(A) Sleep(1000*A)
  386. #define START_TIME_TYPE DWORD
  387. static DWORD start_time = 0;
  388. START_TIME_TYPE start_clock(void)
  389. {
  390. return GetTickCount();
  391. }
  392. #elif defined(AIX)
  393. #define mqsleep sleep
  394. #define START_TIME_TYPE struct timespec
  395. START_TIME_TYPE start_clock(void)
  396. {
  397. static struct timespec start;
  398. clock_gettime(CLOCK_REALTIME, &start);
  399. return start;
  400. }
  401. #else
  402. #define mqsleep sleep
  403. #define START_TIME_TYPE struct timeval
  404. /* TODO - unused - remove? static struct timeval start_time; */
  405. START_TIME_TYPE start_clock(void)
  406. {
  407. struct timeval start_time;
  408. gettimeofday(&start_time, NULL);
  409. return start_time;
  410. }
  411. #endif
  412. #if defined(WIN32)
  413. long elapsed(START_TIME_TYPE start_time)
  414. {
  415. return GetTickCount() - start_time;
  416. }
  417. #elif defined(AIX)
  418. #define assert(a)
  419. long elapsed(struct timespec start)
  420. {
  421. struct timespec now, res;
  422. clock_gettime(CLOCK_REALTIME, &now);
  423. ntimersub(now, start, res);
  424. return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
  425. }
  426. #else
  427. long elapsed(START_TIME_TYPE start_time)
  428. {
  429. struct timeval now, res;
  430. gettimeofday(&now, NULL);
  431. timersub(&now, &start_time, &res);
  432. return (res.tv_sec)*1000 + (res.tv_usec)/1000;
  433. }
  434. #endif
  435. int tests = 0, failures = 0;
  436. void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
  437. {
  438. ++tests;
  439. if (!value)
  440. {
  441. va_list args;
  442. ++failures;
  443. printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
  444. va_start(args, format);
  445. vprintf(format, args);
  446. va_end(args);
  447. //cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
  448. // description, filename, lineno);
  449. }
  450. else
  451. printf("Assertion succeeded, file %s, line %d, description: %s\n", filename, lineno, description);
  452. }
  453. #define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
  454. #define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
  455. #include <stdio.h>
  456. thread_return_type cond_secondary(void* n)
  457. {
  458. int rc = 0;
  459. cond_type cond = n;
  460. printf("This should return immediately as it was posted already\n");
  461. rc = Thread_wait_cond(cond, 99999);
  462. assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
  463. printf("This should hang around a few seconds\n");
  464. rc = Thread_wait_cond(cond, 99999);
  465. assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
  466. printf("Secondary cond thread ending\n");
  467. return 0;
  468. }
  469. int cond_test()
  470. {
  471. int rc = 0;
  472. cond_type cond = Thread_create_cond();
  473. thread_type thread;
  474. printf("Post secondary so it should return immediately\n");
  475. rc = Thread_signal_cond(cond);
  476. assert("rc 0 from signal cond", rc == 0, "rc was %d", rc);
  477. printf("Starting secondary thread\n");
  478. thread = Thread_start(cond_secondary, (void*)cond);
  479. sleep(3);
  480. printf("post secondary\n");
  481. rc = Thread_signal_cond(cond);
  482. assert("rc 1 from signal cond", rc == 1, "rc was %d", rc);
  483. sleep(3);
  484. printf("Main thread ending\n");
  485. return failures;
  486. }
  487. thread_return_type sem_secondary(void* n)
  488. {
  489. int rc = 0;
  490. sem_type sem = n;
  491. printf("Secondary semaphore pointer %p\n", sem);
  492. rc = Thread_check_sem(sem);
  493. assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
  494. printf("Secondary thread about to wait\n");
  495. rc = Thread_wait_sem(sem, 99999);
  496. printf("Secondary thread returned from wait %d\n", rc);
  497. printf("Secondary thread about to wait\n");
  498. rc = Thread_wait_sem(sem, 99999);
  499. printf("Secondary thread returned from wait %d\n", rc);
  500. printf("Secondary check sem %d\n", Thread_check_sem(sem));
  501. printf("Secondary thread ending\n");
  502. return 0;
  503. }
  504. int sem_test()
  505. {
  506. int rc = 0;
  507. sem_type sem = Thread_create_sem();
  508. thread_type thread;
  509. printf("Primary semaphore pointer %p\n", sem);
  510. rc = Thread_check_sem(sem);
  511. assert("rc 0 from check_sem", rc == 0, "rc was %d\n", rc);
  512. printf("post secondary so then check should be 1\n");
  513. rc = Thread_post_sem(sem);
  514. assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc);
  515. rc = Thread_check_sem(sem);
  516. assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
  517. printf("Starting secondary thread\n");
  518. thread = Thread_start(sem_secondary, (void*)sem);
  519. sleep(3);
  520. rc = Thread_check_sem(sem);
  521. assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
  522. printf("post secondary\n");
  523. rc = Thread_post_sem(sem);
  524. assert("rc 1 from post_sem", rc == 1, "rc was %d", rc);
  525. sleep(3);
  526. printf("Main thread ending\n");
  527. return failures;
  528. }
  529. int main(int argc, char *argv[])
  530. {
  531. sem_test();
  532. //cond_test();
  533. }
  534. #endif