source: rtems/testsuites/sptests/sp37/init.c @ 1cfe012

4.115
Last change on this file since 1cfe012 was 80f376d, checked in by Sebastian Huber <sebastian.huber@…>, on 05/06/15 at 12:25:09

score: Remove Giant lock in rtems_clock_tick()

Update #2307.

  • Property mode set to 100644
File size: 16.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 = 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  _Thread_Disable_dispatch();
247  rtems_interrupt_disable( level );
248
249  saved_ticks = _Watchdog_Ticks_since_boot;
250
251  _Watchdog_Ticks_since_boot = 0xdeadbeef;
252  rtems_test_assert( rtems_clock_get_ticks_since_boot() == 0xdeadbeef );
253
254  rtems_test_assert( rtems_clock_tick_later( 0 ) == 0xdeadbeef );
255  rtems_test_assert( rtems_clock_tick_later( 0x8160311e ) == 0x600df00d );
256
257  _Watchdog_Ticks_since_boot = 0;
258  rtems_test_assert( rtems_clock_tick_later_usec( 0 ) == 1 );
259  rtems_test_assert( rtems_clock_tick_later_usec( 1 ) == 2 );
260  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK ) == 2 );
261  rtems_test_assert( rtems_clock_tick_later_usec( US_PER_TICK + 1 ) == 3 );
262
263  _Watchdog_Ticks_since_boot = 0;
264  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
265  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
266  rtems_test_assert( rtems_clock_tick_before( 1 ) );
267
268  _Watchdog_Ticks_since_boot = 1;
269  rtems_test_assert( !rtems_clock_tick_before( 0 ) );
270  rtems_test_assert( !rtems_clock_tick_before( 1 ) );
271  rtems_test_assert( rtems_clock_tick_before( 2 ) );
272
273  _Watchdog_Ticks_since_boot = 0x7fffffff;
274  rtems_test_assert( !rtems_clock_tick_before( 0x7ffffffe ) );
275  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
276  rtems_test_assert( rtems_clock_tick_before( 0x80000000 ) );
277
278  _Watchdog_Ticks_since_boot = 0x80000000;
279  rtems_test_assert( !rtems_clock_tick_before( 0x7fffffff ) );
280  rtems_test_assert( !rtems_clock_tick_before( 0x80000000 ) );
281  rtems_test_assert( rtems_clock_tick_before( 0x80000001 ) );
282
283  _Watchdog_Ticks_since_boot = 0xffffffff;
284  rtems_test_assert( !rtems_clock_tick_before( 0xfffffffe ) );
285  rtems_test_assert( !rtems_clock_tick_before( 0xffffffff ) );
286  rtems_test_assert( rtems_clock_tick_before( 0 ) );
287
288  _Watchdog_Ticks_since_boot = saved_ticks;
289
290  rtems_interrupt_enable( level );
291  _Thread_Enable_dispatch();
292}
293
294void test_interrupt_inline(void)
295{
296  rtems_interrupt_level level;
297  rtems_mode            level_mode_body;
298  rtems_mode            level_mode_macro;
299  bool                  in_isr;
300
301  puts( "interrupt is in progress (use body)" );
302  in_isr = rtems_interrupt_is_in_progress();
303  if ( in_isr ) {
304    puts( "interrupt reported to be is in progress (body)" );
305    rtems_test_exit( 0 );
306  }
307
308  puts( "interrupt disable (use inline)" );
309  _Thread_Disable_dispatch();
310  rtems_interrupt_disable( level );
311  _Thread_Enable_dispatch();
312
313  puts( "interrupt flash (use inline)" );
314  _Thread_Disable_dispatch();
315  rtems_interrupt_flash( level );
316  _Thread_Enable_dispatch();
317
318  puts( "interrupt enable (use inline)" );
319  _Thread_Disable_dispatch();
320  rtems_interrupt_enable( level );
321  _Thread_Enable_dispatch();
322
323  puts( "interrupt level mode (use inline)" );
324  level_mode_body = rtems_interrupt_level_body( level );
325  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
326  if ( level_mode_macro == level_mode_body ) {
327    puts( "test case working.." );
328  }
329}
330
331volatile int isr_in_progress_body;
332volatile int isr_in_progress_inline;
333
334void check_isr_in_progress_inline(void)
335{
336  bool in_isr;
337
338  in_isr = rtems_interrupt_is_in_progress();
339  isr_in_progress_inline = ( in_isr ) ? 1 : 2;
340}
341
342#undef rtems_interrupt_disable
343extern rtems_interrupt_level rtems_interrupt_disable(void);
344#undef rtems_interrupt_enable
345extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
346#undef rtems_interrupt_flash
347extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
348#undef rtems_interrupt_is_in_progress
349extern bool rtems_interrupt_is_in_progress(void);
350
351rtems_timer_service_routine test_isr_in_progress(
352  rtems_id  timer,
353  void     *arg
354)
355{
356  bool in_isr;
357
358  check_isr_in_progress_inline();
359
360  in_isr = rtems_interrupt_is_in_progress();
361  isr_in_progress_body = ( in_isr ) ? 1 : 2;
362}
363
364void check_isr_worked(
365  char *s,
366  int   result
367)
368{
369  switch (result) {
370    case -1:
371      printf( "isr_in_progress(%s) timer did not fire\n", s );
372      break;
373    case 1:
374      printf( "isr_in_progress(%s) from ISR -- OK\n", s );
375      break;
376    case 2:
377      printf( "isr_in_progress(%s) from ISR -- returned bad value\n", s);
378      rtems_test_exit(0);
379      break;
380  }
381}
382
383volatile int blocked_task_status;
384rtems_id     blocked_task_id;
385
386rtems_task blocked_task(
387  rtems_task_argument argument
388)
389{
390  rtems_status_code     status;
391
392  puts( "Blocking task... suspending self" );
393  blocked_task_status = 1;
394  status = rtems_task_suspend( RTEMS_SELF );
395  directive_failed( status, "rtems_task_suspend" );
396
397  blocked_task_status = 3;
398  status = rtems_task_delete( RTEMS_SELF );
399  directive_failed( status, "rtems_task_delete" );
400}
401
402/*
403 *  Timer Service Routine
404 *
405 *  If we are in an ISR, then this is a normal clock tick.
406 *  If we are not, then it is the test case.
407 */
408rtems_timer_service_routine test_unblock_task(
409  rtems_id  timer,
410  void     *arg
411)
412{
413  bool              in_isr;
414  rtems_status_code status;
415
416  in_isr = rtems_interrupt_is_in_progress();
417  status = rtems_task_is_suspended( blocked_task_id );
418  if ( in_isr ) {
419    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
420    directive_failed( status, "timer_fire_after failed" );
421    return;
422  }
423
424  if ( (status != RTEMS_ALREADY_SUSPENDED) ) {
425    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
426    directive_failed( status, "timer_fire_after failed" );
427    return;
428  }
429
430  blocked_task_status = 2;
431  _Thread_Disable_dispatch();
432  status = rtems_task_resume( blocked_task_id );
433  _Thread_Unnest_dispatch();
434  directive_failed( status, "rtems_task_resume" );
435}
436
437rtems_task Init(
438  rtems_task_argument argument
439)
440{
441  rtems_time_of_day     time;
442  rtems_status_code     status;
443  rtems_interrupt_level level;
444  rtems_mode            level_mode_body;
445  rtems_mode            level_mode_macro;
446  bool                  in_isr;
447  rtems_id              timer;
448  int                   i;
449
450  TEST_BEGIN();
451
452  test_isr_level();
453  test_isr_locks();
454  test_interrupt_locks();
455
456  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
457  status = rtems_clock_set( &time );
458  directive_failed( status, "rtems_clock_set" );
459
460  /*
461   *  Timer used in multiple ways
462   */
463  status = rtems_timer_create( 1, &timer );
464  directive_failed( status, "rtems_timer_create" );
465
466  /*
467   *  Test clock tick from outside ISR
468   */
469  status = rtems_clock_tick();
470  directive_failed( status, "rtems_clock_tick" );
471  puts( "clock_tick from task level" );
472
473  test_clock_tick_functions();
474
475  /*
476   *  Now do a dispatch directly out of a clock tick that is
477   *  called from a task.  We need to create a task that will
478   *  block so we have one to unblock.  Then we schedule a TSR
479   *  to run in the clock tick but it has to be careful to
480   *  make sure it is not called from an ISR and that the
481   *  dispatching critical section is managed properly to
482   *  make the dispatch happen.
483   */
484
485  blocked_task_status = -1;
486
487  status = rtems_task_create(
488    rtems_build_name( 'T', 'A', '1', ' ' ),
489    1,
490    RTEMS_MINIMUM_STACK_SIZE,
491    RTEMS_DEFAULT_MODES,
492    RTEMS_DEFAULT_ATTRIBUTES,
493    &blocked_task_id
494  );
495  directive_failed( status, "rtems_task_create" );
496
497  status = rtems_task_start( blocked_task_id, blocked_task, 0 );
498  directive_failed( status, "rtems_task_start" );
499
500  status = rtems_task_wake_after( 10 );
501  directive_failed( status, "rtems_task_wake_after" );
502
503  status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
504  directive_failed( status, "timer_fire_after failed" );
505
506  /* we expect to be preempted from this call */
507  for ( i=0 ; i<100 && blocked_task_status != 3 ; i++ ) {
508    status = rtems_clock_tick();
509    directive_failed( status, "rtems_clock_tick" );
510  }
511  switch ( blocked_task_status ) {
512     case -1:
513       puts(
514         "clock_tick with task preempt -- task blocked, timer did not fire"
515       );
516       rtems_test_exit(0);
517       break;
518     case 1:
519       puts( "clock_tick with task preempt -- timer fired case 1" );
520       rtems_test_exit(0);
521       break;
522     case 2:
523       puts( "clock_tick with task preempt -- timer fired case 2" );
524       rtems_test_exit(0);
525       break;
526     case 3:
527       puts( "clock_tick from task level with preempt -- OK" );
528       break;
529  }
530
531  /*
532   *  Test interrupt inline versions
533   */
534  test_interrupt_inline();
535
536  /*
537   *  Test interrupt bodies
538   */
539  puts( "interrupt is in progress (use body)" );
540  in_isr = rtems_interrupt_is_in_progress();
541  if ( in_isr ) {
542    puts( "interrupt reported to be is in progress (body)" );
543    rtems_test_exit( 0 );
544  }
545
546  puts( "interrupt disable (use body)" );
547  _Thread_Disable_dispatch();
548  level = rtems_interrupt_disable();
549  _Thread_Enable_dispatch();
550
551  puts( "interrupt disable (use body)" );
552  _Thread_Disable_dispatch();
553  level = rtems_interrupt_disable();
554  _Thread_Enable_dispatch();
555
556  puts( "interrupt flash (use body)" );
557  _Thread_Disable_dispatch();
558  rtems_interrupt_flash( level );
559  _Thread_Enable_dispatch();
560
561  puts( "interrupt enable (use body)" );
562  _Thread_Disable_dispatch();
563  rtems_interrupt_enable( level );
564  _Thread_Enable_dispatch();
565
566  puts( "interrupt level mode (use body)" );
567  level_mode_body = rtems_interrupt_level_body( level );
568  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
569  if ( level_mode_macro == level_mode_body ) {
570    puts("test seems to work");
571  }
572
573  /*
574   * Test ISR in progress from actual ISR
575   */
576  isr_in_progress_body   = -1;
577  isr_in_progress_inline = -1;
578
579  status = rtems_timer_fire_after( timer, 10, test_isr_in_progress, NULL );
580  directive_failed( status, "timer_fire_after failed" );
581
582  status = rtems_task_wake_after( 100 );
583  directive_failed( status, "wake_after failed" );
584
585  check_isr_worked( "inline", isr_in_progress_body );
586
587  check_isr_worked( "body", isr_in_progress_body );
588
589  TEST_END();
590  rtems_test_exit( 0 );
591}
Note: See TracBrowser for help on using the repository browser.