source: rtems/testsuites/sptests/sp37/init.c @ cdf30f05

4.115
Last change on this file since cdf30f05 was cdf30f05, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 19, 2015 at 12:57:44 PM

rtems: Add rtems_interrupt_local_disable|enable()

Add rtems_interrupt_local_disable|enable() as suggested by Pavel Pisa to
emphasize that interrupts are only disabled on the current processor.
Do not define the rtems_interrupt_disable|enable|flash() macros and
functions on SMP configurations since they don't ensure system wide
mutual exclusion.

  • Property mode set to 100644
File size: 16.3 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.ticket_lock.Stats.name )
165    + sizeof( ((ISR_lock_Control *) 0)->Lock.ticket_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;
442  rtems_mode            level_mode_body;
443  rtems_mode            level_mode_macro;
444  bool                  in_isr;
445
446  puts( "interrupt disable (use body)" );
447  level = rtems_interrupt_disable();
448
449  puts( "interrupt disable (use body)" );
450  level = rtems_interrupt_disable();
451
452  puts( "interrupt flash (use body)" );
453  rtems_interrupt_flash( level );
454
455  puts( "interrupt enable (use body)" );
456  rtems_interrupt_enable( level );
457
458  puts( "interrupt level mode (use body)" );
459  level_mode_body = rtems_interrupt_level_body( level );
460  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
461  if ( level_mode_macro == level_mode_body ) {
462    puts("test seems to work");
463  }
464
465  /*
466   *  Test interrupt bodies
467   */
468  puts( "interrupt is in progress (use body)" );
469  in_isr = rtems_interrupt_is_in_progress();
470  if ( in_isr ) {
471    puts( "interrupt reported to be is in progress (body)" );
472    rtems_test_exit( 0 );
473  }
474#endif /* RTEMS_SMP */
475}
476
477rtems_timer_service_routine test_isr_in_progress(
478  rtems_id  timer,
479  void     *arg
480)
481{
482  check_isr_in_progress_inline();
483
484  isr_in_progress_body = rtems_interrupt_is_in_progress() ? 1 : 2;
485}
486
487rtems_task Init(
488  rtems_task_argument argument
489)
490{
491  rtems_time_of_day     time;
492  rtems_status_code     status;
493  rtems_id              timer;
494  int                   i;
495
496  TEST_BEGIN();
497
498  test_isr_level();
499  test_isr_locks();
500  test_interrupt_locks();
501
502  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
503  status = rtems_clock_set( &time );
504  directive_failed( status, "rtems_clock_set" );
505
506  /*
507   *  Timer used in multiple ways
508   */
509  status = rtems_timer_create( 1, &timer );
510  directive_failed( status, "rtems_timer_create" );
511
512  /*
513   *  Test clock tick from outside ISR
514   */
515  status = rtems_clock_tick();
516  directive_failed( status, "rtems_clock_tick" );
517  puts( "clock_tick from task level" );
518
519  test_clock_tick_functions();
520
521  /*
522   *  Now do a dispatch directly out of a clock tick that is
523   *  called from a task.  We need to create a task that will
524   *  block so we have one to unblock.  Then we schedule a TSR
525   *  to run in the clock tick but it has to be careful to
526   *  make sure it is not called from an ISR and that the
527   *  dispatching critical section is managed properly to
528   *  make the dispatch happen.
529   */
530
531  blocked_task_status = -1;
532
533  status = rtems_task_create(
534    rtems_build_name( 'T', 'A', '1', ' ' ),
535    1,
536    RTEMS_MINIMUM_STACK_SIZE,
537    RTEMS_DEFAULT_MODES,
538    RTEMS_DEFAULT_ATTRIBUTES,
539    &blocked_task_id
540  );
541  directive_failed( status, "rtems_task_create" );
542
543  status = rtems_task_start( blocked_task_id, blocked_task, 0 );
544  directive_failed( status, "rtems_task_start" );
545
546  status = rtems_task_wake_after( 10 );
547  directive_failed( status, "rtems_task_wake_after" );
548
549  status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
550  directive_failed( status, "timer_fire_after failed" );
551
552  /* we expect to be preempted from this call */
553  for ( i=0 ; i<100 && blocked_task_status != 3 ; i++ ) {
554    status = rtems_clock_tick();
555    directive_failed( status, "rtems_clock_tick" );
556  }
557  switch ( blocked_task_status ) {
558     case -1:
559       puts(
560         "clock_tick with task preempt -- task blocked, timer did not fire"
561       );
562       rtems_test_exit(0);
563       break;
564     case 1:
565       puts( "clock_tick with task preempt -- timer fired case 1" );
566       rtems_test_exit(0);
567       break;
568     case 2:
569       puts( "clock_tick with task preempt -- timer fired case 2" );
570       rtems_test_exit(0);
571       break;
572     case 3:
573       puts( "clock_tick from task level with preempt -- OK" );
574       break;
575  }
576
577  test_interrupt_inline();
578  test_interrupt_body();
579
580  /*
581   * Test ISR in progress from actual ISR
582   */
583  status = rtems_timer_fire_after( timer, 10, test_isr_in_progress, NULL );
584  directive_failed( status, "timer_fire_after failed" );
585
586  status = rtems_task_wake_after( 11 );
587  directive_failed( status, "wake_after failed" );
588
589  check_isr_worked( "inline", isr_in_progress_inline );
590
591  check_isr_worked( "body", isr_in_progress_body );
592
593  TEST_END();
594  rtems_test_exit( 0 );
595}
Note: See TracBrowser for help on using the repository browser.