source: rtems/testsuites/smptests/smpscheduler03/init.c @ 5eac9676

5
Last change on this file since 5eac9676 was 5eac9676, checked in by Sebastian Huber <sebastian.huber@…>, on 05/17/16 at 12:54:48

testsuites: Replace _Thread_Get()

Replace _Thread_Get() with _Thread_Get_interrupt_disable() to avoid the
Giant lock.

Update #2555.

  • Property mode set to 100644
File size: 16.6 KB
Line 
1/*
2 * Copyright (c) 2014-2015 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <stdio.h>
20#include <inttypes.h>
21
22#include <rtems.h>
23#include <rtems/libcsupport.h>
24#include <rtems/score/threadimpl.h>
25#include <rtems/score/schedulersmpimpl.h>
26
27#include "tmacros.h"
28
29const char rtems_test_name[] = "SMPSCHEDULER 3";
30
31#define CPU_MAX 3
32
33#define SCHED_NAME(i) rtems_build_name(' ', ' ', ' ', (char) ('A' + (i)))
34
35typedef struct {
36  rtems_id barrier_id;
37  rtems_id task_id[CPU_MAX];
38  uint32_t cpu_index[CPU_MAX];
39} test_context;
40
41static test_context test_instance;
42
43static bool change_priority_filter(
44  Thread_Control   *thread,
45  Priority_Control *new_priority,
46  void             *arg
47)
48{
49  return thread->current_priority != *new_priority;
50}
51
52static void change_priority(
53  Thread_Control   *thread,
54  Priority_Control  new_priority,
55  bool              prepend_it
56)
57{
58  _Thread_Change_priority(
59    thread,
60    new_priority,
61    NULL,
62    change_priority_filter,
63    prepend_it
64  );
65}
66
67static void barrier_wait(test_context *ctx)
68{
69  rtems_status_code sc;
70
71  sc = rtems_barrier_wait(ctx->barrier_id, RTEMS_NO_TIMEOUT);
72  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
73}
74
75static void task(rtems_task_argument arg)
76{
77  rtems_test_assert(0);
78}
79
80static rtems_id start_task(rtems_task_priority prio)
81{
82  rtems_status_code sc;
83  rtems_id task_id;
84
85  sc = rtems_task_create(
86    rtems_build_name('T', 'A', 'S', 'K'),
87    prio,
88    RTEMS_MINIMUM_STACK_SIZE,
89    RTEMS_DEFAULT_MODES,
90    RTEMS_DEFAULT_ATTRIBUTES,
91    &task_id
92  );
93  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
94
95  sc = rtems_task_start(task_id, task, 0);
96  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
97
98  return task_id;
99}
100
101static Thread_Control *get_thread_by_id(rtems_id task_id)
102{
103  ISR_lock_Context lock_context;
104  Thread_Control *thread;
105
106  thread = _Thread_Get_interrupt_disable(task_id, &lock_context);
107  rtems_test_assert(thread != NULL);
108  _ISR_lock_ISR_enable(&lock_context);
109
110  return thread;
111}
112
113static void test_case_change_priority(
114  Thread_Control *executing,
115  Scheduler_SMP_Node *node,
116  Scheduler_SMP_Node_state start_state,
117  Priority_Control prio,
118  bool prepend_it,
119  Scheduler_SMP_Node_state new_state
120)
121{
122  Per_CPU_Control *cpu_self;
123
124  cpu_self = _Thread_Dispatch_disable();
125
126  switch (start_state) {
127    case SCHEDULER_SMP_NODE_SCHEDULED:
128      change_priority(executing, 1, true);
129      break;
130    case SCHEDULER_SMP_NODE_READY:
131      change_priority(executing, 4, true);
132      break;
133    default:
134      rtems_test_assert(0);
135      break;
136  }
137  rtems_test_assert(node->state == start_state);
138
139  change_priority(executing, prio, prepend_it);
140  rtems_test_assert(node->state == new_state);
141
142  change_priority(executing, 1, true);
143  rtems_test_assert(node->state == SCHEDULER_SMP_NODE_SCHEDULED);
144
145  _Thread_Dispatch_enable( cpu_self );
146}
147
148static const Scheduler_SMP_Node_state states[2] = {
149  SCHEDULER_SMP_NODE_SCHEDULED,
150  SCHEDULER_SMP_NODE_READY
151};
152
153static const Priority_Control priorities[2] = { 2, 5 };
154
155static const bool prepend_it[2] = { true, false };
156
157static void test_change_priority(void)
158{
159  rtems_status_code sc;
160  rtems_id task_id;
161  Thread_Control *executing;
162  Scheduler_SMP_Node *node;
163  size_t i;
164  size_t j;
165  size_t k;
166
167  task_id = start_task(3);
168  executing = _Thread_Get_executing();
169  node = _Scheduler_SMP_Thread_get_node(executing);
170
171  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
172    for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) {
173      for (k = 0; k < RTEMS_ARRAY_SIZE(prepend_it); ++k) {
174        test_case_change_priority(
175          executing,
176          node,
177          states[i],
178          priorities[j],
179          prepend_it[k],
180          states[j]
181        );
182      }
183    }
184  }
185
186  sc = rtems_task_delete(task_id);
187  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
188}
189
190static Thread_Control *change_priority_op(
191  Thread_Control *thread,
192  Priority_Control new_priority,
193  bool prepend_it
194)
195{
196  const Scheduler_Control *scheduler;
197  ISR_lock_Context state_lock_context;
198  ISR_lock_Context scheduler_lock_context;
199  Thread_Control *needs_help;
200
201  _Thread_State_acquire( thread, &state_lock_context );
202  scheduler = _Scheduler_Get( thread );
203  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
204
205  thread->current_priority = new_priority;
206  needs_help = (*scheduler->Operations.change_priority)(
207    scheduler,
208    thread,
209    new_priority,
210    prepend_it
211  );
212
213  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
214  _Thread_State_release( thread, &state_lock_context );
215
216  return needs_help;
217}
218
219static void test_case_change_priority_op(
220  Thread_Control *executing,
221  Scheduler_SMP_Node *executing_node,
222  Thread_Control *other,
223  Scheduler_SMP_Node_state start_state,
224  Priority_Control prio,
225  bool prepend_it,
226  Scheduler_SMP_Node_state new_state
227)
228{
229  Thread_Control *needs_help;
230  Per_CPU_Control *cpu_self;
231
232  cpu_self = _Thread_Dispatch_disable();
233
234  switch (start_state) {
235    case SCHEDULER_SMP_NODE_SCHEDULED:
236      change_priority(executing, 1, true);
237      break;
238    case SCHEDULER_SMP_NODE_READY:
239      change_priority(executing, 4, true);
240      break;
241    default:
242      rtems_test_assert(0);
243      break;
244  }
245  rtems_test_assert(executing_node->state == start_state);
246
247  needs_help = change_priority_op(executing, prio, prepend_it);
248  rtems_test_assert(executing_node->state == new_state);
249
250  if (start_state != new_state) {
251    switch (start_state) {
252      case SCHEDULER_SMP_NODE_SCHEDULED:
253        rtems_test_assert(needs_help == executing);
254        break;
255      case SCHEDULER_SMP_NODE_READY:
256        rtems_test_assert(needs_help == other);
257        break;
258      default:
259        rtems_test_assert(0);
260        break;
261    }
262  } else {
263    rtems_test_assert(needs_help == NULL);
264  }
265
266  change_priority(executing, 1, true);
267  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
268
269  _Thread_Dispatch_enable( cpu_self );
270}
271
272static void test_change_priority_op(void)
273{
274  rtems_status_code sc;
275  rtems_id task_id;
276  Thread_Control *executing;
277  Scheduler_SMP_Node *executing_node;
278  Thread_Control *other;
279  size_t i;
280  size_t j;
281  size_t k;
282
283  task_id = start_task(3);
284  executing = _Thread_Get_executing();
285  executing_node = _Scheduler_SMP_Thread_get_node(executing);
286
287  other = get_thread_by_id(task_id);
288
289  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
290    for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) {
291      for (k = 0; k < RTEMS_ARRAY_SIZE(prepend_it); ++k) {
292        test_case_change_priority_op(
293          executing,
294          executing_node,
295          other,
296          states[i],
297          priorities[j],
298          prepend_it[k],
299          states[j]
300        );
301      }
302    }
303  }
304
305  sc = rtems_task_delete(task_id);
306  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
307}
308
309static Thread_Control *yield_op(Thread_Control *thread)
310{
311  const Scheduler_Control *scheduler;
312  ISR_lock_Context state_lock_context;
313  ISR_lock_Context scheduler_lock_context;
314  Thread_Control *needs_help;
315
316  _Thread_State_acquire( thread, &state_lock_context );
317  scheduler = _Scheduler_Get( thread );
318  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
319
320  needs_help = (*scheduler->Operations.yield)(scheduler, thread);
321
322  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
323  _Thread_State_release( thread, &state_lock_context );
324
325  return needs_help;
326}
327
328static void test_case_yield_op(
329  Thread_Control *executing,
330  Scheduler_SMP_Node *executing_node,
331  Thread_Control *other,
332  Scheduler_SMP_Node_state start_state,
333  Scheduler_SMP_Node_state new_state
334)
335{
336  Thread_Control *needs_help;
337  Per_CPU_Control *cpu_self;
338
339  cpu_self = _Thread_Dispatch_disable();
340
341  change_priority(executing, 4, false);
342  change_priority(other, 4, false);
343
344  switch (start_state) {
345    case SCHEDULER_SMP_NODE_SCHEDULED:
346      switch (new_state) {
347        case SCHEDULER_SMP_NODE_SCHEDULED:
348          change_priority(executing, 2, false);
349          change_priority(other, 3, false);
350          break;
351        case SCHEDULER_SMP_NODE_READY:
352          change_priority(executing, 2, false);
353          change_priority(other, 2, false);
354          break;
355        default:
356          rtems_test_assert(0);
357          break;
358      }
359      break;
360    case SCHEDULER_SMP_NODE_READY:
361      switch (new_state) {
362        case SCHEDULER_SMP_NODE_SCHEDULED:
363          rtems_test_assert(0);
364          break;
365        case SCHEDULER_SMP_NODE_READY:
366          change_priority(executing, 3, false);
367          change_priority(other, 2, false);
368          break;
369        default:
370          rtems_test_assert(0);
371          break;
372      }
373      break;
374    default:
375      rtems_test_assert(0);
376      break;
377  }
378  rtems_test_assert(executing_node->state == start_state);
379
380  needs_help = yield_op(executing);
381  rtems_test_assert(executing_node->state == new_state);
382
383  if (start_state != new_state) {
384    switch (start_state) {
385      case SCHEDULER_SMP_NODE_SCHEDULED:
386        rtems_test_assert(needs_help == executing);
387        break;
388      case SCHEDULER_SMP_NODE_READY:
389        rtems_test_assert(needs_help == other);
390        break;
391      default:
392        rtems_test_assert(0);
393        break;
394    }
395  } else {
396    rtems_test_assert(needs_help == NULL);
397  }
398
399  change_priority(executing, 1, true);
400  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
401
402  _Thread_Dispatch_enable( cpu_self );
403}
404
405static void test_yield_op(void)
406{
407  rtems_status_code sc;
408  rtems_id task_id;
409  Thread_Control *executing;
410  Scheduler_SMP_Node *executing_node;
411  Thread_Control *other;
412  size_t i;
413  size_t j;
414
415  task_id = start_task(2);
416  executing = _Thread_Get_executing();
417  executing_node = _Scheduler_SMP_Thread_get_node(executing);
418
419  other = get_thread_by_id(task_id);
420
421  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
422    for (j = 0; j < RTEMS_ARRAY_SIZE(states); ++j) {
423      if (
424        states[i] != SCHEDULER_SMP_NODE_READY
425          || states[j] != SCHEDULER_SMP_NODE_SCHEDULED
426      ) {
427        test_case_yield_op(
428          executing,
429          executing_node,
430          other,
431          states[i],
432          states[j]
433        );
434      }
435    }
436  }
437
438  sc = rtems_task_delete(task_id);
439  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
440}
441
442static void block_op(Thread_Control *thread)
443{
444  const Scheduler_Control *scheduler;
445  ISR_lock_Context state_lock_context;
446  ISR_lock_Context scheduler_lock_context;
447
448  _Thread_State_acquire( thread, &state_lock_context );
449  scheduler = _Scheduler_Get( thread );
450  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
451
452  (*scheduler->Operations.block)(scheduler, thread);
453
454  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
455  _Thread_State_release( thread, &state_lock_context );
456}
457
458static Thread_Control *unblock_op(Thread_Control *thread)
459{
460  const Scheduler_Control *scheduler;
461  ISR_lock_Context state_lock_context;
462  ISR_lock_Context scheduler_lock_context;
463  Thread_Control *needs_help;
464
465  _Thread_State_acquire( thread, &state_lock_context );
466  scheduler = _Scheduler_Get( thread );
467  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
468
469  needs_help = (*scheduler->Operations.unblock)(scheduler, thread);
470
471  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
472  _Thread_State_release( thread, &state_lock_context );
473
474  return needs_help;
475}
476
477static void test_case_unblock_op(
478  Thread_Control *executing,
479  Scheduler_SMP_Node *executing_node,
480  Thread_Control *other,
481  Scheduler_SMP_Node_state new_state
482)
483{
484  Thread_Control *needs_help;
485  Per_CPU_Control *cpu_self;
486
487  cpu_self = _Thread_Dispatch_disable();
488
489  switch (new_state) {
490    case SCHEDULER_SMP_NODE_SCHEDULED:
491      change_priority(executing, 2, false);
492      rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
493      break;
494    case SCHEDULER_SMP_NODE_READY:
495      change_priority(executing, 4, false);
496      rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_READY);
497      break;
498    default:
499      rtems_test_assert(0);
500      break;
501  }
502
503  block_op(executing);
504  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_BLOCKED);
505
506  needs_help = unblock_op(executing);
507  rtems_test_assert(executing_node->state == new_state);
508
509  switch (new_state) {
510    case SCHEDULER_SMP_NODE_SCHEDULED:
511      rtems_test_assert(needs_help == other);
512      break;
513    case SCHEDULER_SMP_NODE_READY:
514      rtems_test_assert(needs_help == executing);
515      break;
516    default:
517      rtems_test_assert(0);
518      break;
519  }
520
521  change_priority(executing, 1, true);
522  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
523
524  _Thread_Dispatch_enable( cpu_self );
525}
526
527static void test_unblock_op(void)
528{
529  rtems_status_code sc;
530  rtems_id task_id;
531  Thread_Control *executing;
532  Scheduler_SMP_Node *executing_node;
533  Thread_Control *other;
534  size_t i;
535
536  task_id = start_task(3);
537  executing = _Thread_Get_executing();
538  executing_node = _Scheduler_SMP_Thread_get_node(executing);
539
540  other = get_thread_by_id(task_id);
541
542  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
543    test_case_unblock_op(
544      executing,
545      executing_node,
546      other,
547      states[i]
548    );
549  }
550
551  sc = rtems_task_delete(task_id);
552  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
553}
554
555static void tests(void)
556{
557  test_change_priority();
558  test_change_priority_op();
559  test_yield_op();
560  test_unblock_op();
561}
562
563static void test_task(rtems_task_argument arg)
564{
565  test_context *ctx = &test_instance;
566
567  tests();
568
569  ctx->cpu_index[arg] = rtems_get_current_processor();
570
571  barrier_wait(ctx);
572
573  rtems_task_suspend(RTEMS_SELF);
574  rtems_test_assert(0);
575}
576
577static void done(uint32_t cpu_index)
578{
579  printf("test done on processor %" PRIu32 "\n", cpu_index);
580}
581
582static void Init(rtems_task_argument arg)
583{
584  test_context *ctx = &test_instance;
585  rtems_status_code sc;
586  rtems_resource_snapshot snapshot;
587  uint32_t cpu_count = rtems_get_processor_count();
588  uint32_t cpu_index;
589
590  TEST_BEGIN();
591
592  rtems_resource_snapshot_take(&snapshot);
593
594  sc = rtems_barrier_create(
595    rtems_build_name('B', 'A', 'R', 'I'),
596    RTEMS_BARRIER_AUTOMATIC_RELEASE,
597    cpu_count,
598    &ctx->barrier_id
599  );
600  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
601
602  for (cpu_index = 1; cpu_index < cpu_count; ++cpu_index) {
603    rtems_id scheduler_id;
604
605    sc = rtems_task_create(
606      rtems_build_name('T', 'A', 'S', 'K'),
607      1,
608      RTEMS_MINIMUM_STACK_SIZE,
609      RTEMS_DEFAULT_MODES,
610      RTEMS_DEFAULT_ATTRIBUTES,
611      &ctx->task_id[cpu_index]
612    );
613    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
614
615    sc = rtems_scheduler_ident(SCHED_NAME(cpu_index), &scheduler_id);
616    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
617
618    sc = rtems_task_set_scheduler(ctx->task_id[cpu_index], scheduler_id);
619    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
620
621    sc = rtems_task_start(ctx->task_id[cpu_index], test_task, cpu_index);
622    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
623  }
624
625  tests();
626
627  barrier_wait(ctx);
628
629  sc = rtems_barrier_delete(ctx->barrier_id);
630  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
631
632  done(0);
633
634  for (cpu_index = 1; cpu_index < cpu_count; ++cpu_index) {
635    sc = rtems_task_delete(ctx->task_id[cpu_index]);
636    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
637
638    rtems_test_assert(ctx->cpu_index[cpu_index] == cpu_index);
639
640    done(cpu_index);
641  }
642
643  rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
644
645  TEST_END();
646  rtems_test_exit(0);
647}
648
649#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
650#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
651
652#define CONFIGURE_SMP_APPLICATION
653
654#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_MAX
655
656#define CONFIGURE_MAXIMUM_PRIORITY 255
657
658#define CONFIGURE_SCHEDULER_PRIORITY_SMP
659#define CONFIGURE_SCHEDULER_SIMPLE_SMP
660#define CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP
661
662#include <rtems/scheduler.h>
663
664RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(a, CONFIGURE_MAXIMUM_PRIORITY + 1);
665
666RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
667
668RTEMS_SCHEDULER_CONTEXT_PRIORITY_AFFINITY_SMP(
669  c,
670  CONFIGURE_MAXIMUM_PRIORITY + 1
671);
672
673#define CONFIGURE_SCHEDULER_CONTROLS \
674  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(a, SCHED_NAME(0)), \
675  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, SCHED_NAME(1)), \
676  RTEMS_SCHEDULER_CONTROL_PRIORITY_AFFINITY_SMP(c, SCHED_NAME(2))
677
678#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
679  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
680  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
681  RTEMS_SCHEDULER_ASSIGN(2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
682
683#define CONFIGURE_MAXIMUM_TASKS 6
684#define CONFIGURE_MAXIMUM_BARRIERS 1
685
686#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
687
688#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
689
690#define CONFIGURE_INIT
691
692#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.