Thread.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, 2020 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 v2.0
6  * and Eclipse Distribution License v1.0 which accompany this distribution.
7  *
8  * The Eclipse Public License is available at
9  * https://www.eclipse.org/legal/epl-2.0/
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 
30 #include "Thread.h"
31 #if defined(THREAD_UNIT_TESTS)
32 #define NOSTACKTRACE
33 #endif
34 #include "Log.h"
35 #include "StackTrace.h"
36 
37 #undef malloc
38 #undef realloc
39 #undef free
40 
41 #if !defined(_WIN32) && !defined(_WIN64)
42 #include <errno.h>
43 #include <unistd.h>
44 #include <sys/time.h>
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <sys/stat.h>
48 #include <limits.h>
49 #endif
50 #include <stdlib.h>
51 
52 #include "OsWrapper.h"
53 
60 thread_type Thread_start(thread_fn fn, void* parameter)
61 {
62 #if defined(_WIN32) || defined(_WIN64)
63  thread_type thread = NULL;
64 #else
65  thread_type thread = 0;
66  pthread_attr_t attr;
67 #endif
68 
69  FUNC_ENTRY;
70 #if defined(_WIN32) || defined(_WIN64)
71  thread = CreateThread(NULL, 0, fn, parameter, 0, NULL);
72 #else
73  pthread_attr_init(&attr);
74  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
75  if (pthread_create(&thread, &attr, fn, parameter) != 0)
76  thread = 0;
77  pthread_attr_destroy(&attr);
78 #endif
79  FUNC_EXIT;
80  return thread;
81 }
82 
83 
89 {
90  mutex_type mutex = NULL;
91 
92  FUNC_ENTRY;
93  *rc = -1;
94  #if defined(_WIN32) || defined(_WIN64)
95  mutex = CreateMutex(NULL, 0, NULL);
96  if (mutex == NULL)
97  *rc = GetLastError();
98  #else
99  mutex = malloc(sizeof(pthread_mutex_t));
100  if (mutex)
101  *rc = pthread_mutex_init(mutex, NULL);
102  #endif
103  FUNC_EXIT_RC(*rc);
104  return mutex;
105 }
106 
107 
113 {
114  int rc = -1;
115 
116  /* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
117  #if defined(_WIN32) || defined(_WIN64)
118  /* WaitForSingleObject returns WAIT_OBJECT_0 (0), on success */
119  rc = WaitForSingleObject(mutex, INFINITE);
120  #else
121  rc = pthread_mutex_lock(mutex);
122  #endif
123 
124  return rc;
125 }
126 
127 
134 {
135  int rc = -1;
136 
137  /* don't add entry/exit trace points as the stack log uses mutexes - recursion beckons */
138  #if defined(_WIN32) || defined(_WIN64)
139  /* if ReleaseMutex fails, the return value is 0 */
140  if (ReleaseMutex(mutex) == 0)
141  rc = GetLastError();
142  else
143  rc = 0;
144  #else
145  rc = pthread_mutex_unlock(mutex);
146  #endif
147 
148  return rc;
149 }
150 
151 
157 {
158  int rc = 0;
159 
160  FUNC_ENTRY;
161  #if defined(_WIN32) || defined(_WIN64)
162  rc = CloseHandle(mutex);
163  #else
164  rc = pthread_mutex_destroy(mutex);
165  free(mutex);
166  #endif
167  FUNC_EXIT_RC(rc);
168  return rc;
169 }
170 
171 
177 {
178  #if defined(_WIN32) || defined(_WIN64)
179  return GetCurrentThreadId();
180  #else
181  return pthread_self();
182  #endif
183 }
184 
185 
191 {
192  sem_type sem = NULL;
193 
194  FUNC_ENTRY;
195  *rc = -1;
196  #if defined(_WIN32) || defined(_WIN64)
197  sem = CreateEvent(
198  NULL, /* default security attributes */
199  FALSE, /* manual-reset event? */
200  FALSE, /* initial state is nonsignaled */
201  NULL /* object name */
202  );
203 #if 0
204  sem = CreateSemaphore(
205  NULL, /* default security attributes */
206  0, /* initial count - non signaled */
207  1, /* maximum count */
208  NULL /* unnamed semaphore */
209  );
210 #endif
211  #elif defined(OSX)
212  sem = dispatch_semaphore_create(0L);
213  *rc = (sem == NULL) ? -1 : 0;
214  #else
215  sem = malloc(sizeof(sem_t));
216  if (sem)
217  *rc = sem_init(sem, 0, 0);
218  #endif
219  FUNC_EXIT_RC(*rc);
220  return sem;
221 }
222 
223 
230 int Thread_wait_sem(sem_type sem, int timeout)
231 {
232 /* sem_timedwait is the obvious call to use, but seemed not to work on the Viper,
233  * so I've used trywait in a loop instead. Ian Craggs 23/7/2010
234  */
235  int rc = -1;
236 #if !defined(_WIN32) && !defined(_WIN64) && !defined(OSX)
237 #define USE_TRYWAIT
238 #if defined(USE_TRYWAIT)
239  int i = 0;
240  useconds_t interval = 10000; /* 10000 microseconds: 10 milliseconds */
241  int count = (1000 * timeout) / interval; /* how many intervals in timeout period */
242 #else
243  struct timespec ts;
244 #endif
245 #endif
246 
247  FUNC_ENTRY;
248  #if defined(_WIN32) || defined(_WIN64)
249  /* returns 0 (WAIT_OBJECT_0) on success, non-zero (WAIT_TIMEOUT) if timeout occurred */
250  rc = WaitForSingleObject(sem, timeout < 0 ? 0 : timeout);
251  if (rc == WAIT_TIMEOUT)
252  rc = ETIMEDOUT;
253  #elif defined(OSX)
254  /* returns 0 on success, non-zero if timeout occurred */
255  rc = (int)dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (int64_t)timeout*1000000L));
256  if (rc != 0)
257  rc = ETIMEDOUT;
258  #elif defined(USE_TRYWAIT)
259  while (++i < count && (rc = sem_trywait(sem)) != 0)
260  {
261  if (rc == -1 && ((rc = errno) != EAGAIN))
262  {
263  rc = 0;
264  break;
265  }
266  usleep(interval); /* microseconds - .1 of a second */
267  }
268  #else
269  /* We have to use CLOCK_REALTIME rather than MONOTONIC for sem_timedwait interval.
270  * Does this make it susceptible to system clock changes?
271  * The intervals are small enough, and repeated, that I think it's not an issue.
272  */
273  if (clock_gettime(CLOCK_REALTIME, &ts) != -1)
274  {
275  ts.tv_sec += timeout;
276  rc = sem_timedwait(sem, &ts);
277  }
278  #endif
279 
280  FUNC_EXIT_RC(rc);
281  return rc;
282 }
283 
284 
293 {
294 #if defined(_WIN32) || defined(_WIN64)
295  /* if the return value is not 0, the semaphore will not have been decremented */
296  return WaitForSingleObject(sem, 0) == WAIT_OBJECT_0;
297 #elif defined(OSX)
298  /* if the return value is not 0, the semaphore will not have been decremented */
299  return dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW) == 0;
300 #else
301  /* If the call was unsuccessful, the state of the semaphore shall be unchanged,
302  * and the function shall return a value of -1 */
303  return sem_trywait(sem) == 0;
304 #endif
305 }
306 
307 
314 {
315  int rc = 0;
316 
317  FUNC_ENTRY;
318  #if defined(_WIN32) || defined(_WIN64)
319  if (SetEvent(sem) == 0)
320  rc = GetLastError();
321  #elif defined(OSX)
322  rc = (int)dispatch_semaphore_signal(sem);
323  #else
324  int val;
325  int rc1 = sem_getvalue(sem, &val);
326  if (rc1 != 0)
327  rc = errno;
328  else if (val == 0 && sem_post(sem) == -1)
329  rc = errno;
330  #endif
331 
332  FUNC_EXIT_RC(rc);
333  return rc;
334 }
335 
336 
342 {
343  int rc = 0;
344 
345  FUNC_ENTRY;
346  #if defined(_WIN32) || defined(_WIN64)
347  rc = CloseHandle(sem);
348  #elif defined(OSX)
349  dispatch_release(sem);
350  #else
351  rc = sem_destroy(sem);
352  free(sem);
353  #endif
354  FUNC_EXIT_RC(rc);
355  return rc;
356 }
357 
358 
359 #if !defined(_WIN32) && !defined(_WIN64)
360 
366 {
367  cond_type condvar = NULL;
368  pthread_condattr_t attr;
369 
370  FUNC_ENTRY;
371  *rc = -1;
372  pthread_condattr_init(&attr);
373 
374 #if 0
375  /* in theory, a monotonic clock should be able to be used. However on at least
376  * one system reported, even though setclock() reported success, it didn't work.
377  */
378  if ((rc = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) == 0)
379  use_clock_monotonic = 1;
380  else
381  Log(LOG_ERROR, -1, "Error %d calling pthread_condattr_setclock(CLOCK_MONOTONIC)", rc);
382 #endif
383 
384  condvar = malloc(sizeof(cond_type_struct));
385  if (condvar)
386  {
387  *rc = pthread_cond_init(&condvar->cond, &attr);
388  *rc = pthread_mutex_init(&condvar->mutex, NULL);
389  }
390 
391  FUNC_EXIT_RC(*rc);
392  return condvar;
393 }
394 
400 {
401  int rc = 0;
402 
403  FUNC_ENTRY;
404  pthread_mutex_lock(&condvar->mutex);
405  rc = pthread_cond_signal(&condvar->cond);
406  pthread_mutex_unlock(&condvar->mutex);
407 
408  FUNC_EXIT_RC(rc);
409  return rc;
410 }
411 
416 int Thread_wait_cond(cond_type condvar, int timeout)
417 {
418  int rc = 0;
419  struct timespec cond_timeout;
420 
421  FUNC_ENTRY;
422 #if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 /* for older versions of MacOS */
423  struct timeval cur_time;
424  gettimeofday(&cur_time, NULL);
425  cond_timeout.tv_sec = cur_time.tv_sec + timeout;
426  cond_timeout.tv_nsec = cur_time.tv_usec * 1000;
427 #else
428  clock_gettime(CLOCK_REALTIME, &cond_timeout);
429 
430  cond_timeout.tv_sec += timeout;
431 #endif
432  pthread_mutex_lock(&condvar->mutex);
433  rc = pthread_cond_timedwait(&condvar->cond, &condvar->mutex, &cond_timeout);
434  pthread_mutex_unlock(&condvar->mutex);
435 
436  FUNC_EXIT_RC(rc);
437  return rc;
438 }
439 
445 {
446  int rc = 0;
447 
448  rc = pthread_mutex_destroy(&condvar->mutex);
449  rc = pthread_cond_destroy(&condvar->cond);
450  free(condvar);
451 
452  return rc;
453 }
454 #endif
455 
456 
457 #if defined(THREAD_UNIT_TESTS)
458 
459 #if defined(_WIN32) || defined(_WINDOWS)
460 #define mqsleep(A) Sleep(1000*A)
461 #define START_TIME_TYPE DWORD
462 static DWORD start_time = 0;
464 {
465  return GetTickCount();
466 }
467 #elif defined(AIX)
468 #define mqsleep sleep
469 #define START_TIME_TYPE struct timespec
471 {
472  static struct timespec start;
473  clock_gettime(CLOCK_REALTIME, &start);
474  return start;
475 }
476 #else
477 #define mqsleep sleep
478 #define START_TIME_TYPE struct timeval
479 /* TODO - unused - remove? static struct timeval start_time; */
481 {
482  struct timeval start_time;
483  gettimeofday(&start_time, NULL);
484  return start_time;
485 }
486 #endif
487 
488 
489 #if defined(_WIN32)
490 long elapsed(START_TIME_TYPE start_time)
491 {
492  return GetTickCount() - start_time;
493 }
494 #elif defined(AIX)
495 #define assert(a)
496 long elapsed(struct timespec start)
497 {
498  struct timespec now, res;
499 
500  clock_gettime(CLOCK_REALTIME, &now);
501  ntimersub(now, start, res);
502  return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
503 }
504 #else
505 long elapsed(START_TIME_TYPE start_time)
506 {
507  struct timeval now, res;
508 
509  gettimeofday(&now, NULL);
510  timersub(&now, &start_time, &res);
511  return (res.tv_sec)*1000 + (res.tv_usec)/1000;
512 }
513 #endif
514 
515 
516 int tests = 0, failures = 0;
517 
518 void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
519 {
520  ++tests;
521  if (!value)
522  {
523  va_list args;
524 
525  ++failures;
526  printf("Assertion failed, file %s, line %d, description: %s\n", filename, lineno, description);
527 
528  va_start(args, format);
529  vprintf(format, args);
530  va_end(args);
531 
532  //cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
533  // description, filename, lineno);
534  }
535  else
536  printf("Assertion succeeded, file %s, line %d, description: %s\n", filename, lineno, description);
537 }
538 
539 #define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
540 #define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
541 
542 #include <stdio.h>
543 
545 {
546  int rc = 0;
547  cond_type cond = n;
548 
549  printf("This should return immediately as it was posted already\n");
550  rc = Thread_wait_cond(cond, 99999);
551  assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
552 
553  printf("This should hang around a few seconds\n");
554  rc = Thread_wait_cond(cond, 99999);
555  assert("rc 1 from wait_cond", rc == 1, "rc was %d", rc);
556 
557  printf("Secondary cond thread ending\n");
558  return 0;
559 }
560 
561 
562 int cond_test()
563 {
564  int rc = 0;
567 
568  printf("Post secondary so it should return immediately\n");
569  rc = Thread_signal_cond(cond);
570  assert("rc 0 from signal cond", rc == 0, "rc was %d", rc);
571 
572  printf("Starting secondary thread\n");
573  thread = Thread_start(cond_secondary, (void*)cond);
574 
575  sleep(3);
576 
577  printf("post secondary\n");
578  rc = Thread_signal_cond(cond);
579  assert("rc 1 from signal cond", rc == 1, "rc was %d", rc);
580 
581  sleep(3);
582 
583  printf("Main thread ending\n");
584 
585  return failures;
586 }
587 
588 
590 {
591  int rc = 0;
592  sem_type sem = n;
593 
594  printf("Secondary semaphore pointer %p\n", sem);
595 
596  rc = Thread_check_sem(sem);
597  assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
598 
599  printf("Secondary thread about to wait\n");
600  rc = Thread_wait_sem(sem, 99999);
601  printf("Secondary thread returned from wait %d\n", rc);
602 
603  printf("Secondary thread about to wait\n");
604  rc = Thread_wait_sem(sem, 99999);
605  printf("Secondary thread returned from wait %d\n", rc);
606  printf("Secondary check sem %d\n", Thread_check_sem(sem));
607 
608  printf("Secondary thread ending\n");
609  return 0;
610 }
611 
612 
613 int sem_test()
614 {
615  int rc = 0;
616  sem_type sem = Thread_create_sem();
618 
619  printf("Primary semaphore pointer %p\n", sem);
620 
621  rc = Thread_check_sem(sem);
622  assert("rc 0 from check_sem", rc == 0, "rc was %d\n", rc);
623 
624  printf("post secondary so then check should be 1\n");
625  rc = Thread_post_sem(sem);
626  assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc);
627 
628  rc = Thread_check_sem(sem);
629  assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
630 
631  printf("Starting secondary thread\n");
632  thread = Thread_start(sem_secondary, (void*)sem);
633 
634  sleep(3);
635  rc = Thread_check_sem(sem);
636  assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
637 
638  printf("post secondary\n");
639  rc = Thread_post_sem(sem);
640  assert("rc 1 from post_sem", rc == 1, "rc was %d", rc);
641 
642  sleep(3);
643 
644  printf("Main thread ending\n");
645 
646  return failures;
647 }
648 
649 
650 int main(int argc, char *argv[])
651 {
652  sem_test();
653  //cond_test();
654 }
655 
656 #endif
int Thread_post_sem(sem_type sem)
Definition: Thread.c:313
int Thread_wait_cond(cond_type condvar, int timeout)
Definition: Thread.c:416
enum MQTTPropertyCodes value
FMT_INLINE std::basic_string< Char > format(const S &format_str, Args &&...args)
Definition: core.h:2081
sem_type Thread_create_sem(int *rc)
Definition: Thread.c:190
#define FUNC_EXIT
Definition: StackTrace.h:59
int Thread_lock_mutex(mutex_type mutex)
Definition: Thread.c:112
#define malloc(x)
Definition: Heap.h:41
int Thread_destroy_cond(cond_type condvar)
Definition: Thread.c:444
long elapsed(START_TIME_TYPE start_time)
Definition: test1.c:233
static int cond(LexState *ls)
Definition: lparser.c:1396
thread_return_type(* thread_fn)(void *)
Definition: Thread.h:45
mutex_type Thread_create_mutex(int *rc)
Definition: Thread.c:88
basic_thread< reference > thread
Definition: forward.hpp:720
#define free(x)
Definition: Heap.h:55
thread_return_type cond_secondary(void *n)
Definition: thread.c:328
constexpr size_t count()
Definition: core.h:960
static thread_return_type WINAPI sem_secondary(void *n)
Definition: thread.c:229
#define FUNC_EXIT_RC(x)
Definition: StackTrace.h:63
description
Definition: setup.py:19
int Thread_unlock_mutex(mutex_type mutex)
Definition: Thread.c:133
void Log(enum LOG_LEVELS log_level, int msgno, const char *format,...)
Definition: Log.c:417
#define START_TIME_TYPE
Definition: MQTTTime.h:36
#define mutex_type
Definition: mutex_type.h:22
Definition: Log.h:41
void myassert(char *filename, int lineno, char *description, int value, char *format,...)
#define FUNC_ENTRY
Definition: StackTrace.h:55
#define assert(a, b, c, d)
int Thread_wait_sem(sem_type sem, int timeout)
Definition: Thread.c:230
cond_type Thread_create_cond(int *rc)
Definition: Thread.c:365
pthread_cond_t cond
Definition: Thread.h:46
#define thread_type
Definition: Thread.h:42
pthread_mutex_t mutex
Definition: Thread.h:46
#define thread_return_type
Definition: Thread.h:44
thread_id_type Thread_getid(void)
Definition: Thread.c:176
int Thread_check_sem(sem_type sem)
Definition: Thread.c:292
sem_t * sem_type
Definition: Thread.h:53
int Thread_signal_cond(cond_type condvar)
Definition: Thread.c:399
thread_type Thread_start(thread_fn fn, void *parameter)
Definition: Thread.c:60
#define thread_id_type
Definition: Thread.h:43
int Thread_destroy_sem(sem_type sem)
Definition: Thread.c:341
int Thread_destroy_mutex(mutex_type mutex)
Definition: Thread.c:156
list tests
Definition: MQTTV311.py:899
enum MQTTReasonCodes rc
Definition: test10.c:1112
int main(int argc, char **argv)
Definition: lua.c:619
int failures
START_TIME_TYPE start_clock(void)


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 04:02:48