source: rtems/testsuites/smptests/smpscheduler03/init.c @ 9bfad8c

5
Last change on this file since 9bfad8c was 9bfad8c, checked in by Sebastian Huber <sebastian.huber@…>, on 06/08/16 at 20:22:46

score: Add thread priority to scheduler nodes

The thread priority is manifest in two independent areas. One area is
the user visible thread priority along with a potential thread queue.
The other is the scheduler. Currently, a thread priority update via
_Thread_Change_priority() first updates the user visble thread priority
and the thread queue, then the scheduler is notified if necessary. The
priority is passed to the scheduler via a local variable. A generation
counter ensures that the scheduler discards out-of-date priorities.

This use of a local variable ties the update in these two areas close
together. For later enhancements and the OMIP locking protocol
implementation we need more flexibility. Add a thread priority
information block to Scheduler_Node and synchronize priority value
updates via a sequence lock on SMP configurations.

Update #2556.

  • Property mode set to 100644
File size: 16.7 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(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 *update_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  Scheduler_Node *node;
201
202  thread->current_priority = new_priority;
203  node = _Scheduler_Thread_get_node(thread);
204  _Scheduler_Node_set_priority(node, new_priority, prepend_it);
205
206  _Thread_State_acquire( thread, &state_lock_context );
207  scheduler = _Scheduler_Get( thread );
208  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
209
210  needs_help = (*scheduler->Operations.update_priority)( scheduler, thread);
211
212  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
213  _Thread_State_release( thread, &state_lock_context );
214
215  return needs_help;
216}
217
218static void test_case_update_priority_op(
219  Thread_Control *executing,
220  Scheduler_SMP_Node *executing_node,
221  Thread_Control *other,
222  Scheduler_SMP_Node_state start_state,
223  Priority_Control prio,
224  bool prepend_it,
225  Scheduler_SMP_Node_state new_state
226)
227{
228  Thread_Control *needs_help;
229  Per_CPU_Control *cpu_self;
230
231  cpu_self = _Thread_Dispatch_disable();
232
233  switch (start_state) {
234    case SCHEDULER_SMP_NODE_SCHEDULED:
235      change_priority(executing, 1, true);
236      break;
237    case SCHEDULER_SMP_NODE_READY:
238      change_priority(executing, 4, true);
239      break;
240    default:
241      rtems_test_assert(0);
242      break;
243  }
244  rtems_test_assert(executing_node->state == start_state);
245
246  needs_help = update_priority_op(executing, prio, prepend_it);
247  rtems_test_assert(executing_node->state == new_state);
248
249  if (start_state != new_state) {
250    switch (start_state) {
251      case SCHEDULER_SMP_NODE_SCHEDULED:
252        rtems_test_assert(needs_help == executing);
253        break;
254      case SCHEDULER_SMP_NODE_READY:
255        rtems_test_assert(needs_help == other);
256        break;
257      default:
258        rtems_test_assert(0);
259        break;
260    }
261  } else {
262    rtems_test_assert(needs_help == NULL);
263  }
264
265  change_priority(executing, 1, true);
266  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
267
268  _Thread_Dispatch_enable( cpu_self );
269}
270
271static void test_update_priority_op(void)
272{
273  rtems_status_code sc;
274  rtems_id task_id;
275  Thread_Control *executing;
276  Scheduler_SMP_Node *executing_node;
277  Thread_Control *other;
278  size_t i;
279  size_t j;
280  size_t k;
281
282  task_id = start_task(3);
283  executing = _Thread_Get_executing();
284  executing_node = _Scheduler_SMP_Thread_get_node(executing);
285
286  other = get_thread_by_id(task_id);
287
288  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
289    for (j = 0; j < RTEMS_ARRAY_SIZE(priorities); ++j) {
290      for (k = 0; k < RTEMS_ARRAY_SIZE(prepend_it); ++k) {
291        test_case_update_priority_op(
292          executing,
293          executing_node,
294          other,
295          states[i],
296          priorities[j],
297          prepend_it[k],
298          states[j]
299        );
300      }
301    }
302  }
303
304  sc = rtems_task_delete(task_id);
305  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
306}
307
308static Thread_Control *yield_op(Thread_Control *thread)
309{
310  const Scheduler_Control *scheduler;
311  ISR_lock_Context state_lock_context;
312  ISR_lock_Context scheduler_lock_context;
313  Thread_Control *needs_help;
314
315  _Thread_State_acquire( thread, &state_lock_context );
316  scheduler = _Scheduler_Get( thread );
317  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
318
319  needs_help = (*scheduler->Operations.yield)(scheduler, thread);
320
321  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
322  _Thread_State_release( thread, &state_lock_context );
323
324  return needs_help;
325}
326
327static void test_case_yield_op(
328  Thread_Control *executing,
329  Scheduler_SMP_Node *executing_node,
330  Thread_Control *other,
331  Scheduler_SMP_Node_state start_state,
332  Scheduler_SMP_Node_state new_state
333)
334{
335  Thread_Control *needs_help;
336  Per_CPU_Control *cpu_self;
337
338  cpu_self = _Thread_Dispatch_disable();
339
340  change_priority(executing, 4, false);
341  change_priority(other, 4, false);
342
343  switch (start_state) {
344    case SCHEDULER_SMP_NODE_SCHEDULED:
345      switch (new_state) {
346        case SCHEDULER_SMP_NODE_SCHEDULED:
347          change_priority(executing, 2, false);
348          change_priority(other, 3, false);
349          break;
350        case SCHEDULER_SMP_NODE_READY:
351          change_priority(executing, 2, false);
352          change_priority(other, 2, false);
353          break;
354        default:
355          rtems_test_assert(0);
356          break;
357      }
358      break;
359    case SCHEDULER_SMP_NODE_READY:
360      switch (new_state) {
361        case SCHEDULER_SMP_NODE_SCHEDULED:
362          rtems_test_assert(0);
363          break;
364        case SCHEDULER_SMP_NODE_READY:
365          change_priority(executing, 3, false);
366          change_priority(other, 2, false);
367          break;
368        default:
369          rtems_test_assert(0);
370          break;
371      }
372      break;
373    default:
374      rtems_test_assert(0);
375      break;
376  }
377  rtems_test_assert(executing_node->state == start_state);
378
379  needs_help = yield_op(executing);
380  rtems_test_assert(executing_node->state == new_state);
381
382  if (start_state != new_state) {
383    switch (start_state) {
384      case SCHEDULER_SMP_NODE_SCHEDULED:
385        rtems_test_assert(needs_help == executing);
386        break;
387      case SCHEDULER_SMP_NODE_READY:
388        rtems_test_assert(needs_help == other);
389        break;
390      default:
391        rtems_test_assert(0);
392        break;
393    }
394  } else {
395    rtems_test_assert(needs_help == NULL);
396  }
397
398  change_priority(executing, 1, true);
399  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
400
401  _Thread_Dispatch_enable( cpu_self );
402}
403
404static void test_yield_op(void)
405{
406  rtems_status_code sc;
407  rtems_id task_id;
408  Thread_Control *executing;
409  Scheduler_SMP_Node *executing_node;
410  Thread_Control *other;
411  size_t i;
412  size_t j;
413
414  task_id = start_task(2);
415  executing = _Thread_Get_executing();
416  executing_node = _Scheduler_SMP_Thread_get_node(executing);
417
418  other = get_thread_by_id(task_id);
419
420  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
421    for (j = 0; j < RTEMS_ARRAY_SIZE(states); ++j) {
422      if (
423        states[i] != SCHEDULER_SMP_NODE_READY
424          || states[j] != SCHEDULER_SMP_NODE_SCHEDULED
425      ) {
426        test_case_yield_op(
427          executing,
428          executing_node,
429          other,
430          states[i],
431          states[j]
432        );
433      }
434    }
435  }
436
437  sc = rtems_task_delete(task_id);
438  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
439}
440
441static void block_op(Thread_Control *thread)
442{
443  const Scheduler_Control *scheduler;
444  ISR_lock_Context state_lock_context;
445  ISR_lock_Context scheduler_lock_context;
446
447  _Thread_State_acquire( thread, &state_lock_context );
448  scheduler = _Scheduler_Get( thread );
449  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
450
451  (*scheduler->Operations.block)(scheduler, thread);
452
453  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
454  _Thread_State_release( thread, &state_lock_context );
455}
456
457static Thread_Control *unblock_op(Thread_Control *thread)
458{
459  const Scheduler_Control *scheduler;
460  ISR_lock_Context state_lock_context;
461  ISR_lock_Context scheduler_lock_context;
462  Thread_Control *needs_help;
463
464  _Thread_State_acquire( thread, &state_lock_context );
465  scheduler = _Scheduler_Get( thread );
466  _Scheduler_Acquire_critical( scheduler, &scheduler_lock_context );
467
468  needs_help = (*scheduler->Operations.unblock)(scheduler, thread);
469
470  _Scheduler_Release_critical( scheduler, &scheduler_lock_context );
471  _Thread_State_release( thread, &state_lock_context );
472
473  return needs_help;
474}
475
476static void test_case_unblock_op(
477  Thread_Control *executing,
478  Scheduler_SMP_Node *executing_node,
479  Thread_Control *other,
480  Scheduler_SMP_Node_state new_state
481)
482{
483  Thread_Control *needs_help;
484  Per_CPU_Control *cpu_self;
485
486  cpu_self = _Thread_Dispatch_disable();
487
488  switch (new_state) {
489    case SCHEDULER_SMP_NODE_SCHEDULED:
490      change_priority(executing, 2, false);
491      rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
492      break;
493    case SCHEDULER_SMP_NODE_READY:
494      change_priority(executing, 4, false);
495      rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_READY);
496      break;
497    default:
498      rtems_test_assert(0);
499      break;
500  }
501
502  block_op(executing);
503  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_BLOCKED);
504
505  needs_help = unblock_op(executing);
506  rtems_test_assert(executing_node->state == new_state);
507
508  switch (new_state) {
509    case SCHEDULER_SMP_NODE_SCHEDULED:
510      rtems_test_assert(needs_help == other);
511      break;
512    case SCHEDULER_SMP_NODE_READY:
513      rtems_test_assert(needs_help == executing);
514      break;
515    default:
516      rtems_test_assert(0);
517      break;
518  }
519
520  change_priority(executing, 1, true);
521  rtems_test_assert(executing_node->state == SCHEDULER_SMP_NODE_SCHEDULED);
522
523  _Thread_Dispatch_enable( cpu_self );
524}
525
526static void test_unblock_op(void)
527{
528  rtems_status_code sc;
529  rtems_id task_id;
530  Thread_Control *executing;
531  Scheduler_SMP_Node *executing_node;
532  Thread_Control *other;
533  size_t i;
534
535  task_id = start_task(3);
536  executing = _Thread_Get_executing();
537  executing_node = _Scheduler_SMP_Thread_get_node(executing);
538
539  other = get_thread_by_id(task_id);
540
541  for (i = 0; i < RTEMS_ARRAY_SIZE(states); ++i) {
542    test_case_unblock_op(
543      executing,
544      executing_node,
545      other,
546      states[i]
547    );
548  }
549
550  sc = rtems_task_delete(task_id);
551  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
552}
553
554static void tests(void)
555{
556  test_change_priority();
557  test_update_priority_op();
558  test_yield_op();
559  test_unblock_op();
560}
561
562static void test_task(rtems_task_argument arg)
563{
564  test_context *ctx = &test_instance;
565
566  tests();
567
568  ctx->cpu_index[arg] = rtems_get_current_processor();
569
570  barrier_wait(ctx);
571
572  rtems_task_suspend(RTEMS_SELF);
573  rtems_test_assert(0);
574}
575
576static void done(uint32_t cpu_index)
577{
578  printf("test done on processor %" PRIu32 "\n", cpu_index);
579}
580
581static void Init(rtems_task_argument arg)
582{
583  test_context *ctx = &test_instance;
584  rtems_status_code sc;
585  rtems_resource_snapshot snapshot;
586  uint32_t cpu_count = rtems_get_processor_count();
587  uint32_t cpu_index;
588
589  TEST_BEGIN();
590
591  rtems_resource_snapshot_take(&snapshot);
592
593  sc = rtems_barrier_create(
594    rtems_build_name('B', 'A', 'R', 'I'),
595    RTEMS_BARRIER_AUTOMATIC_RELEASE,
596    cpu_count,
597    &ctx->barrier_id
598  );
599  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
600
601  for (cpu_index = 1; cpu_index < cpu_count; ++cpu_index) {
602    rtems_id scheduler_id;
603
604    sc = rtems_task_create(
605      rtems_build_name('T', 'A', 'S', 'K'),
606      1,
607      RTEMS_MINIMUM_STACK_SIZE,
608      RTEMS_DEFAULT_MODES,
609      RTEMS_DEFAULT_ATTRIBUTES,
610      &ctx->task_id[cpu_index]
611    );
612    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
613
614    sc = rtems_scheduler_ident(SCHED_NAME(cpu_index), &scheduler_id);
615    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
616
617    sc = rtems_task_set_scheduler(ctx->task_id[cpu_index], scheduler_id);
618    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
619
620    sc = rtems_task_start(ctx->task_id[cpu_index], test_task, cpu_index);
621    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
622  }
623
624  tests();
625
626  barrier_wait(ctx);
627
628  sc = rtems_barrier_delete(ctx->barrier_id);
629  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
630
631  done(0);
632
633  for (cpu_index = 1; cpu_index < cpu_count; ++cpu_index) {
634    sc = rtems_task_delete(ctx->task_id[cpu_index]);
635    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
636
637    rtems_test_assert(ctx->cpu_index[cpu_index] == cpu_index);
638
639    done(cpu_index);
640  }
641
642  rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
643
644  TEST_END();
645  rtems_test_exit(0);
646}
647
648#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
649#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
650
651#define CONFIGURE_SMP_APPLICATION
652
653#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_MAX
654
655#define CONFIGURE_MAXIMUM_PRIORITY 255
656
657#define CONFIGURE_SCHEDULER_PRIORITY_SMP
658#define CONFIGURE_SCHEDULER_SIMPLE_SMP
659#define CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP
660
661#include <rtems/scheduler.h>
662
663RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(a, CONFIGURE_MAXIMUM_PRIORITY + 1);
664
665RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
666
667RTEMS_SCHEDULER_CONTEXT_PRIORITY_AFFINITY_SMP(
668  c,
669  CONFIGURE_MAXIMUM_PRIORITY + 1
670);
671
672#define CONFIGURE_SCHEDULER_CONTROLS \
673  RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(a, SCHED_NAME(0)), \
674  RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, SCHED_NAME(1)), \
675  RTEMS_SCHEDULER_CONTROL_PRIORITY_AFFINITY_SMP(c, SCHED_NAME(2))
676
677#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
678  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
679  RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
680  RTEMS_SCHEDULER_ASSIGN(2, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
681
682#define CONFIGURE_MAXIMUM_TASKS 6
683#define CONFIGURE_MAXIMUM_BARRIERS 1
684
685#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
686
687#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
688
689#define CONFIGURE_INIT
690
691#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.