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 API and implementation and/or initial documentation
15  *******************************************************************************/
16 
17 
24 #include "Thread.h"
25 #include <string.h>
26 #include <stdlib.h>
27 
28 #if !defined(_WINDOWS)
29  #include <sys/time.h>
30  #include <sys/socket.h>
31  #include <unistd.h>
32  #include <errno.h>
33  #define WINAPI
34 #else
35  #include <windows.h>
36 #endif
37 
38 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
39 
40 void usage(void)
41 {
42  printf("help!!\n");
43  exit(EXIT_FAILURE);
44 }
45 
46 struct Options
47 {
48  int verbose;
49  int test_no;
50  int iterations;
51 } options =
52 {
53  0,
54  -1,
55  1,
56 };
57 
58 void getopts(int argc, char** argv)
59 {
60  int count = 1;
61 
62  while (count < argc)
63  {
64  if (strcmp(argv[count], "--test_no") == 0)
65  {
66  if (++count < argc)
67  options.test_no = atoi(argv[count]);
68  else
69  usage();
70  }
71  else if (strcmp(argv[count], "--iterations") == 0)
72  {
73  if (++count < argc)
74  options.iterations = atoi(argv[count]);
75  else
76  usage();
77  }
78  else if (strcmp(argv[count], "--verbose") == 0)
79  options.verbose = 1;
80  count++;
81  }
82 }
83 
84 #define LOGA_DEBUG 0
85 #define LOGA_INFO 1
86 #include <stdarg.h>
87 #include <time.h>
88 #include <sys/timeb.h>
89 void MyLog(int LOGA_level, char* format, ...)
90 {
91  static char msg_buf[256];
92  va_list args;
93 #if defined(_WIN32) || defined(_WINDOWS)
94  struct timeb ts;
95 #else
96  struct timeval ts;
97 #endif
98  struct tm *timeinfo;
99 
100  if (LOGA_level == LOGA_DEBUG && options.verbose == 0)
101  return;
102 
103 #if defined(_WIN32) || defined(_WINDOWS)
104  ftime(&ts);
105  timeinfo = localtime(&ts.time);
106 #else
107  gettimeofday(&ts, NULL);
108  timeinfo = localtime(&ts.tv_sec);
109 #endif
110  strftime(msg_buf, 80, "%Y%m%d %H%M%S", timeinfo);
111 
112 #if defined(_WIN32) || defined(_WINDOWS)
113  sprintf(&msg_buf[strlen(msg_buf)], ".%.3hu ", ts.millitm);
114 #else
115  sprintf(&msg_buf[strlen(msg_buf)], ".%.3lu ", ts.tv_usec / 1000);
116 #endif
117 
118  va_start(args, format);
119  vsnprintf(&msg_buf[strlen(msg_buf)], sizeof(msg_buf) - strlen(msg_buf), format, args);
120  va_end(args);
121 
122  printf("%s\n", msg_buf);
123  fflush(stdout);
124 }
125 
126 
127 #if defined(_WIN32) || defined(_WINDOWS)
128 #define mysleep(A) Sleep(1000*A)
129 #define START_TIME_TYPE DWORD
130 static DWORD start_time = 0;
132 {
133  return GetTickCount();
134 }
135 #elif defined(AIX)
136 #define mysleep sleep
137 #define START_TIME_TYPE struct timespec
139 {
140  static struct timespec start;
141  clock_gettime(CLOCK_REALTIME, &start);
142  return start;
143 }
144 #else
145 #define mysleep sleep
146 #define START_TIME_TYPE struct timeval
147 /* TODO - unused - remove? static struct timeval start_time; */
149 {
150  struct timeval start_time;
151  gettimeofday(&start_time, NULL);
152  return start_time;
153 }
154 #endif
155 
156 
157 #if defined(_WIN32)
158 long elapsed(START_TIME_TYPE start_time)
159 {
160  return GetTickCount() - start_time;
161 }
162 #elif defined(AIX)
163 #define assert(a)
164 long elapsed(struct timespec start)
165 {
166  struct timespec now, res;
167 
168  clock_gettime(CLOCK_REALTIME, &now);
169  ntimersub(now, start, res);
170  return (res.tv_sec)*1000L + (res.tv_nsec)/1000000L;
171 }
172 #else
173 long elapsed(START_TIME_TYPE start_time)
174 {
175  struct timeval now, res;
176 
177  gettimeofday(&now, NULL);
178  timersub(&now, &start_time, &res);
179  return (res.tv_sec)*1000 + (res.tv_usec)/1000;
180 }
181 #endif
182 
183 #define assert(a, b, c, d) myassert(__FILE__, __LINE__, a, b, c, d)
184 #define assert1(a, b, c, d, e) myassert(__FILE__, __LINE__, a, b, c, d, e)
185 
186 int tests = 0;
187 int failures = 0;
188 FILE* xml;
190 char output[3000];
192 
194 {
195  long duration = elapsed(global_start_time);
196 
197  fprintf(xml, " time=\"%ld.%.3ld\" >\n", duration / 1000, duration % 1000);
198  if (cur_output != output)
199  {
200  fprintf(xml, "%s", output);
201  cur_output = output;
202  }
203  fprintf(xml, "</testcase>\n");
204 }
205 
206 void myassert(char* filename, int lineno, char* description, int value, char* format, ...)
207 {
208  ++tests;
209  if (!value)
210  {
211  va_list args;
212 
213  ++failures;
214  printf("Assertion failed, file %s, line %d, description: %s, ", filename, lineno, description);
215 
216  va_start(args, format);
217  vprintf(format, args);
218  va_end(args);
219 
220  printf("\n");
221 
222  cur_output += sprintf(cur_output, "<failure type=\"%s\">file %s, line %d </failure>\n",
223  description, filename, lineno);
224  }
225  else
226  MyLog(LOGA_DEBUG, "Assertion succeeded, file %s, line %d, description: %s", filename, lineno, description);
227 }
228 
230 {
231  int rc = 0;
232  sem_type sem = n;
233  START_TIME_TYPE start;
234  long duration;
235 
236  MyLog(LOGA_DEBUG, "Secondary semaphore pointer %p", sem);
237 
238  rc = Thread_check_sem(sem);
239  assert("rc 0 from check_sem", rc == 0, "rc was %d", rc);
240 
241  MyLog(LOGA_DEBUG, "Secondary thread about to wait");
242  start = start_clock();
243  rc = Thread_wait_sem(sem, 99999);
244  duration = elapsed(start);
245  assert("rc 0 from lock mutex", rc == 0, "rc was %d", rc);
246  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
247  assert("duration is 2s", duration >= 2000L, "duration was %ld", duration);
248 
249  MyLog(LOGA_DEBUG, "Secondary thread ending");
250  return 0;
251 }
252 
253 
255 {
256  char* testname = "test_sem";
257  int rc = 0, i = 0;
258  START_TIME_TYPE start;
259  long duration;
260  sem_type sem = Thread_create_sem(&rc);
262 
263  MyLog(LOGA_INFO, "Starting semaphore test");
264  fprintf(xml, "<testcase classname=\"test\" name=\"%s\"", testname);
266 
267  MyLog(LOGA_DEBUG, "Primary semaphore pointer %p\n", sem);
268 
269  /* The semaphore should be created non-signaled */
270  rc = Thread_check_sem(sem);
271  assert("rc 0 from check_sem", rc == 0, "rc was %d\n", rc);
272 
273  MyLog(LOGA_DEBUG, "Post semaphore so then check should be 1\n");
274  rc = Thread_post_sem(sem);
275  assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc);
276 
277  /* should be 1, and then reset to 0 */
278  rc = Thread_check_sem(sem);
279  assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
280 
281  /* so now it'll be 0 */
282  rc = Thread_check_sem(sem);
283  assert("rc 0 from check_sem", rc == 0, "rc was %d", rc);
284 
285  /* multiple posts */
286  for (i = 0; i < 10; ++i)
287  {
288  rc = Thread_post_sem(sem);
289  assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc);
290  }
291 
292  for (i = 0; i < 10; ++i)
293  {
294  rc = Thread_check_sem(sem);
295  assert("rc 1 from check_sem", rc == 1, "rc was %d", rc);
296  }
297  rc = Thread_check_sem(sem);
298  assert("rc 0 from check_sem", rc == 0, "rc was %d", rc);
299 
300  MyLog(LOGA_DEBUG, "Check timeout");
301  start = start_clock();
302  rc = Thread_wait_sem(sem, 1500);
303  duration = elapsed(start);
304  assert("rc ETIMEDOUT from lock mutex", rc == ETIMEDOUT, "rc was %d", rc);
305  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
306  assert("duration is 2s", duration >= 1500L, "duration was %ld", duration);
307 
308  MyLog(LOGA_DEBUG, "Starting secondary thread");
309  thread = Thread_start(sem_secondary, (void*)sem);
310 
311  mysleep(2);
312  MyLog(LOGA_DEBUG, "post secondary");
313  rc = Thread_post_sem(sem);
314  assert("rc 1 from post_sem", rc == 1, "rc was %d", rc);
315 
316  mysleep(1);
317 
318  MyLog(LOGA_DEBUG, "Main thread ending");
319 
320  /*exit: */ MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.",
321  (failures == 0) ? "passed" : "failed", testname, tests, failures);
323 
324  return failures;
325 }
326 
327 #if !defined(_WIN32) && !defined(_WIN64)
329 {
330  int rc = 0;
331  cond_type cond = n;
332  START_TIME_TYPE start;
333  long duration;
334 
335  MyLog(LOGA_DEBUG, "This will time out");
336  start = start_clock();
337  rc = Thread_wait_cond(cond, 1);
338  duration = elapsed(start);
339  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
340  assert("duration is about 1s", duration >= 1000L && duration <= 1050L, "duration was %ld", duration);
341  assert("rc non 0 from wait_cond", rc == ETIMEDOUT, "rc was %d", rc);
342 
343  MyLog(LOGA_DEBUG, "This should hang around a few seconds");
344  start = start_clock();
345  rc = Thread_wait_cond(cond, 99999);
346  duration = elapsed(start);
347  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
348  assert("duration is around 1s", duration >= 990L && duration <= 1010L, "duration was %ld", duration);
349  assert("rc 9 from wait_cond", rc == 0, "rc was %d", rc);
350 
351  MyLog(LOGA_DEBUG, "Secondary cond thread ending");
352  return 0;
353 }
354 
355 
357 {
358  char* testname = "test_cond";
359  int rc = 0, i = 0;
360  START_TIME_TYPE start;
361  long duration;
364 
365  MyLog(LOGA_INFO, "Starting condition variable test");
366  fprintf(xml, "<testcase classname=\"cond\" name=\"%s\"", testname);
368 
369  /* The semaphore should be created non-signaled */
370  rc = Thread_wait_cond(cond, 0);
371  assert("rc 0 from wait_cond", rc == ETIMEDOUT, "rc was %d", rc);
372 
373  MyLog(LOGA_DEBUG, "Check timeout");
374  start = start_clock();
375  rc = Thread_wait_cond(cond, 2);
376  duration = elapsed(start);
377  assert("rc ETIMEDOUT from lock mutex", rc == ETIMEDOUT, "rc was %d", rc);
378  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
379  assert("duration is 2s", duration >= 2000L, "duration was %ld", duration);
380 
381  /* multiple posts */
382  for (i = 0; i < 10; ++i)
383  {
384  rc = Thread_signal_cond(cond);
385  assert("rc 0 from signal cond", rc == 0, "rc was %d\n", rc);
386  }
387 
388  /* the signals are not stored */
389  for (i = 0; i < 10; ++i)
390  {
391  rc = Thread_wait_cond(cond, 0);
392  assert("rc non-zero from wait_cond", rc == ETIMEDOUT, "rc was %d", rc);
393  }
394  rc = Thread_wait_cond(cond, 0);
395  assert("rc non-zero from wait_cond", rc == ETIMEDOUT, "rc was %d", rc);
396 
397  MyLog(LOGA_DEBUG, "Post secondary but it will time out");
398  rc = Thread_signal_cond(cond);
399  assert("rc 0 from signal cond", rc == 0, "rc was %d", rc);
400 
401  MyLog(LOGA_DEBUG, "Starting secondary thread");
402  thread = Thread_start(cond_secondary, (void*)cond);
403 
404  MyLog(LOGA_DEBUG, "wait for secondary thread to enter second wait");
405  mysleep(2);
406 
407  MyLog(LOGA_DEBUG, "post secondary");
408  rc = Thread_signal_cond(cond);
409  assert("rc 0 from signal cond", rc == 0, "rc was %d", rc);
410 
411  mysleep(1);
412 
413  MyLog(LOGA_DEBUG, "Main thread ending");
414 
415  exit: MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.",
416  (failures == 0) ? "passed" : "failed", testname, tests, failures);
418 
419  return failures;
420 }
421 #endif
422 
423 
425 {
426  int rc = 0;
427  mutex_type mutex = n;
428  START_TIME_TYPE start;
429  long duration;
430 
431  /* this should take 2s, as there is another lock held */
432  start = start_clock();
433  rc = Thread_lock_mutex(mutex);
434  duration = elapsed(start);
435  assert("rc 0 from lock mutex", rc == 0, "rc was %d", rc);
436  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
437  assert("duration is 2s", duration >= 1000L, "duration was %ld", duration);
438 
439  rc = Thread_unlock_mutex(mutex);
440  assert("rc 0 from unlock mutex", rc == 0, "rc was %d", rc);
441  MyLog(LOGA_DEBUG, "Secondary thread ending");
442  return 0;
443 }
444 
445 
447 {
448  char* testname = "test_mutex";
449  int rc = 0;
450  mutex_type mutex = Thread_create_mutex(&rc);
452  START_TIME_TYPE start;
453  long duration;
454 
455  MyLog(LOGA_INFO, "Starting mutex test");
456  fprintf(xml, "<testcase classname=\"test\" name=\"%s\"", testname);
458 
459  /* this should happen immediately, as there is no other lock held */
460  start = start_clock();
461  rc = Thread_lock_mutex(mutex);
462  duration = elapsed(start);
463  assert("rc 0 from lock mutex", rc == 0, "rc was %d", rc);
464  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
465  assert("duration is very low", duration < 5L, "duration was %ld", duration);
466 
467  MyLog(LOGA_DEBUG, "Starting secondary thread");
468  thread = Thread_start(mutex_secondary, (void*)mutex);
469 
470  mysleep(2);
471  rc = Thread_unlock_mutex(mutex); /* let background thread have it */
472  assert("rc 0 from unlock mutex", rc == 0, "rc was %d", rc);
473 
474  start = start_clock();
475  rc = Thread_lock_mutex(mutex); /* make sure background thread hasn't locked it */
476  duration = elapsed(start);
477  assert("rc 0 from lock mutex", rc == 0, "rc was %d", rc);
478  MyLog(LOGA_INFO, "Lock duration was %ld", duration);
479  assert("duration is very low", duration < 5L, "duration was %ld", duration);
480 
481  Thread_destroy_mutex(mutex);
482 
483  MyLog(LOGA_DEBUG, "Main thread ending");
484 
485  /*exit:*/ MyLog(LOGA_INFO, "%s: test %s. %d tests run, %d failures.",
486  (failures == 0) ? "passed" : "failed", testname, tests, failures);
488 
489  return failures;
490 }
491 
492 
493 
494 int main(int argc, char** argv)
495 {
496  int rc = -1;
497  int (*tests[])() = {NULL,
498  test_mutex,
499  test_sem,
500 #if !defined(_WIN32) && !defined(_WIN64)
501  test_cond
502 #endif
503  }; /* indexed starting from 1 */
504  int i;
505 
506  xml = fopen("TEST-thread.xml", "w");
507  fprintf(xml, "<testsuite name=\"thread\" tests=\"%d\">\n", (int)(ARRAY_SIZE(tests)) - 1);
508 
509  getopts(argc, argv);
510 
511  for (i = 0; i < options.iterations; ++i)
512  {
513  if (options.test_no == -1)
514  { /* run all the tests */
516  {
517  failures = rc = 0;
518  rc += tests[options.test_no](options); /* return number of failures. 0 = test succeeded */
519  }
520  }
521  else
522  {
524  MyLog(LOGA_INFO, "No test number %d", options.test_no);
525  else
526  {
527  rc = tests[options.test_no](options); /* run just the selected test */
528  }
529  }
530  }
531 
532  if (rc == 0)
533  MyLog(LOGA_INFO, "verdict pass");
534  else
535  MyLog(LOGA_INFO, "verdict fail");
536 
537  fprintf(xml, "</testsuite>\n");
538  fclose(xml);
539 
540  return rc;
541 }
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
FILE * xml
Definition: thread.c:188
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
int main(int argc, char **argv)
Definition: thread.c:494
int Thread_lock_mutex(mutex_type mutex)
Definition: Thread.c:112
size_t strftime(char *str, size_t count, const char *format, const std::tm *time)
Definition: chrono.h:375
long elapsed(START_TIME_TYPE start_time)
Definition: thread.c:173
#define WINAPI
Definition: thread.c:33
std::tm localtime(std::time_t time)
Definition: chrono.h:292
void write_test_result(void)
Definition: thread.c:193
static int cond(LexState *ls)
Definition: lparser.c:1396
mutex_type Thread_create_mutex(int *rc)
Definition: Thread.c:88
static char msg_buf[512]
Definition: Log.c:122
char * cur_output
Definition: thread.c:191
basic_thread< reference > thread
Definition: forward.hpp:720
static thread_return_type WINAPI mutex_secondary(void *n)
Definition: thread.c:424
struct Options options
thread_return_type cond_secondary(void *n)
Definition: thread.c:328
void MyLog(int LOGA_level, char *format,...)
Definition: thread.c:89
constexpr size_t count()
Definition: core.h:960
char output[3000]
Definition: thread.c:190
static thread_return_type WINAPI sem_secondary(void *n)
Definition: thread.c:229
description
Definition: setup.py:19
int Thread_unlock_mutex(mutex_type mutex)
Definition: Thread.c:133
#define LOGA_DEBUG
Definition: thread.c:84
#define ARRAY_SIZE(a)
Definition: thread.c:38
#define mutex_type
Definition: mutex_type.h:22
#define LOGA_INFO
Definition: thread.c:85
#define assert(a, b, c, d)
Definition: thread.c:183
START_TIME_TYPE start_clock(void)
Definition: thread.c:148
int tests
Definition: thread.c:186
int test_cond(struct Options options)
Definition: thread.c:356
int Thread_wait_sem(sem_type sem, int timeout)
Definition: Thread.c:230
void myassert(char *filename, int lineno, char *description, int value, char *format,...)
Definition: thread.c:206
cond_type Thread_create_cond(int *rc)
Definition: Thread.c:365
#define thread_type
Definition: Thread.h:42
#define thread_return_type
Definition: Thread.h:44
START_TIME_TYPE global_start_time
Definition: thread.c:189
int Thread_check_sem(sem_type sem)
Definition: Thread.c:292
int test_sem(struct Options options)
Definition: thread.c:254
sem_t * sem_type
Definition: Thread.h:53
int failures
Definition: thread.c:187
int Thread_signal_cond(cond_type condvar)
Definition: Thread.c:399
void getopts(int argc, char **argv)
Definition: thread.c:58
thread_type Thread_start(thread_fn fn, void *parameter)
Definition: Thread.c:60
int test_mutex(struct Options options)
Definition: thread.c:446
int Thread_destroy_mutex(mutex_type mutex)
Definition: Thread.c:156
#define mysleep
Definition: thread.c:145
enum MQTTReasonCodes rc
Definition: test10.c:1112
#define START_TIME_TYPE
Definition: thread.c:146
void usage(void)
Definition: thread.c:40
int test_no
Definition: test1.c:54


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