30 #include <rtems/test.h> 32 #include <sys/queue.h> 37 #include <stdatomic.h> 40 #include <rtems/score/io.h> 44 #include <rtems/linkersets.h> 47 #include "t-test-printf.h" 50 #define T_LINE_SIZE 128 53 pthread_spinlock_t lock;
55 unsigned int buf_mask;
58 void (*putchar)(int,
void *);
60 T_verbosity verbosity;
66 T_time case_begin_time;
67 atomic_uint planned_steps;
70 jmp_buf case_begin_context;
71 unsigned int fixture_steps;
72 unsigned int overall_cases;
73 unsigned int overall_steps;
74 unsigned int overall_failures;
75 T_time run_begin_time;
81 pthread_t runner_thread;
91 .flags = T_CHECK_FMT | T_CHECK_QUIET
105 cpu_self = _Per_CPU_Get();
107 if (ctx->runner_thread != NULL) {
109 _Per_CPU_Get_executing(cpu_self) == ctx->runner_thread;
111 is_runner = cpu_self == ctx->runner_cpu;
116 is_runner = ctx->runner_valid &&
117 pthread_equal(pthread_self(), ctx->runner_thread) != 0;
123 bool T_is_runner(
void)
125 return T_do_is_runner(&T_instance);
134 T_putchar_string(
int c,
void *arg)
159 T_snprintf(
char *s,
size_t n,
char const *fmt, ...)
169 len = _IO_Vprintf(T_putchar_string, &sctx, fmt, ap);
185 head = atomic_load_explicit(&ctx->buf_head, memory_order_acquire);
186 tail = atomic_load_explicit(&ctx->buf_tail, memory_order_relaxed);
188 while (head != tail) {
189 (*ctx->putchar)(ctx->buf[tail], ctx->putchar_arg);
190 tail = (tail + 1) & ctx->buf_mask;
193 atomic_store_explicit(&ctx->buf_tail, tail, memory_order_relaxed);
197 T_output_buffer_fill(
T_context *ctx,
const char *buf,
unsigned int len)
202 unsigned int capacity;
204 pthread_spin_lock(&ctx->lock);
205 head = atomic_load_explicit(&ctx->buf_head, memory_order_relaxed);
206 tail = atomic_load_explicit(&ctx->buf_tail, memory_order_relaxed);
207 mask = ctx->buf_mask;
208 capacity = (tail - head - 1) & mask;
210 if (len <= capacity) {
219 head = (head + 1) & mask;
224 atomic_store_explicit(&ctx->buf_head, head,
225 memory_order_release);
231 pthread_spin_unlock(&ctx->lock);
236 T_vprintf_direct(
char const *fmt, va_list ap)
241 T_output_buffer_drain(ctx);
242 return _IO_Vprintf(ctx->putchar, ctx->putchar_arg, fmt, ap);
246 T_vprintf_buffered(
char const *fmt, va_list ap)
248 char buf[T_LINE_SIZE];
255 len = (
unsigned int)_IO_Vprintf(T_putchar_string, &sctx, fmt, ap);
257 if (len >=
sizeof(buf)) {
258 len =
sizeof(buf) - 1;
261 return (
int)T_output_buffer_fill(&T_instance, buf, len);
265 T_vprintf(
char const *fmt, va_list ap)
270 len = T_vprintf_direct(fmt, ap);
272 len = T_vprintf_buffered(fmt, ap);
279 T_do_puts(
T_context *ctx,
const char *buf,
size_t len)
281 if (T_do_is_runner(ctx)) {
284 T_output_buffer_drain(ctx);
286 for (i = 0; i < len; ++i) {
287 (*ctx->putchar)(buf[i], ctx->putchar_arg);
290 len = T_output_buffer_fill(ctx, buf, len);
297 T_puts(
const char *buf,
size_t len)
299 return T_do_puts(&T_instance, buf, len);
305 #if defined(__rtems__) 306 return (
int)_SMP_Get_current_processor();
307 #elif defined(__linux__) 308 return sched_getcpu();
315 T_str_copy(
char *dst,
const char *src,
size_t n)
321 while (*src !=
'\0' && i < n) {
331 #if defined(__rtems__) 333 T_object_name_to_string(
char *dst,
Objects_Name name,
size_t n)
342 for (s = 24; s >= 0; s -= 8) {
345 c = (
unsigned char)(on >> s);
347 if (c >=
'!' && c <=
'~' && i < n) {
365 if (name != NULL && name[0] !=
'\0') {
366 return T_str_copy(dst, name, n);
369 return T_object_name_to_string(dst, th->
Object.
name, n);
372 return T_str_copy(dst,
"?", n);
377 T_scope(
T_context *ctx,
char *dst,
size_t n)
382 #if defined(__rtems__) 387 cpu_self = _Per_CPU_Get();
392 executing = _Per_CPU_Get_executing(cpu_self);
394 len = T_thread_name(dst, executing, n);
397 len = T_str_copy(dst,
"ISR", n);
400 #elif defined(__linux__) 401 static __thread
char name[128];
403 if (name[0] ==
'\0') {
404 pthread_getname_np(pthread_self(), name,
sizeof(name));
407 len = T_str_copy(dst, name, n);
409 len = T_str_copy(dst,
"?", n);
414 node = &ctx->case_fixture;
419 fixture = node->fixture;
421 if (fixture != NULL && fixture->scope != NULL) {
424 m = (*fixture->scope)(node->context, dst, n);
430 node = node->previous;
431 }
while (node != NULL);
444 cpu_self = _Per_CPU_Get();
445 ctx->runner_cpu = cpu_self;
448 ctx->runner_thread = _Per_CPU_Get_executing(cpu_self);
450 ctx->runner_thread = NULL;
455 ctx->runner_valid =
true;
456 ctx->runner_thread = pthread_self();
463 T_do_make_runner(&T_instance);
467 T_printf(
char const *fmt, ...)
473 len = T_vprintf(fmt, ap);
480 T_log(T_verbosity verbosity,
char const *fmt, ...)
486 if (ctx->verbosity >= verbosity) {
500 return atomic_fetch_add_explicit(&ctx->steps, 1, memory_order_relaxed);
506 return atomic_fetch_add_explicit(&ctx->failures, 1,
507 memory_order_relaxed);
510 T_NO_RETURN
static void 515 node = ctx->fixtures;
517 while (node != NULL) {
520 fixture = node->fixture;
522 if (fixture != NULL && fixture->stop != NULL) {
523 (*fixture->stop)(node->context);
529 longjmp(ctx->case_begin_context, 1);
535 T_do_stop(&T_instance);
538 void T_plan(
unsigned int planned_steps)
541 unsigned int expected;
546 success = atomic_compare_exchange_strong_explicit(&ctx->planned_steps,
547 &expected, planned_steps, memory_order_relaxed,
548 memory_order_relaxed);
549 T_check(&T_special, success,
"planned steps (%u) already set",
558 T_push_fixture(node, &T_empty_fixture);
559 T_plan(planned_steps);
574 tt.flags |= T_CHECK_STEP(expected);
575 T_check(&tt,
true,
"actual step is not equal to expected step (%u)",
585 tc->next = ctx->registered_cases;
586 ctx->registered_cases = tc;
590 T_set_verbosity(T_verbosity verbosity)
593 T_verbosity previous;
596 previous = ctx->verbosity;
597 ctx->verbosity = verbosity;
603 T_fixture_context(
void)
605 return T_instance.fixtures->context;
609 T_set_fixture_context(
void *context)
611 T_instance.fixtures->context = context;
619 tc = T_instance.current_case;
633 file = strrchr(t->file,
'/');
642 static const char T_planned_step_fmt[] =
"planned step (%u)";
645 T_check_putc(
int c,
void *arg)
669 node = &ctx->case_fixture;
672 node = node->previous;
675 _IO_Printf(T_check_putc, sctx,
"%u.",
682 if (step != UINT_MAX) {
683 _IO_Printf(T_check_putc, sctx,
"%u", step);
685 T_check_putc(
'*', sctx);
694 char line[T_LINE_SIZE];
701 if ((t->flags & T_CHECK_QUIET) == 0) {
702 step = T_fetch_add_step(ctx);
712 if ((t->flags & T_CHECK_STEP_FLAG) != 0 &&
713 step != T_CHECK_STEP_FROM_FLAGS(t->flags)) {
716 line_number = t->line;
717 fmt = T_planned_step_fmt;
721 if (ctx->verbosity >= T_NORMAL) {
723 line_number = t->line;
725 if ((t->flags & T_CHECK_FMT) != 0) {
726 fmt = va_arg(ap,
const char *);
729 }
else if ((t->flags & T_CHECK_QUIET) == 0 &&
730 ctx->verbosity >= T_VERBOSE) {
732 line_number = t->line;
735 if (line[0] !=
'\0') {
739 sctx.n =
sizeof(line) - 1;
741 T_check_putc(
':', &sctx);
742 T_check_print_steps(ctx, &sctx, step);
743 _IO_Printf(T_check_putc, &sctx,
":%i:", T_cpu());
744 chunk = T_scope(ctx, sctx.s, sctx.n);
747 T_check_putc(
':', &sctx);
748 chunk = T_str_copy(sctx.s, T_file(t), sctx.n);
751 T_check_putc(
':', &sctx);
753 if (line_number >= 0) {
754 _IO_Printf(T_check_putc, &sctx,
"%i", line_number);
756 T_check_putc(
'*', &sctx);
760 if (fmt == T_planned_step_fmt) {
761 T_check_putc(
':', &sctx);
762 _IO_Printf(T_check_putc, &sctx, fmt,
763 T_CHECK_STEP_FROM_FLAGS(t->flags));
765 T_check_putc(
':', &sctx);
766 _IO_Vprintf(T_check_putc, &sctx, fmt, ap);
770 T_check_putc(
'\n', &sctx);
771 line[
sizeof(line) - 1] =
'\n';
772 T_puts(&line[0],
sizeof(line) - sctx.n);
775 if (!ok && (t->flags & T_CHECK_STOP) != 0) {
783 T_do_log(
T_context *ctx, T_verbosity verbosity,
char const *fmt, ...)
785 if (ctx->verbosity >= verbosity) {
797 #if defined(__rtems__) 798 T_do_log(ctx, T_QUIET,
"S:Platform:RTEMS\n");
799 T_do_log(ctx, T_QUIET,
"S:Compiler:" __VERSION__
"\n");
803 T_do_log(ctx, T_QUIET,
"S:RTEMS_DEBUG:1\n");
805 T_do_log(ctx, T_QUIET,
"S:RTEMS_DEBUG:0\n");
807 #if RTEMS_MULTIPROCESSING 808 T_do_log(ctx, T_QUIET,
"S:RTEMS_MULTIPROCESSING:1\n");
810 T_do_log(ctx, T_QUIET,
"S:RTEMS_MULTIPROCESSING:0\n");
813 T_do_log(ctx, T_QUIET,
"S:RTEMS_POSIX_API:1\n");
815 T_do_log(ctx, T_QUIET,
"S:RTEMS_POSIX_API:0\n");
818 T_do_log(ctx, T_QUIET,
"S:RTEMS_PROFILING:1\n");
820 T_do_log(ctx, T_QUIET,
"S:RTEMS_PROFILING:0\n");
823 T_do_log(ctx, T_QUIET,
"S:RTEMS_SMP:1\n");
825 T_do_log(ctx, T_QUIET,
"S:RTEMS_SMP:0\n");
827 #elif defined(__linux__) 828 T_do_log(ctx, T_QUIET,
"S:Platform:Linux\n");
829 T_do_log(ctx, T_QUIET,
"S:Compiler:" __VERSION__
"\n");
831 T_do_log(ctx, T_QUIET,
"S:Platform:POSIX\n");
833 T_do_log(ctx, T_QUIET,
"S:Compiler:" __VERSION__
"\n");
843 dtor->destroy = destroy;
845 pthread_spin_lock(&ctx->lock);
846 LIST_INSERT_HEAD(&ctx->destructors, dtor, node);
847 pthread_spin_unlock(&ctx->lock);
856 pthread_spin_lock(&ctx->lock);
857 LIST_REMOVE(dtor, node);
858 pthread_spin_unlock(&ctx->lock);
867 while (!LIST_EMPTY(&ctx->destructors)) {
868 dtor = LIST_FIRST(&ctx->destructors);
869 LIST_REMOVE(dtor, node);
870 (*dtor->destroy)(dtor);
875 LIST_FOREACH_SAFE(dtor, &ctx->destructors, node, tmp) {
876 (*dtor->destroy)(dtor);
882 T_actions_forward(
const T_config *config, T_event event,
const char *name)
884 const T_action *actions;
888 actions = config->actions;
889 n = config->action_count;
891 for (i = 0; i < n; ++i) {
892 (*actions[i])(event, name);
897 T_actions_backward(
const T_config *config, T_event event,
900 const T_action *actions;
904 actions = config->actions;
905 n = config->action_count;
907 for (i = 0; i < n; ++i) {
908 (*actions[n - i - 1])(event, name);
913 T_do_run_initialize(
const T_config *config)
919 pthread_spin_init(&ctx->lock, PTHREAD_PROCESS_PRIVATE);
921 ctx->config = config;
922 ctx->buf = config->buf;
924 if (config->buf_size > 0 &&
925 (config->buf_size & (config->buf_size - 1)) == 0) {
926 ctx->buf_mask = config->buf_size - 1;
931 ctx->fixtures = &ctx->case_fixture;
932 atomic_store_explicit(&ctx->buf_head, 0, memory_order_relaxed);
934 ctx->putchar = config->putchar;
935 ctx->putchar_arg = config->putchar_arg;
936 ctx->verbosity = config->verbosity;
937 ctx->overall_cases = 0;
938 ctx->overall_steps = 0;
939 ctx->overall_failures = 0;
941 T_do_make_runner(ctx);
942 T_actions_forward(config, T_EVENT_RUN_INITIALIZE_EARLY, config->name);
943 T_do_log(ctx, T_QUIET,
"A:%s\n", config->name);
945 ctx->run_begin_time = (*config->now)();
946 T_actions_forward(config, T_EVENT_RUN_INITIALIZE_LATE, config->name);
957 config = ctx->config;
958 fixture = tc->fixture;
959 ctx->verbosity = config->verbosity;
960 ctx->current_case = tc;
961 ctx->fixtures = &ctx->case_fixture;
962 LIST_INIT(&ctx->destructors);
963 atomic_store_explicit(&ctx->planned_steps, UINT_MAX,
964 memory_order_relaxed);
965 atomic_store_explicit(&ctx->steps, 0, memory_order_relaxed);
966 atomic_store_explicit(&ctx->failures, 0, memory_order_relaxed);
967 ctx->fixture_steps = 0;
969 T_actions_forward(config, T_EVENT_CASE_EARLY, tc->name);
970 T_do_log(ctx, T_NORMAL,
"B:%s\n", tc->name);
971 ctx->case_begin_time = (*config->now)();
972 T_actions_forward(config, T_EVENT_CASE_BEGIN, tc->name);
974 if (fixture != NULL) {
975 ctx->case_fixture.fixture = fixture;
976 ctx->case_fixture.context = fixture->initial_context;
978 if (fixture->setup != NULL) {
979 (*fixture->setup)(ctx->case_fixture.context);
985 T_check_steps(
unsigned int planned_steps,
unsigned int steps,
986 unsigned int failures)
988 if (planned_steps != UINT_MAX && planned_steps != steps &&
990 T_check(&T_special,
false,
"actual steps (%u), " 991 "planned steps (%u)", steps, planned_steps);
999 unsigned int planned_steps;
1001 unsigned int failures;
1005 while (ctx->fixtures != NULL) {
1009 T_call_destructors(ctx);
1010 config = ctx->config;
1011 T_actions_backward(config, T_EVENT_CASE_END, tc->name);
1013 planned_steps = atomic_fetch_add_explicit(&ctx->planned_steps,
1014 0, memory_order_relaxed);
1015 steps = atomic_fetch_add_explicit(&ctx->steps, 0,
1016 memory_order_relaxed);
1017 failures = atomic_fetch_add_explicit(&ctx->failures, 0,
1018 memory_order_relaxed);
1019 T_check_steps(planned_steps, steps, failures);
1021 failures = atomic_load_explicit(&ctx->failures, memory_order_relaxed);
1022 delta = (*config->now)() - ctx->case_begin_time;
1023 steps += ctx->fixture_steps;
1024 T_do_log(ctx, T_QUIET,
"E:%s:N:%u:F:%u:D:%s\n",
1025 tc->name, steps, failures, T_time_to_string_us(delta, ts));
1027 ++ctx->overall_cases;
1028 ctx->overall_steps += steps;
1029 ctx->overall_failures += failures;
1031 T_actions_backward(config, T_EVENT_CASE_LATE, tc->name);
1037 T_do_case_begin(ctx, tc);
1039 if (setjmp(ctx->case_begin_context) == 0) {
1043 T_do_case_end(ctx, tc);
1051 tc = ctx->registered_cases;
1053 while (tc != NULL) {
1054 T_run_case(ctx, tc);
1066 config = ctx->config;
1067 T_actions_backward(config, T_EVENT_RUN_FINALIZE_EARLY, config->name);
1068 delta = (*config->now)() - ctx->run_begin_time;
1069 T_do_log(ctx, T_QUIET,
"Z:%s:C:%u:N:%u:F:%u:D:%s\n", config->name,
1070 ctx->overall_cases, ctx->overall_steps, ctx->overall_failures,
1071 T_time_to_string_us(delta, ts));
1072 T_actions_backward(config, T_EVENT_RUN_FINALIZE_LATE, config->name);
1074 ctx->runner_thread = NULL;
1075 ctx->runner_cpu = NULL;
1077 ctx->runner_valid =
false;
1079 pthread_spin_destroy(&ctx->lock);
1081 return ctx->overall_failures == 0;
1089 ctx = T_do_run_initialize(config);
1092 return T_do_run_finalize(ctx) ? 0 : 1;
1099 void T_register(
void)
1104 RTEMS_LINKER_SET_FOREACH(_T, tc) {
1105 T_case_register(*tc);
1111 T_run_initialize(
const T_config *config)
1113 (void)T_do_run_initialize(config);
1119 T_do_run_all(&T_instance);
1123 T_run_by_name(
const char *name)
1129 tc = ctx->registered_cases;
1131 while (tc != NULL) {
1132 if (strcmp(tc->name, name) == 0) {
1133 T_run_case(ctx, tc);
1144 T_case_begin(
const char *name,
const T_fixture *fixture)
1150 tc->fixture = fixture;
1151 T_do_case_begin(&T_instance, tc);
1160 T_do_case_end(&T_instance, tc);
1164 T_run_finalize(
void)
1166 return T_do_run_finalize(&T_instance);
1170 T_case_begin_time(
void)
1172 return T_instance.case_begin_time;
1176 T_set_putchar(T_putchar new_putchar,
void *new_arg, T_putchar *old_putchar,
1182 *old_putchar = ctx->putchar;
1183 *old_arg = ctx->putchar_arg;
1184 ctx->putchar = new_putchar;
1185 ctx->putchar_arg = new_arg;
1195 config = ctx->config;
1196 return (*config->now)();
1207 old = ctx->fixtures;
1208 old->previous = node;
1210 node->previous = NULL;
1211 node->fixture = fixture;
1212 context = fixture->initial_context;
1213 node->context = context;
1214 node->next_planned_steps = atomic_exchange_explicit(
1215 &ctx->planned_steps, UINT_MAX, memory_order_relaxed);
1216 node->next_steps = atomic_exchange_explicit(&ctx->steps, 0,
1217 memory_order_relaxed);
1218 node->failures = atomic_fetch_add_explicit(&ctx->failures, 0,
1219 memory_order_relaxed);
1220 ctx->fixtures = node;
1222 if (fixture != NULL && fixture->setup != NULL) {
1223 (*fixture->setup)(context);
1238 node = ctx->fixtures;
1240 ctx->fixtures = next;
1241 fixture = node->fixture;
1243 if (fixture != NULL && fixture->teardown != NULL) {
1244 (*fixture->teardown)(node->context);
1248 unsigned int planned_steps;
1250 unsigned int failures;
1252 next->previous = NULL;
1253 planned_steps = atomic_exchange_explicit(&ctx->planned_steps,
1254 node->next_planned_steps, memory_order_relaxed);
1255 steps = atomic_exchange_explicit(&ctx->steps, node->next_steps,
1256 memory_order_relaxed);
1257 failures = atomic_fetch_add_explicit(&ctx->failures, 0,
1258 memory_order_relaxed);
1259 ctx->fixture_steps += steps;
1260 T_check_steps(planned_steps, steps, node->failures - failures);
1263 memset(node, 0,
sizeof(*node));
1267 T_get_scope(
const char *
const *
const *desc,
char *buf,
size_t n,
1268 const size_t *second_indices)
1277 const char *
const *desc2;
1282 if (desc2 == NULL) {
1294 m = T_str_copy(buf, desc2[second_indices[i]], c);
#define _ISR_Local_disable(_level)
Disables interrupts on this processor.
SuperCore SMP Support API.
Thread_queue_Queue Queue
The actual thread queue.
const char * name
The thread queue name.
const char * rtems_board_support_package(void)
Returns the board support package name.
#define _ISR_Local_enable(_level)
Enables interrupts on this processor.
Thread_queue_Control Join_queue
Thread queue for thread join operations and multi-purpose lock.
Inlined Routines from the Thread Handler.
const char * rtems_version(void)
Returns the version string.