source: rtems/testsuites/sptests/sp37/init.c @ 2e8c4ad

5
Last change on this file since 2e8c4ad was 2e8c4ad, checked in by Sebastian Huber <sebastian.huber@…>, on 01/18/16 at 08:07:55

sptests/sp37: Fix interrupt level usage

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