source: rtems/testsuites/smptests/smpthreadpin01/init.c @ 03c9f24

5
Last change on this file since 03c9f24 was 03c9f24, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 5, 2019 at 6:03:12 AM

rtems: Add rtems_scheduler_get_processor()

Add rtems_scheduler_get_processor() as a replacement for
rtems_get_current_processor(). The rtems_get_current_processor() is a
bit orphaned. Adopt it by the Scheduler Manager. This is in line with
the glibc sched_getcpu() function.

Deprecate rtems_get_current_processor().

Update #3731.

  • Property mode set to 100644
File size: 14.7 KB
Line 
1/*
2 * Copyright (c) 2018 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 <rtems.h>
20#include <rtems/thread.h>
21#include <rtems/score/threadimpl.h>
22
23#include <tmacros.h>
24
25const char rtems_test_name[] = "SMPTHREADPIN 1";
26
27#define CPU_COUNT 2
28
29#define SCHED_A rtems_build_name(' ', ' ', ' ', 'A')
30
31#define SCHED_B rtems_build_name(' ', ' ', ' ', 'B')
32
33#define EVENT_WAKEUP_MASTER RTEMS_EVENT_0
34
35#define EVENT_MTX_LOCK RTEMS_EVENT_1
36
37#define EVENT_MTX_UNLOCK RTEMS_EVENT_2
38
39#define EVENT_MOVE_BUSY_TO_CPU_0 RTEMS_EVENT_3
40
41#define EVENT_MOVE_BUSY_TO_CPU_1 RTEMS_EVENT_4
42
43#define EVENT_MOVE_SELF_TO_CPU_0 RTEMS_EVENT_5
44
45#define EVENT_MOVE_SELF_TO_CPU_1 RTEMS_EVENT_6
46
47#define EVENT_SET_SELF_PRIO_TO_LOW RTEMS_EVENT_7
48
49#define EVENT_SET_BUSY_PRIO_TO_IDLE RTEMS_EVENT_8
50
51#define EVENT_SET_FLAG RTEMS_EVENT_9
52
53#define PRIO_IDLE 6
54
55#define PRIO_VERY_LOW 5
56
57#define PRIO_LOW 4
58
59#define PRIO_MIDDLE 3
60
61#define PRIO_HIGH 2
62
63#define PRIO_VERY_HIGH 1
64
65typedef struct {
66  rtems_id master;
67  rtems_id event;
68  rtems_id event_2;
69  rtems_id busy;
70  rtems_id sched_a;
71  rtems_id sched_b;
72  rtems_mutex mtx;
73  volatile bool flag;
74} test_context;
75
76static test_context test_instance;
77
78static rtems_task_priority set_prio(rtems_id id, rtems_task_priority prio)
79{
80  rtems_status_code sc;
81  rtems_task_priority old_prio;
82
83  old_prio = 0xffffffff;
84  sc = rtems_task_set_priority(id, prio, &old_prio);
85  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
86
87  return old_prio;
88}
89
90static void set_affinity(rtems_id task, uint32_t cpu_index)
91{
92  rtems_status_code sc;
93  rtems_id sched_cpu;
94  rtems_id sched_task;
95  cpu_set_t set;
96
97  sc = rtems_scheduler_ident_by_processor(cpu_index, &sched_cpu);
98  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
99
100  sc = rtems_task_get_scheduler(task, &sched_task);
101  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
102
103  if (sched_task != sched_cpu) {
104    rtems_task_priority prio;
105
106    CPU_FILL(&set);
107    sc = rtems_task_set_affinity(task, sizeof(set), &set);
108    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
109
110    prio = set_prio(task, RTEMS_CURRENT_PRIORITY);
111    sc = rtems_task_set_scheduler(task, sched_cpu, prio);
112    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
113  }
114
115  CPU_ZERO(&set);
116  CPU_SET((int) cpu_index, &set);
117  sc = rtems_task_set_affinity(task, sizeof(set), &set);
118  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
119}
120
121static void send_events(rtems_id task, rtems_event_set events)
122{
123  rtems_status_code sc;
124
125  sc = rtems_event_send(task, events);
126  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
127}
128
129static rtems_event_set wait_for_events(void)
130{
131  rtems_event_set events;
132  rtems_status_code sc;
133
134  sc = rtems_event_receive(
135    RTEMS_ALL_EVENTS,
136    RTEMS_EVENT_ANY | RTEMS_WAIT,
137    RTEMS_NO_TIMEOUT,
138    &events
139  );
140  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
141
142  return events;
143}
144
145static void pin(bool blocked)
146{
147  Per_CPU_Control *cpu_self;
148  Thread_Control *executing;
149
150  cpu_self = _Thread_Dispatch_disable();
151  executing = _Per_CPU_Get_executing(cpu_self);
152
153  if (blocked) {
154    _Thread_Set_state(executing, STATES_SUSPENDED);
155  }
156
157  _Thread_Pin(executing);
158
159  if (blocked) {
160    _Thread_Clear_state(executing, STATES_SUSPENDED);
161  }
162
163  _Thread_Dispatch_enable(cpu_self);
164}
165
166static void unpin(bool blocked)
167{
168  Per_CPU_Control *cpu_self;
169  Thread_Control *executing;
170
171  cpu_self = _Thread_Dispatch_disable();
172  executing = _Per_CPU_Get_executing(cpu_self);
173
174  if (blocked) {
175    _Thread_Set_state(executing, STATES_SUSPENDED);
176  }
177
178  _Thread_Unpin(executing, cpu_self);
179
180  if (blocked) {
181    _Thread_Clear_state(executing, STATES_SUSPENDED);
182  }
183
184  _Thread_Dispatch_enable(cpu_self);
185}
186
187static void event_task(rtems_task_argument arg)
188{
189  test_context *ctx;
190
191  ctx = (test_context *) arg;
192
193  while (true) {
194    rtems_event_set events;
195
196    events = wait_for_events();
197
198    /*
199     * The order of event processing is important!
200     */
201
202    if ((events & EVENT_MTX_LOCK) != 0) {
203      rtems_mutex_lock(&ctx->mtx);
204    }
205
206    if ((events & EVENT_MTX_UNLOCK) != 0) {
207      rtems_mutex_unlock(&ctx->mtx);
208    }
209
210    if ((events & EVENT_MOVE_BUSY_TO_CPU_0) != 0) {
211      set_affinity(ctx->busy, 0);
212    }
213
214    if ((events & EVENT_MOVE_BUSY_TO_CPU_1) != 0) {
215      set_affinity(ctx->busy, 1);
216    }
217
218    if ((events & EVENT_MOVE_SELF_TO_CPU_0) != 0) {
219      set_affinity(RTEMS_SELF, 0);
220    }
221
222    if ((events & EVENT_MOVE_SELF_TO_CPU_1) != 0) {
223      set_affinity(RTEMS_SELF, 1);
224    }
225
226    if ((events & EVENT_SET_SELF_PRIO_TO_LOW) != 0) {
227      set_prio(RTEMS_SELF, PRIO_LOW);
228    }
229
230    if ((events & EVENT_SET_BUSY_PRIO_TO_IDLE) != 0) {
231      set_prio(ctx->busy, PRIO_IDLE);
232    }
233
234    if ((events & EVENT_SET_FLAG) != 0) {
235      ctx->flag = true;
236    }
237
238    if ((events & EVENT_WAKEUP_MASTER) != 0) {
239      send_events(ctx->master, EVENT_WAKEUP_MASTER);
240    }
241  }
242}
243
244static void busy_task(rtems_task_argument arg)
245{
246  (void) arg;
247
248  _CPU_Thread_Idle_body(0);
249}
250
251static const char *blocked_or_ready(bool blocked)
252{
253  return blocked ? "blocked" : "ready";
254}
255
256static void reconfigure_scheduler(test_context *ctx)
257{
258  rtems_status_code sc;
259
260  puts("reconfigure scheduler");
261
262  set_prio(ctx->master, PRIO_MIDDLE);
263  set_prio(ctx->event, PRIO_LOW);
264  set_prio(ctx->event_2, PRIO_VERY_LOW);
265  set_prio(ctx->busy, PRIO_IDLE);
266
267  set_affinity(ctx->master, 0);
268  set_affinity(ctx->event, 0);
269  set_affinity(ctx->event_2, 0);
270  set_affinity(ctx->busy, 0);
271
272  sc = rtems_scheduler_remove_processor(ctx->sched_a, 1);
273  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
274
275  sc = rtems_scheduler_add_processor(ctx->sched_b, 1);
276  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
277}
278
279static void test_simple_pin_unpin(test_context *ctx, int run)
280{
281  Per_CPU_Control *cpu_self;
282  Thread_Control *executing;
283
284  printf("test simple wait unpin (run %i)\n", run);
285
286  set_affinity(ctx->busy, 0);
287  set_prio(ctx->busy, PRIO_IDLE);
288  set_prio(RTEMS_SELF, PRIO_MIDDLE);
289  rtems_test_assert(rtems_scheduler_get_processor() == 1);
290
291  cpu_self = _Thread_Dispatch_disable();
292  executing = _Per_CPU_Get_executing(cpu_self);
293  _Thread_Pin(executing);
294
295  rtems_test_assert(rtems_scheduler_get_processor() == 1);
296
297  _Thread_Unpin(executing, cpu_self);
298  _Thread_Dispatch_enable(cpu_self);
299
300  rtems_test_assert(rtems_scheduler_get_processor() == 1);
301}
302
303static void test_pin_wait_unpin(test_context *ctx, bool blocked, int run)
304{
305  printf("test pin wait unpin (%s, run %i)\n", blocked_or_ready(blocked), run);
306
307  set_affinity(ctx->busy, 0);
308  set_prio(ctx->busy, PRIO_IDLE);
309  set_prio(RTEMS_SELF, PRIO_MIDDLE);
310  set_prio(ctx->event, PRIO_LOW);
311  set_affinity(ctx->event, 1);
312  rtems_test_assert(rtems_scheduler_get_processor() == 1);
313
314  pin(blocked);
315  rtems_test_assert(rtems_scheduler_get_processor() == 1);
316
317  send_events(ctx->event, EVENT_WAKEUP_MASTER);
318  rtems_test_assert(rtems_scheduler_get_processor() == 1);
319  wait_for_events();
320  rtems_test_assert(rtems_scheduler_get_processor() == 1);
321
322  set_prio(ctx->busy, PRIO_HIGH);
323  set_affinity(ctx->busy, 0);
324  unpin(blocked);
325  rtems_test_assert(rtems_scheduler_get_processor() == 1);
326}
327
328static void test_pin_preempt_unpin(test_context *ctx, bool blocked, int run)
329{
330  printf(
331    "test pin preempt unpin (%s, run %i)\n",
332    blocked_or_ready(blocked),
333    run
334  );
335
336  set_prio(RTEMS_SELF, PRIO_MIDDLE);
337  set_prio(ctx->event, PRIO_VERY_HIGH);
338  set_prio(ctx->busy, PRIO_HIGH);
339  set_affinity(ctx->event, 0);
340  set_affinity(ctx->busy, 0);
341  rtems_test_assert(rtems_scheduler_get_processor() == 1);
342
343  pin(blocked);
344  rtems_test_assert(rtems_scheduler_get_processor() == 1);
345
346  ctx->flag = false;
347  send_events(
348    ctx->event,
349    EVENT_MOVE_BUSY_TO_CPU_1 | EVENT_SET_SELF_PRIO_TO_LOW
350      | EVENT_SET_BUSY_PRIO_TO_IDLE | EVENT_SET_FLAG
351  );
352
353  while (!ctx->flag) {
354    rtems_test_assert(rtems_scheduler_get_processor() == 1);
355  }
356
357  set_affinity(ctx->busy, 0);
358  unpin(blocked);
359  rtems_test_assert(rtems_scheduler_get_processor() == 1);
360}
361
362static void test_pin_home_no_help_unpin(
363  test_context *ctx,
364  bool blocked,
365  int run
366)
367{
368  rtems_status_code sc;
369
370  printf(
371    "test pin home no help unpin (%s, run %i)\n",
372    blocked_or_ready(blocked),
373    run
374  );
375
376  set_affinity(ctx->busy, 1);
377  set_prio(ctx->busy, PRIO_IDLE);
378  set_prio(RTEMS_SELF, PRIO_MIDDLE);
379  rtems_test_assert(rtems_scheduler_get_processor() == 0);
380
381  pin(blocked);
382  rtems_test_assert(rtems_scheduler_get_processor() == 0);
383
384  sc = rtems_task_set_scheduler(RTEMS_SELF, ctx->sched_b, 1);
385  rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE);
386
387  rtems_mutex_lock(&ctx->mtx);
388  rtems_test_assert(rtems_scheduler_get_processor() == 0);
389
390  set_affinity(ctx->event, 1);
391  set_prio(ctx->event, PRIO_MIDDLE);
392
393  send_events(ctx->event, EVENT_MTX_LOCK);
394  set_prio(ctx->event_2, PRIO_LOW);
395  set_affinity(ctx->event_2, 1);
396  send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
397  wait_for_events();
398
399  /* Now the event task can help us */
400  rtems_test_assert(ctx->mtx._Queue._heads != NULL);
401  rtems_test_assert(rtems_scheduler_get_processor() == 0);
402
403  set_affinity(ctx->event_2, 0);
404  set_affinity(ctx->busy, 1);
405  set_prio(ctx->busy, PRIO_HIGH);
406  send_events(
407    ctx->event_2,
408    EVENT_MOVE_BUSY_TO_CPU_0 | EVENT_MOVE_SELF_TO_CPU_1
409      | EVENT_SET_SELF_PRIO_TO_LOW | EVENT_SET_BUSY_PRIO_TO_IDLE
410  );
411  set_prio(ctx->event_2, PRIO_VERY_HIGH);
412  rtems_test_assert(rtems_scheduler_get_processor() == 0);
413
414  rtems_mutex_unlock(&ctx->mtx);
415  rtems_test_assert(rtems_scheduler_get_processor() == 0);
416
417  send_events(ctx->event, EVENT_WAKEUP_MASTER | EVENT_MTX_UNLOCK);
418  wait_for_events();
419  rtems_test_assert(rtems_scheduler_get_processor() == 0);
420
421  unpin(blocked);
422  rtems_test_assert(rtems_scheduler_get_processor() == 0);
423}
424
425static void test_pin_foreign_no_help_unpin(
426  test_context *ctx,
427  bool blocked,
428  int run
429)
430{
431  printf(
432    "test pin foreign no help unpin (%s, run %i)\n",
433    blocked_or_ready(blocked),
434    run
435  );
436
437  set_affinity(ctx->busy, 1);
438  set_prio(ctx->busy, PRIO_IDLE);
439  set_prio(RTEMS_SELF, PRIO_MIDDLE);
440  rtems_test_assert(rtems_scheduler_get_processor() == 0);
441
442  rtems_mutex_lock(&ctx->mtx);
443  rtems_test_assert(rtems_scheduler_get_processor() == 0);
444
445  set_affinity(ctx->event, 1);
446  set_prio(ctx->event, PRIO_MIDDLE);
447  send_events(ctx->event, EVENT_MTX_LOCK);
448  set_prio(ctx->event_2, PRIO_LOW);
449  set_affinity(ctx->event_2, 1);
450  send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
451  wait_for_events();
452
453  /* Now the event task can help us */
454  rtems_test_assert(ctx->mtx._Queue._heads != NULL);
455  rtems_test_assert(rtems_scheduler_get_processor() == 0);
456
457  /* Request help */
458  set_affinity(ctx->busy, 0);
459  set_prio(ctx->busy, PRIO_HIGH);
460  rtems_test_assert(rtems_scheduler_get_processor() == 1);
461
462  /* Pin while using foreign scheduler */
463  pin(blocked);
464  rtems_test_assert(rtems_scheduler_get_processor() == 1);
465
466  set_affinity(ctx->event_2, 1);
467  send_events(
468    ctx->event_2,
469    EVENT_MOVE_BUSY_TO_CPU_1 | EVENT_MOVE_SELF_TO_CPU_0
470      | EVENT_SET_SELF_PRIO_TO_LOW | EVENT_SET_BUSY_PRIO_TO_IDLE
471  );
472  set_prio(ctx->event_2, PRIO_VERY_HIGH);
473  rtems_test_assert(rtems_scheduler_get_processor() == 1);
474
475  unpin(blocked);
476  rtems_test_assert(rtems_scheduler_get_processor() == 0);
477
478  set_prio(ctx->busy, PRIO_IDLE);
479  rtems_mutex_unlock(&ctx->mtx);
480  rtems_test_assert(rtems_scheduler_get_processor() == 0);
481
482  send_events(ctx->event, EVENT_WAKEUP_MASTER | EVENT_MTX_UNLOCK);
483  wait_for_events();
484  rtems_test_assert(rtems_scheduler_get_processor() == 0);
485}
486
487static void test(test_context *ctx)
488{
489  rtems_status_code sc;
490  int run;
491
492  ctx->master = rtems_task_self();
493
494  rtems_mutex_init(&ctx->mtx, "test");
495
496  sc = rtems_scheduler_ident(SCHED_A, &ctx->sched_a);
497  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
498
499  sc = rtems_scheduler_ident(SCHED_B, &ctx->sched_b);
500  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
501
502  sc = rtems_task_create(
503    rtems_build_name('B', 'U', 'S', 'Y'),
504    PRIO_HIGH,
505    RTEMS_MINIMUM_STACK_SIZE,
506    RTEMS_DEFAULT_MODES,
507    RTEMS_DEFAULT_ATTRIBUTES,
508    &ctx->busy
509  );
510  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
511
512  sc = rtems_task_start(ctx->busy, busy_task, (rtems_task_argument) ctx);
513  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
514
515  set_affinity(ctx->busy, 0);
516  set_prio(ctx->busy, PRIO_IDLE);
517  rtems_test_assert(rtems_scheduler_get_processor() == 1);
518
519  sc = rtems_task_create(
520    rtems_build_name('E', 'V', 'T', '1'),
521    PRIO_LOW,
522    RTEMS_MINIMUM_STACK_SIZE,
523    RTEMS_DEFAULT_MODES,
524    RTEMS_DEFAULT_ATTRIBUTES,
525    &ctx->event
526  );
527  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
528
529  sc = rtems_task_start(ctx->event, event_task, (rtems_task_argument) ctx);
530  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
531
532  send_events(ctx->event, EVENT_WAKEUP_MASTER);
533  wait_for_events();
534
535  sc = rtems_task_create(
536    rtems_build_name('E', 'V', 'T', '2'),
537    PRIO_LOW,
538    RTEMS_MINIMUM_STACK_SIZE,
539    RTEMS_DEFAULT_MODES,
540    RTEMS_DEFAULT_ATTRIBUTES,
541    &ctx->event_2
542  );
543  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
544
545  sc = rtems_task_start(ctx->event_2, event_task, (rtems_task_argument) ctx);
546  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
547
548  send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
549  wait_for_events();
550
551  for (run = 1; run <= 3; ++run) {
552    test_simple_pin_unpin(ctx, run);
553    test_pin_wait_unpin(ctx, true, run);
554    test_pin_wait_unpin(ctx, false, run);
555    test_pin_preempt_unpin(ctx, true, run);
556    test_pin_preempt_unpin(ctx, false, run);
557  }
558
559  reconfigure_scheduler(ctx);
560
561  for (run = 1; run <= 3; ++run) {
562    test_pin_home_no_help_unpin(ctx, true, run);
563    test_pin_home_no_help_unpin(ctx, false, run);
564    test_pin_foreign_no_help_unpin(ctx, true, run);
565    test_pin_foreign_no_help_unpin(ctx, false, run);
566  }
567}
568
569static void Init(rtems_task_argument arg)
570{
571  TEST_BEGIN();
572
573  if (rtems_get_processor_count() == CPU_COUNT) {
574    test(&test_instance);
575  } else {
576    puts("warning: wrong processor count to run the test");
577  }
578
579  TEST_END();
580  rtems_test_exit(0);
581}
582
583#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
584#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
585
586#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
587
588#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
589
590#define CONFIGURE_MAXIMUM_TASKS 4
591
592#define CONFIGURE_INIT_TASK_PRIORITY PRIO_MIDDLE
593
594#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
595
596#define CONFIGURE_SCHEDULER_EDF_SMP
597
598#include <rtems/scheduler.h>
599
600RTEMS_SCHEDULER_EDF_SMP(a, CONFIGURE_MAXIMUM_PROCESSORS);
601
602RTEMS_SCHEDULER_EDF_SMP(b, CONFIGURE_MAXIMUM_PROCESSORS);
603
604#define CONFIGURE_SCHEDULER_TABLE_ENTRIES \
605  RTEMS_SCHEDULER_TABLE_EDF_SMP(a, SCHED_A), \
606  RTEMS_SCHEDULER_TABLE_EDF_SMP(b, SCHED_B)  \
607
608#define CONFIGURE_SCHEDULER_ASSIGNMENTS \
609  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
610  RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
611
612#define CONFIGURE_INIT
613
614#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.