source: rtems/testsuites/sptests/sp37/init.c @ 3bd39999

5
Last change on this file since 3bd39999 was 3bd39999, checked in by Sebastian Huber <sebastian.huber@…>, on 01/08/19 at 08:53:26

Adjust interrupt mode tests for some CPU ports

In case the robust thread dispatch is enabled by the CPU port, then the
interrupt level must not be changed through the task mode.

Update #3000.

  • Property mode set to 100644
File size: 17.0 KB
Line 
1/**
2 *  @brief Test for Bodies of Macros
3 *
4 *  Interrupt Disable/Enable Tests
5 *  Clock Tick from task level
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2012.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#define CONFIGURE_INIT
22#include "system.h"
23
24const char rtems_test_name[] = "SP 37";
25
26/* prototypes */
27void test_interrupt_inline(void);
28void check_isr_in_progress_inline(void);
29rtems_task blocked_task(rtems_task_argument argument);
30rtems_timer_service_routine test_unblock_task(
31  rtems_id  timer,
32  void     *arg
33);
34rtems_timer_service_routine test_unblock_task(
35  rtems_id  timer,
36  void     *arg
37);
38void check_isr_worked(
39  char *s,
40  int   result
41);
42rtems_timer_service_routine test_isr_in_progress(
43  rtems_id  timer,
44  void     *arg
45);
46
47/* test bodies */
48
49#define TEST_ISR_EVENT RTEMS_EVENT_0
50
51typedef struct {
52  ISR_Level actual_level;
53  rtems_id master_task_id;
54} test_isr_level_context;
55
56static void isr_level_check_task( rtems_task_argument arg )
57{
58  test_isr_level_context *ctx = (test_isr_level_context *) arg;
59  rtems_status_code sc;
60
61  ctx->actual_level = _ISR_Get_level();
62
63  sc = rtems_event_send( ctx->master_task_id,  TEST_ISR_EVENT );
64  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
65
66  ( void ) rtems_task_suspend( RTEMS_SELF );
67  rtems_test_assert( 0 );
68}
69
70static void test_isr_level_for_new_threads( ISR_Level last_proper_level )
71{
72  ISR_Level mask = CPU_MODES_INTERRUPT_MASK;
73  ISR_Level current;
74  test_isr_level_context ctx = {
75    .master_task_id = rtems_task_self()
76  };
77
78  for ( current = 0 ; current <= mask ; ++current ) {
79    rtems_mode initial_modes;
80    rtems_id id;
81    rtems_status_code sc;
82    rtems_event_set events;
83
84    initial_modes = RTEMS_INTERRUPT_LEVEL(current);
85
86#if CPU_ENABLE_ROBUST_THREAD_DISPATCH == TRUE
87    if ( initial_modes != 0 ) {
88      break;
89    }
90#endif
91
92    ctx.actual_level = 0xffffffff;
93
94    sc = rtems_task_create(
95      rtems_build_name('I', 'S', 'R', 'L'),
96      RTEMS_MINIMUM_PRIORITY,
97      RTEMS_MINIMUM_STACK_SIZE,
98      initial_modes,
99      RTEMS_DEFAULT_ATTRIBUTES,
100      &id
101    );
102    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
103
104    sc = rtems_task_start(
105      id,
106      isr_level_check_task,
107      (rtems_task_argument) &ctx
108    );
109    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
110
111    sc = rtems_event_receive(
112      TEST_ISR_EVENT,
113      RTEMS_EVENT_ALL | RTEMS_WAIT,
114      RTEMS_NO_TIMEOUT,
115      &events
116    );
117    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
118    rtems_test_assert( events == TEST_ISR_EVENT );
119
120    if ( current <= last_proper_level ) {
121      rtems_test_assert( ctx.actual_level == current );
122    } else {
123      rtems_test_assert( ctx.actual_level == last_proper_level );
124    }
125
126    sc = rtems_task_delete( id ) ;
127    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
128  }
129}
130
131static void test_isr_level( void )
132{
133  ISR_Level mask = CPU_MODES_INTERRUPT_MASK;
134  ISR_Level normal = _ISR_Get_level();
135  ISR_Level current = 0;
136  ISR_Level last_proper_level;
137
138  _ISR_Set_level( current );
139  rtems_test_assert( _ISR_Get_level() == current );
140
141  for ( current = current + 1 ; current <= mask ; ++current ) {
142    ISR_Level actual;
143
144    _ISR_Set_level( current );
145
146    actual = _ISR_Get_level();
147    rtems_test_assert( actual == current || actual == ( current - 1 ) );
148
149    if ( _ISR_Get_level() != current ) {
150      break;
151    }
152  }
153
154  last_proper_level = current - 1;
155
156  for ( current = current + 1 ; current <= mask ; ++current ) {
157    _ISR_Set_level( current );
158    rtems_test_assert( _ISR_Get_level() == current );
159  }
160
161  _ISR_Set_level( normal );
162
163  /*
164   * Now test that the ISR level specified for _Thread_Initialize() propagates
165   * properly to the thread.
166   */
167  test_isr_level_for_new_threads( last_proper_level );
168}
169
170static void test_isr_locks( void )
171{
172  ISR_Level normal_interrupt_level = _ISR_Get_level();
173  ISR_lock_Control initialized = ISR_LOCK_INITIALIZER("test");
174  union {
175    ISR_lock_Control lock;
176    uint8_t bytes[ sizeof( ISR_lock_Control ) ];
177  } container;
178  ISR_lock_Context lock_context;
179  size_t i;
180  const uint8_t *initialized_bytes;
181
182  memset( &container, 0xff, sizeof( container ) );
183  _ISR_lock_Initialize( &container.lock, "test" );
184  initialized_bytes = (const uint8_t *) &initialized;
185
186  for ( i = 0; i < sizeof( container ); ++i ) {
187    if ( container.bytes[ i ] != 0xff ) {
188      rtems_test_assert( container.bytes[ i ] == initialized_bytes[ i] );
189    }
190  }
191
192  _ISR_lock_ISR_disable_and_acquire( &container.lock, &lock_context );
193  rtems_test_assert( normal_interrupt_level != _ISR_Get_level() );
194  _ISR_lock_Flash( &container.lock, &lock_context );
195  rtems_test_assert( normal_interrupt_level != _ISR_Get_level() );
196  _ISR_lock_Release_and_ISR_enable( &container.lock, &lock_context );
197
198  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
199
200  _ISR_lock_ISR_disable( &lock_context );
201  rtems_test_assert( normal_interrupt_level != _ISR_Get_level() );
202  _ISR_lock_ISR_enable( &lock_context );
203
204  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
205
206  _ISR_lock_Acquire( &container.lock, &lock_context );
207  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
208  _ISR_lock_Release( &container.lock, &lock_context );
209
210  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
211
212  _ISR_lock_Destroy( &container.lock );
213  _ISR_lock_Destroy( &initialized );
214}
215
216static rtems_mode get_interrupt_level( void )
217{
218  rtems_status_code sc;
219  rtems_mode mode;
220
221  sc = rtems_task_mode( RTEMS_CURRENT_MODE, RTEMS_CURRENT_MODE, &mode );
222  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
223
224  return mode & RTEMS_INTERRUPT_MASK;
225}
226
227static void test_interrupt_locks( void )
228{
229  rtems_mode normal_interrupt_level = get_interrupt_level();
230  rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER("test");
231  union {
232    rtems_interrupt_lock lock;
233    uint8_t bytes[ sizeof( rtems_interrupt_lock ) ];
234  } container;
235  rtems_interrupt_lock_context lock_context;
236  size_t i;
237  const uint8_t *initialized_bytes;
238
239  rtems_interrupt_lock_initialize( &container.lock, "test" );
240  initialized_bytes = (const uint8_t *) &initialized;
241
242  for ( i = 0; i < sizeof( container ); ++i ) {
243    if ( container.bytes[ i ] != 0xff ) {
244      rtems_test_assert( container.bytes[ i ] == initialized_bytes[ i] );
245    }
246  }
247
248  rtems_interrupt_lock_acquire( &container.lock, &lock_context );
249  rtems_test_assert( normal_interrupt_level != get_interrupt_level() );
250  rtems_interrupt_lock_release( &container.lock, &lock_context );
251
252  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
253
254  rtems_interrupt_lock_acquire_isr( &container.lock, &lock_context );
255  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
256  rtems_interrupt_lock_release_isr( &container.lock, &lock_context );
257
258  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
259
260  rtems_interrupt_lock_destroy( &container.lock );
261  rtems_interrupt_lock_destroy( &initialized );
262}
263
264static void test_clock_tick_functions( void )
265{
266  rtems_interrupt_level level;
267  Watchdog_Interval saved_ticks;
268
269  rtems_interrupt_local_disable( level );
270
271  saved_ticks = _Watchdog_Ticks_since_boot;
272
273  _Watchdog_Ticks_since_boot = 0xdeadbeef;
274  rtems_test_assert( rtems_clock_get_ticks_since_boot() == 0xdeadbeef );
275
276  rtems_test_assert( rtems_clock_tick_later( 0 ) == 0xdeadbeef );
277  rtems_test_assert( rtems_clock_tick_later( 0x8160311e ) == 0x600df00d );
278
279  _Watchdog_Ticks_since_boot = 0;
280  rtems_test_assert( rtems_clock_tick_later_usec( 0 ) == 1 );
281  rtems_test_assert( rtems_clock_tick_later_usec( 1 ) == 2 );
282  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK ) == 2 );
283  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK + 1 ) == 3 );
284
285  _Watchdog_Ticks_since_boot = 0;
286  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
287  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
288  rtems_test_assert( rtems_clock_tick_before( 1 ) );
289
290  _Watchdog_Ticks_since_boot = 1;
291  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
292  rtems_test_assert( !rtems_clock_tick_before( 1 ) );
293  rtems_test_assert( rtems_clock_tick_before( 2 ) );
294
295  _Watchdog_Ticks_since_boot = 0x7fffffff;
296  rtems_test_assert( !rtems_clock_tick_before( 0x7ffffffe ) );
297  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
298  rtems_test_assert( rtems_clock_tick_before( 0x80000000 ) );
299
300  _Watchdog_Ticks_since_boot = 0x80000000;
301  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
302  rtems_test_assert( !rtems_clock_tick_before( 0x80000000 ) );
303  rtems_test_assert( rtems_clock_tick_before( 0x80000001 ) );
304
305  _Watchdog_Ticks_since_boot = 0xffffffff;
306  rtems_test_assert( !rtems_clock_tick_before( 0xfffffffe ) );
307  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
308  rtems_test_assert( rtems_clock_tick_before( 0 ) );
309
310  _Watchdog_Ticks_since_boot = saved_ticks;
311
312  rtems_interrupt_local_enable( level );
313}
314
315void test_interrupt_inline(void)
316{
317  rtems_interrupt_level level;
318  rtems_interrupt_level level_1;
319  rtems_mode            level_mode_body;
320  rtems_mode            level_mode_macro;
321  bool                  in_isr;
322  uint32_t              isr_level_0;
323  uint32_t              isr_level_1;
324  uint32_t              isr_level_2;
325
326  puts( "interrupt is in progress (use body)" );
327  in_isr = rtems_interrupt_is_in_progress();
328  if ( in_isr ) {
329    puts( "interrupt reported to be is in progress (body)" );
330    rtems_test_exit( 0 );
331  }
332
333#if !defined(RTEMS_SMP)
334  puts( "interrupt disable (use inline)" );
335  rtems_interrupt_disable( level );
336
337  puts( "interrupt flash (use inline)" );
338  rtems_interrupt_flash( level );
339
340  puts( "interrupt enable (use inline)" );
341  rtems_interrupt_enable( level );
342#endif /* RTEMS_SMP */
343
344  isr_level_0 = _ISR_Get_level();
345  rtems_test_assert( isr_level_0 == 0 );
346
347  rtems_interrupt_local_disable( level );
348  isr_level_1 = _ISR_Get_level();
349  rtems_test_assert( isr_level_1 != isr_level_0 );
350  rtems_test_assert( _ISR_Is_enabled( level ) );
351
352  rtems_interrupt_local_disable( level_1 );
353  isr_level_2 = _ISR_Get_level();
354  rtems_test_assert( isr_level_2 == isr_level_1 );
355  rtems_test_assert( !_ISR_Is_enabled( level_1 ) );
356
357  rtems_interrupt_local_enable( level_1 );
358  rtems_test_assert( _ISR_Get_level() == isr_level_1 );
359
360  rtems_interrupt_local_enable( level );
361  rtems_test_assert( _ISR_Get_level() == isr_level_0 );
362
363  puts( "interrupt level mode (use inline)" );
364  level_mode_body = rtems_interrupt_level_body( level );
365  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
366  if ( level_mode_macro == level_mode_body ) {
367    puts( "test case working.." );
368  }
369}
370
371volatile int isr_in_progress_body;
372
373volatile int isr_in_progress_inline;
374
375void check_isr_in_progress_inline(void)
376{
377  isr_in_progress_inline = rtems_interrupt_is_in_progress() ? 1 : 2;
378}
379
380void check_isr_worked(
381  char *s,
382  int   result
383)
384{
385  switch (result) {
386    case 0:
387      printf( "isr_in_progress(%s) timer did not fire\n", s );
388      rtems_test_exit(0);
389      break;
390    case 1:
391      printf( "isr_in_progress(%s) from ISR -- OK\n", s );
392      break;
393    default:
394      printf( "isr_in_progress(%s) from ISR -- returned bad value\n", s);
395      rtems_test_exit(0);
396      break;
397  }
398}
399
400volatile int blocked_task_status;
401rtems_id     blocked_task_id;
402
403rtems_task blocked_task(
404  rtems_task_argument argument
405)
406{
407  rtems_status_code     status;
408
409  puts( "Blocking task... suspending self" );
410  blocked_task_status = 1;
411  status = rtems_task_suspend( RTEMS_SELF );
412  directive_failed( status, "rtems_task_suspend" );
413
414  blocked_task_status = 3;
415  rtems_task_exit();
416}
417
418/*
419 *  Timer Service Routine
420 *
421 *  If we are in an ISR, then this is a normal clock tick.
422 *  If we are not, then it is the test case.
423 */
424rtems_timer_service_routine test_unblock_task(
425  rtems_id  timer,
426  void     *arg
427)
428{
429  bool               in_isr;
430  rtems_status_code  status;
431  Per_CPU_Control   *cpu_self;
432
433  in_isr = rtems_interrupt_is_in_progress();
434  status = rtems_task_is_suspended( blocked_task_id );
435  if ( in_isr ) {
436    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
437    directive_failed( status, "timer_fire_after failed" );
438    return;
439  }
440
441  if ( (status != RTEMS_ALREADY_SUSPENDED) ) {
442    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
443    directive_failed( status, "timer_fire_after failed" );
444    return;
445  }
446
447  blocked_task_status = 2;
448  cpu_self = _Thread_Dispatch_disable();
449  status = rtems_task_resume( blocked_task_id );
450  _Thread_Dispatch_enable( cpu_self );
451  directive_failed( status, "rtems_task_resume" );
452}
453
454#undef rtems_interrupt_disable
455extern rtems_interrupt_level rtems_interrupt_disable(void);
456#undef rtems_interrupt_enable
457extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
458#undef rtems_interrupt_flash
459extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
460#undef rtems_interrupt_is_in_progress
461extern bool rtems_interrupt_is_in_progress(void);
462
463static void test_interrupt_body(void)
464{
465#if !defined(RTEMS_SMP)
466  rtems_interrupt_level level_0;
467  rtems_interrupt_level level_1;
468  rtems_mode            level_mode_body;
469  rtems_mode            level_mode_macro;
470  bool                  in_isr;
471
472  puts( "interrupt disable (use body)" );
473  level_0 = rtems_interrupt_disable();
474
475  puts( "interrupt disable (use body)" );
476  level_1 = rtems_interrupt_disable();
477
478  puts( "interrupt flash (use body)" );
479  rtems_interrupt_flash( level_1 );
480
481  puts( "interrupt enable (use body)" );
482  rtems_interrupt_enable( level_1 );
483
484  puts( "interrupt level mode (use body)" );
485  level_mode_body = rtems_interrupt_level_body( level_0 );
486  level_mode_macro = RTEMS_INTERRUPT_LEVEL( level_0 );
487  if ( level_mode_macro == level_mode_body ) {
488    puts("test seems to work");
489  }
490
491  /*
492   *  Test interrupt bodies
493   */
494  puts( "interrupt is in progress (use body)" );
495  in_isr = rtems_interrupt_is_in_progress();
496
497  puts( "interrupt enable (use body)" );
498  rtems_interrupt_enable( level_0 );
499
500  if ( in_isr ) {
501    puts( "interrupt reported to be is in progress (body)" );
502    rtems_test_exit( 0 );
503  }
504#endif /* RTEMS_SMP */
505}
506
507rtems_timer_service_routine test_isr_in_progress(
508  rtems_id  timer,
509  void     *arg
510)
511{
512  check_isr_in_progress_inline();
513
514  isr_in_progress_body = rtems_interrupt_is_in_progress() ? 1 : 2;
515}
516
517rtems_task Init(
518  rtems_task_argument argument
519)
520{
521  rtems_time_of_day     time;
522  rtems_status_code     status;
523  rtems_id              timer;
524  int                   i;
525
526  TEST_BEGIN();
527
528  test_isr_level();
529  test_isr_locks();
530  test_interrupt_locks();
531
532  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
533  status = rtems_clock_set( &time );
534  directive_failed( status, "rtems_clock_set" );
535
536  /*
537   *  Timer used in multiple ways
538   */
539  status = rtems_timer_create( 1, &timer );
540  directive_failed( status, "rtems_timer_create" );
541
542  /*
543   *  Test clock tick from outside ISR
544   */
545  status = rtems_clock_tick();
546  directive_failed( status, "rtems_clock_tick" );
547  puts( "clock_tick from task level" );
548
549  test_clock_tick_functions();
550
551  /*
552   *  Now do a dispatch directly out of a clock tick that is
553   *  called from a task.  We need to create a task that will
554   *  block so we have one to unblock.  Then we schedule a TSR
555   *  to run in the clock tick but it has to be careful to
556   *  make sure it is not called from an ISR and that the
557   *  dispatching critical section is managed properly to
558   *  make the dispatch happen.
559   */
560
561  blocked_task_status = -1;
562
563  status = rtems_task_create(
564    rtems_build_name( 'T', 'A', '1', ' ' ),
565    1,
566    RTEMS_MINIMUM_STACK_SIZE,
567    RTEMS_DEFAULT_MODES,
568    RTEMS_DEFAULT_ATTRIBUTES,
569    &blocked_task_id
570  );
571  directive_failed( status, "rtems_task_create" );
572
573  status = rtems_task_start( blocked_task_id, blocked_task, 0 );
574  directive_failed( status, "rtems_task_start" );
575
576  status = rtems_task_wake_after( 10 );
577  directive_failed( status, "rtems_task_wake_after" );
578
579  status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
580  directive_failed( status, "timer_fire_after failed" );
581
582  /* we expect to be preempted from this call */
583  for ( i=0 ; i<100 && blocked_task_status != 3 ; i++ ) {
584    status = rtems_clock_tick();
585    directive_failed( status, "rtems_clock_tick" );
586  }
587  switch ( blocked_task_status ) {
588     case -1:
589       puts(
590         "clock_tick with task preempt -- task blocked, timer did not fire"
591       );
592       rtems_test_exit(0);
593       break;
594     case 1:
595       puts( "clock_tick with task preempt -- timer fired case 1" );
596       rtems_test_exit(0);
597       break;
598     case 2:
599       puts( "clock_tick with task preempt -- timer fired case 2" );
600       rtems_test_exit(0);
601       break;
602     case 3:
603       puts( "clock_tick from task level with preempt -- OK" );
604       break;
605  }
606
607  test_interrupt_inline();
608  test_interrupt_body();
609
610  /*
611   * Test ISR in progress from actual ISR
612   */
613  status = rtems_timer_fire_after( timer, 10, test_isr_in_progress, NULL );
614  directive_failed( status, "timer_fire_after failed" );
615
616  status = rtems_task_wake_after( 11 );
617  directive_failed( status, "wake_after failed" );
618
619  check_isr_worked( "inline", isr_in_progress_inline );
620
621  check_isr_worked( "body", isr_in_progress_body );
622
623  TEST_END();
624  rtems_test_exit( 0 );
625}
Note: See TracBrowser for help on using the repository browser.