source: rtems/testsuites/sptests/sp37/init.c @ 9907dde

4.115
Last change on this file since 9907dde was 96ec8ee8, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 22, 2014 at 3:09:36 PM

rtems: Add more clock tick functions

Add rtems_clock_tick_later(), rtems_clock_tick_later_usec() and
rtems_clock_tick_before().

  • Property mode set to 100644
File size: 15.8 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_Release_and_ISR_enable( &lock, &lock_context );
183
184  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
185
186  _ISR_lock_Acquire( &lock, &lock_context );
187  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
188  _ISR_lock_Release( &lock, &lock_context );
189
190  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
191
192  _ISR_lock_Destroy( &lock );
193  _ISR_lock_Destroy( &initialized );
194}
195
196static rtems_mode get_interrupt_level( void )
197{
198  rtems_status_code sc;
199  rtems_mode mode;
200
201  sc = rtems_task_mode( RTEMS_CURRENT_MODE, RTEMS_CURRENT_MODE, &mode );
202  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
203
204  return mode & RTEMS_INTERRUPT_MASK;
205}
206
207static void test_interrupt_locks( void )
208{
209  rtems_mode normal_interrupt_level = get_interrupt_level();
210  rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER("test");
211  rtems_interrupt_lock lock;
212  rtems_interrupt_lock_context lock_context;
213
214  rtems_interrupt_lock_initialize( &lock, "test" );
215  rtems_test_assert( memcmp( &lock, &initialized, lock_size ) == 0 );
216
217  rtems_interrupt_lock_acquire( &lock, &lock_context );
218  rtems_test_assert( normal_interrupt_level != get_interrupt_level() );
219  rtems_interrupt_lock_release( &lock, &lock_context );
220
221  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
222
223  rtems_interrupt_lock_acquire_isr( &lock, &lock_context );
224  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
225  rtems_interrupt_lock_release_isr( &lock, &lock_context );
226
227  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
228
229  rtems_interrupt_lock_destroy( &lock );
230  rtems_interrupt_lock_destroy( &initialized );
231}
232
233static void test_clock_tick_functions( void )
234{
235  rtems_interrupt_level level;
236  Watchdog_Interval saved_ticks;
237
238  _Thread_Disable_dispatch();
239  rtems_interrupt_disable( level );
240
241  saved_ticks = _Watchdog_Ticks_since_boot;
242
243  _Watchdog_Ticks_since_boot = 0xdeadbeef;
244  rtems_test_assert( rtems_clock_get_ticks_since_boot() == 0xdeadbeef );
245
246  rtems_test_assert( rtems_clock_tick_later( 0 ) == 0xdeadbeef );
247  rtems_test_assert( rtems_clock_tick_later( 0x8160311e ) == 0x600df00d );
248
249  _Watchdog_Ticks_since_boot = 0;
250  rtems_test_assert( rtems_clock_tick_later_usec( 0 ) == 1 );
251  rtems_test_assert( rtems_clock_tick_later_usec( 1 ) == 2 );
252  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK ) == 2 );
253  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK + 1 ) == 3 );
254
255  _Watchdog_Ticks_since_boot = 0;
256  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
257  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
258  rtems_test_assert( rtems_clock_tick_before( 1 ) );
259
260  _Watchdog_Ticks_since_boot = 1;
261  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
262  rtems_test_assert( !rtems_clock_tick_before( 1 ) );
263  rtems_test_assert( rtems_clock_tick_before( 2 ) );
264
265  _Watchdog_Ticks_since_boot = 0x7fffffff;
266  rtems_test_assert( !rtems_clock_tick_before( 0x7ffffffe ) );
267  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
268  rtems_test_assert( rtems_clock_tick_before( 0x80000000 ) );
269
270  _Watchdog_Ticks_since_boot = 0x80000000;
271  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
272  rtems_test_assert( !rtems_clock_tick_before( 0x80000000 ) );
273  rtems_test_assert( rtems_clock_tick_before( 0x80000001 ) );
274
275  _Watchdog_Ticks_since_boot = 0xffffffff;
276  rtems_test_assert( !rtems_clock_tick_before( 0xfffffffe ) );
277  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
278  rtems_test_assert( rtems_clock_tick_before( 0 ) );
279
280  _Watchdog_Ticks_since_boot = saved_ticks;
281
282  rtems_interrupt_enable( level );
283  _Thread_Enable_dispatch();
284}
285
286void test_interrupt_inline(void)
287{
288  rtems_interrupt_level level;
289  rtems_mode            level_mode_body;
290  rtems_mode            level_mode_macro;
291  bool                  in_isr;
292
293  puts( "interrupt is in progress (use body)" );
294  in_isr = rtems_interrupt_is_in_progress();
295  if ( in_isr ) {
296    puts( "interrupt reported to be is in progress (body)" );
297    rtems_test_exit( 0 );
298  }
299
300  puts( "interrupt disable (use inline)" );
301  _Thread_Disable_dispatch();
302  rtems_interrupt_disable( level );
303  _Thread_Enable_dispatch();
304
305  puts( "interrupt flash (use inline)" );
306  _Thread_Disable_dispatch();
307  rtems_interrupt_flash( level );
308  _Thread_Enable_dispatch();
309
310  puts( "interrupt enable (use inline)" );
311  _Thread_Disable_dispatch();
312  rtems_interrupt_enable( level );
313  _Thread_Enable_dispatch();
314
315  puts( "interrupt level mode (use inline)" );
316  level_mode_body = rtems_interrupt_level_body( level );
317  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
318  if ( level_mode_macro == level_mode_body ) {
319    puts( "test case working.." );
320  }
321}
322
323volatile int isr_in_progress_body;
324volatile int isr_in_progress_inline;
325
326void check_isr_in_progress_inline(void)
327{
328  bool in_isr;
329
330  in_isr = rtems_interrupt_is_in_progress();
331  isr_in_progress_inline = ( in_isr ) ? 1 : 2;
332}
333
334#undef rtems_interrupt_disable
335extern rtems_interrupt_level rtems_interrupt_disable(void);
336#undef rtems_interrupt_enable
337extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
338#undef rtems_interrupt_flash
339extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
340#undef rtems_interrupt_is_in_progress
341extern bool rtems_interrupt_is_in_progress(void);
342
343rtems_timer_service_routine test_isr_in_progress(
344  rtems_id  timer,
345  void     *arg
346)
347{
348  bool in_isr;
349
350  check_isr_in_progress_inline();
351
352  in_isr = rtems_interrupt_is_in_progress();
353  isr_in_progress_body = ( in_isr ) ? 1 : 2;
354}
355
356void check_isr_worked(
357  char *s,
358  int   result
359)
360{
361  switch (result) {
362    case -1:
363      printf( "isr_in_progress(%s) timer did not fire\n", s );
364      break;
365    case 1:
366      printf( "isr_in_progress(%s) from ISR -- OK\n", s );
367      break;
368    case 2:
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#if defined( RTEMS_SMP )
427  directive_failed_with_level( status, "rtems_task_resume", 1 );
428#else
429  directive_failed( status, "rtems_task_resume" );
430#endif
431}
432
433rtems_task Init(
434  rtems_task_argument argument
435)
436{
437  rtems_time_of_day     time;
438  rtems_status_code     status;
439  rtems_interrupt_level level;
440  rtems_mode            level_mode_body;
441  rtems_mode            level_mode_macro;
442  bool                  in_isr;
443  rtems_id              timer;
444  int                   i;
445
446  TEST_BEGIN();
447
448  test_isr_level();
449  test_isr_locks();
450  test_interrupt_locks();
451
452  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
453  status = rtems_clock_set( &time );
454  directive_failed( status, "rtems_clock_set" );
455
456  /*
457   *  Timer used in multiple ways
458   */
459  status = rtems_timer_create( 1, &timer );
460  directive_failed( status, "rtems_timer_create" );
461
462  /*
463   *  Test clock tick from outside ISR
464   */
465  status = rtems_clock_tick();
466  directive_failed( status, "rtems_clock_tick" );
467  puts( "clock_tick from task level" );
468
469  test_clock_tick_functions();
470
471  /*
472   *  Now do a dispatch directly out of a clock tick that is
473   *  called from a task.  We need to create a task that will
474   *  block so we have one to unblock.  Then we schedule a TSR
475   *  to run in the clock tick but it has to be careful to
476   *  make sure it is not called from an ISR and that the
477   *  dispatching critical section is managed properly to
478   *  make the dispatch happen.
479   */
480
481  blocked_task_status = -1;
482
483  status = rtems_task_create(
484    rtems_build_name( 'T', 'A', '1', ' ' ),
485    1,
486    RTEMS_MINIMUM_STACK_SIZE,
487    RTEMS_DEFAULT_MODES,
488    RTEMS_DEFAULT_ATTRIBUTES,
489    &blocked_task_id
490  );
491  directive_failed( status, "rtems_task_create" );
492
493  status = rtems_task_start( blocked_task_id, blocked_task, 0 );
494  directive_failed( status, "rtems_task_start" );
495
496  status = rtems_task_wake_after( 10 );
497  directive_failed( status, "rtems_task_wake_after" );
498
499  status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
500  directive_failed( status, "timer_fire_after failed" );
501
502  /* we expect to be preempted from this call */
503  for ( i=0 ; i<100 && blocked_task_status != 3 ; i++ ) {
504    status = rtems_clock_tick();
505    directive_failed( status, "rtems_clock_tick" );
506  }
507  switch ( blocked_task_status ) {
508     case -1:
509       puts(
510         "clock_tick with task preempt -- task blocked, timer did not fire"
511       );
512       rtems_test_exit(0);
513       break;
514     case 1:
515       puts( "clock_tick with task preempt -- timer fired case 1" );
516       rtems_test_exit(0);
517       break;
518     case 2:
519       puts( "clock_tick with task preempt -- timer fired case 2" );
520       rtems_test_exit(0);
521       break;
522     case 3:
523       puts( "clock_tick from task level with preempt -- OK" );
524       break;
525  }
526
527  /*
528   *  Test interrupt inline versions
529   */
530  test_interrupt_inline();
531
532  /*
533   *  Test interrupt bodies
534   */
535  puts( "interrupt is in progress (use body)" );
536  in_isr = rtems_interrupt_is_in_progress();
537  if ( in_isr ) {
538    puts( "interrupt reported to be is in progress (body)" );
539    rtems_test_exit( 0 );
540  }
541
542  puts( "interrupt disable (use body)" );
543  _Thread_Disable_dispatch();
544  level = rtems_interrupt_disable();
545  _Thread_Enable_dispatch();
546
547  puts( "interrupt disable (use body)" );
548  _Thread_Disable_dispatch();
549  level = rtems_interrupt_disable();
550  _Thread_Enable_dispatch();
551
552  puts( "interrupt flash (use body)" );
553  _Thread_Disable_dispatch();
554  rtems_interrupt_flash( level );
555  _Thread_Enable_dispatch();
556
557  puts( "interrupt enable (use body)" );
558  _Thread_Disable_dispatch();
559  rtems_interrupt_enable( level );
560  _Thread_Enable_dispatch();
561
562  puts( "interrupt level mode (use body)" );
563  level_mode_body = rtems_interrupt_level_body( level );
564  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
565  if ( level_mode_macro == level_mode_body ) {
566    puts("test seems to work");
567  }
568
569  /*
570   * Test ISR in progress from actual ISR
571   */
572  isr_in_progress_body   = -1;
573  isr_in_progress_inline = -1;
574
575  status = rtems_timer_fire_after( timer, 10, test_isr_in_progress, NULL );
576  directive_failed( status, "timer_fire_after failed" );
577
578  status = rtems_task_wake_after( 100 );
579  directive_failed( status, "wake_after failed" );
580
581  check_isr_worked( "inline", isr_in_progress_body );
582
583  check_isr_worked( "body", isr_in_progress_body );
584
585  TEST_END();
586  rtems_test_exit( 0 );
587}
Note: See TracBrowser for help on using the repository browser.