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

4.11
Last change on this file since d50acdbb was d50acdbb, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 10, 2014 at 7:25:32 AM

score: Add local context to SMP lock API

Add a local context structure to the SMP lock API for acquire and
release pairs. This context can be used to store the ISR level and
profiling information. It may be later used to enable more
sophisticated lock algorithms, e.g. MCS locks.

There is only one lock that cannot be used with a local context. This
is the per-CPU lock since here we would have to transfer the local
context through a context switch which is very complicated.

  • Property mode set to 100644
File size: 13.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.com/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
24/* prototypes */
25void test_interrupt_inline(void);
26void check_isr_in_progress_inline(void);
27rtems_task blocked_task(rtems_task_argument argument);
28rtems_timer_service_routine test_unblock_task(
29  rtems_id  timer,
30  void     *arg
31);
32rtems_timer_service_routine test_unblock_task(
33  rtems_id  timer,
34  void     *arg
35);
36void check_isr_worked(
37  char *s,
38  int   result
39);
40rtems_timer_service_routine test_isr_in_progress(
41  rtems_id  timer,
42  void     *arg
43);
44
45/* test bodies */
46
47#define TEST_ISR_EVENT RTEMS_EVENT_0
48
49typedef struct {
50  ISR_Level actual_level;
51  rtems_id master_task_id;
52} test_isr_level_context;
53
54static void isr_level_check_task( rtems_task_argument arg )
55{
56  test_isr_level_context *ctx = (test_isr_level_context *) arg;
57  rtems_status_code sc;
58
59  ctx->actual_level = _ISR_Get_level();
60
61  sc = rtems_event_send( ctx->master_task_id,  TEST_ISR_EVENT );
62  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
63
64  ( void ) rtems_task_suspend( RTEMS_SELF );
65  rtems_test_assert( 0 );
66}
67
68static void test_isr_level_for_new_threads( ISR_Level last_proper_level )
69{
70  ISR_Level mask = CPU_MODES_INTERRUPT_MASK;
71  ISR_Level current;
72  test_isr_level_context ctx = {
73    .master_task_id = rtems_task_self()
74  };
75
76  for ( current = 0 ; current <= mask ; ++current ) {
77    rtems_mode initial_modes = RTEMS_INTERRUPT_LEVEL(current);
78    rtems_id id;
79    rtems_status_code sc;
80    rtems_event_set events;
81
82    ctx.actual_level = 0xffffffff;
83
84    sc = rtems_task_create(
85      rtems_build_name('I', 'S', 'R', 'L'),
86      RTEMS_MINIMUM_PRIORITY,
87      RTEMS_MINIMUM_STACK_SIZE,
88      initial_modes,
89      RTEMS_DEFAULT_ATTRIBUTES,
90      &id
91    );
92    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
93
94    sc = rtems_task_start(
95      id,
96      isr_level_check_task,
97      (rtems_task_argument) &ctx
98    );
99    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
100
101    sc = rtems_event_receive(
102      TEST_ISR_EVENT,
103      RTEMS_EVENT_ALL | RTEMS_WAIT,
104      RTEMS_NO_TIMEOUT,
105      &events
106    );
107    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
108    rtems_test_assert( events == TEST_ISR_EVENT );
109
110    if ( current <= last_proper_level ) {
111      rtems_test_assert( ctx.actual_level == current );
112    } else {
113      rtems_test_assert( ctx.actual_level == last_proper_level );
114    }
115
116    sc = rtems_task_delete( id ) ;
117    rtems_test_assert( sc == RTEMS_SUCCESSFUL );
118  }
119}
120
121static void test_isr_level( void )
122{
123  ISR_Level mask = CPU_MODES_INTERRUPT_MASK;
124  ISR_Level normal = _ISR_Get_level();
125  ISR_Level current = 0;
126  ISR_Level last_proper_level;
127
128  _ISR_Set_level( current );
129  rtems_test_assert( _ISR_Get_level() == current );
130
131  for ( current = current + 1 ; current <= mask ; ++current ) {
132    ISR_Level actual;
133
134    _ISR_Set_level( current );
135
136    actual = _ISR_Get_level();
137    rtems_test_assert( actual == current || actual == ( current - 1 ) );
138
139    if ( _ISR_Get_level() != current ) {
140      break;
141    }
142  }
143
144  last_proper_level = current - 1;
145
146  for ( current = current + 1 ; current <= mask ; ++current ) {
147    _ISR_Set_level( current );
148    rtems_test_assert( _ISR_Get_level() == current );
149  }
150
151  _ISR_Set_level( normal );
152
153  /*
154   * Now test that the ISR level specified for _Thread_Initialize() propagates
155   * properly to the thread.
156   */
157  test_isr_level_for_new_threads( last_proper_level );
158}
159
160static void test_isr_locks( void )
161{
162  ISR_Level normal_interrupt_level = _ISR_Get_level();
163  ISR_lock_Control initialized = ISR_LOCK_INITIALIZER;
164  ISR_lock_Control lock;
165  ISR_lock_Context lock_context;
166
167  _ISR_lock_Initialize( &lock );
168  rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 );
169
170  _ISR_lock_ISR_disable_and_acquire( &lock, &lock_context );
171  rtems_test_assert( normal_interrupt_level != _ISR_Get_level() );
172  _ISR_lock_Release_and_ISR_enable( &lock, &lock_context );
173
174  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
175
176  _ISR_lock_Acquire( &lock, &lock_context );
177  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
178  _ISR_lock_Release( &lock, &lock_context );
179
180  rtems_test_assert( normal_interrupt_level == _ISR_Get_level() );
181}
182
183static rtems_mode get_interrupt_level( void )
184{
185  rtems_status_code sc;
186  rtems_mode mode;
187
188  sc = rtems_task_mode( RTEMS_CURRENT_MODE, RTEMS_CURRENT_MODE, &mode );
189  rtems_test_assert( sc == RTEMS_SUCCESSFUL );
190
191  return mode & RTEMS_INTERRUPT_MASK;
192}
193
194static void test_interrupt_locks( void )
195{
196  rtems_mode normal_interrupt_level = get_interrupt_level();
197  rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER;
198  rtems_interrupt_lock lock;
199  rtems_interrupt_lock_context lock_context;
200
201  rtems_interrupt_lock_initialize( &lock );
202  rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 );
203
204  rtems_interrupt_lock_acquire( &lock, &lock_context );
205  rtems_test_assert( normal_interrupt_level != get_interrupt_level() );
206  rtems_interrupt_lock_release( &lock, &lock_context );
207
208  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
209
210  rtems_interrupt_lock_acquire_isr( &lock, &lock_context );
211  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
212  rtems_interrupt_lock_release_isr( &lock, &lock_context );
213
214  rtems_test_assert( normal_interrupt_level == get_interrupt_level() );
215}
216
217void test_interrupt_inline(void)
218{
219  rtems_interrupt_level level;
220  rtems_mode            level_mode_body;
221  rtems_mode            level_mode_macro;
222  bool                  in_isr;
223
224  puts( "interrupt is in progress (use body)" );
225  in_isr = rtems_interrupt_is_in_progress();
226  if ( in_isr ) {
227    puts( "interrupt reported to be is in progress (body)" );
228    rtems_test_exit( 0 );
229  }
230
231  puts( "interrupt disable (use inline)" );
232  _Thread_Disable_dispatch();
233  rtems_interrupt_disable( level );
234  _Thread_Enable_dispatch();
235
236  puts( "interrupt flash (use inline)" );
237  _Thread_Disable_dispatch();
238  rtems_interrupt_flash( level );
239  _Thread_Enable_dispatch();
240
241  puts( "interrupt enable (use inline)" );
242  _Thread_Disable_dispatch();
243  rtems_interrupt_enable( level );
244  _Thread_Enable_dispatch();
245
246  puts( "interrupt level mode (use inline)" );
247  level_mode_body = rtems_interrupt_level_body( level );
248  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
249  if ( level_mode_macro == level_mode_body ) {
250    puts( "test case working.." );
251  }
252}
253
254volatile int isr_in_progress_body;
255volatile int isr_in_progress_inline;
256
257void check_isr_in_progress_inline(void)
258{
259  bool in_isr;
260
261  in_isr = rtems_interrupt_is_in_progress();
262  isr_in_progress_inline = ( in_isr ) ? 1 : 2;
263}
264
265#undef rtems_interrupt_disable
266extern rtems_interrupt_level rtems_interrupt_disable(void);
267#undef rtems_interrupt_enable
268extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
269#undef rtems_interrupt_flash
270extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
271#undef rtems_interrupt_is_in_progress
272extern bool rtems_interrupt_is_in_progress(void);
273
274rtems_timer_service_routine test_isr_in_progress(
275  rtems_id  timer,
276  void     *arg
277)
278{
279  bool in_isr;
280
281  check_isr_in_progress_inline();
282
283  in_isr = rtems_interrupt_is_in_progress();
284  isr_in_progress_body = ( in_isr ) ? 1 : 2;
285}
286
287void check_isr_worked(
288  char *s,
289  int   result
290)
291{
292  switch (result) {
293    case -1:
294      printf( "isr_in_progress(%s) timer did not fire\n", s );
295      break;
296    case 1:
297      printf( "isr_in_progress(%s) from ISR -- OK\n", s );
298      break;
299    case 2:
300      printf( "isr_in_progress(%s) from ISR -- returned bad value\n", s);
301      rtems_test_exit(0);
302      break;
303  }
304}
305
306volatile int blocked_task_status;
307rtems_id     blocked_task_id;
308
309rtems_task blocked_task(
310  rtems_task_argument argument
311)
312{
313  rtems_status_code     status;
314
315  puts( "Blocking task... suspending self" );
316  blocked_task_status = 1;
317  status = rtems_task_suspend( RTEMS_SELF );
318  directive_failed( status, "rtems_task_suspend" );
319
320  blocked_task_status = 3;
321  status = rtems_task_delete( RTEMS_SELF );
322  directive_failed( status, "rtems_task_delete" );
323}
324
325/*
326 *  Timer Service Routine
327 *
328 *  If we are in an ISR, then this is a normal clock tick.
329 *  If we are not, then it is the test case.
330 */
331rtems_timer_service_routine test_unblock_task(
332  rtems_id  timer,
333  void     *arg
334)
335{
336  bool              in_isr;
337  rtems_status_code status;
338
339  in_isr = rtems_interrupt_is_in_progress();
340  status = rtems_task_is_suspended( blocked_task_id );
341  if ( in_isr ) {
342    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
343    directive_failed( status, "timer_fire_after failed" );
344    return;
345  }
346
347  if ( (status != RTEMS_ALREADY_SUSPENDED) ) {
348    status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
349    directive_failed( status, "timer_fire_after failed" );
350    return;
351  }
352
353  blocked_task_status = 2;
354  _Thread_Disable_dispatch();
355  status = rtems_task_resume( blocked_task_id );
356  _Thread_Unnest_dispatch();
357#if defined( RTEMS_SMP )
358  directive_failed_with_level( status, "rtems_task_resume", 1 );
359#else
360  directive_failed( status, "rtems_task_resume" );
361#endif
362}
363
364rtems_task Init(
365  rtems_task_argument argument
366)
367{
368  rtems_time_of_day     time;
369  rtems_status_code     status;
370  rtems_interrupt_level level;
371  rtems_mode            level_mode_body;
372  rtems_mode            level_mode_macro;
373  bool                  in_isr;
374  rtems_id              timer;
375  int                   i;
376
377  puts( "\n\n*** TEST 37 ***" );
378
379  test_isr_level();
380  test_isr_locks();
381  test_interrupt_locks();
382
383  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
384  status = rtems_clock_set( &time );
385  directive_failed( status, "rtems_clock_set" );
386
387  /*
388   *  Timer used in multiple ways
389   */
390  status = rtems_timer_create( 1, &timer );
391  directive_failed( status, "rtems_timer_create" );
392
393  /*
394   *  Test clock tick from outside ISR
395   */
396  status = rtems_clock_tick();
397  directive_failed( status, "rtems_clock_tick" );
398  puts( "clock_tick from task level" );
399
400  /*
401   *  Now do a dispatch directly out of a clock tick that is
402   *  called from a task.  We need to create a task that will
403   *  block so we have one to unblock.  Then we schedule a TSR
404   *  to run in the clock tick but it has to be careful to
405   *  make sure it is not called from an ISR and that the
406   *  dispatching critical section is managed properly to
407   *  make the dispatch happen.
408   */
409
410  blocked_task_status = -1;
411
412  status = rtems_task_create(
413    rtems_build_name( 'T', 'A', '1', ' ' ),
414    1,
415    RTEMS_MINIMUM_STACK_SIZE,
416    RTEMS_DEFAULT_MODES,
417    RTEMS_DEFAULT_ATTRIBUTES,
418    &blocked_task_id
419  );
420  directive_failed( status, "rtems_task_create" );
421
422  status = rtems_task_start( blocked_task_id, blocked_task, 0 );
423  directive_failed( status, "rtems_task_start" );
424
425  status = rtems_task_wake_after( 10 );
426  directive_failed( status, "rtems_task_wake_after" );
427
428  status = rtems_timer_fire_after( timer, 1, test_unblock_task, NULL );
429  directive_failed( status, "timer_fire_after failed" );
430
431  /* we expect to be preempted from this call */
432  for ( i=0 ; i<100 && blocked_task_status != 3 ; i++ ) {
433    status = rtems_clock_tick();
434    directive_failed( status, "rtems_clock_tick" );
435  }
436  switch ( blocked_task_status ) {
437     case -1:
438       puts(
439         "clock_tick with task preempt -- task blocked, timer did not fire"
440       );
441       rtems_test_exit(0);
442       break;
443     case 1:
444       puts( "clock_tick with task preempt -- timer fired case 1" );
445       rtems_test_exit(0);
446       break;
447     case 2:
448       puts( "clock_tick with task preempt -- timer fired case 2" );
449       rtems_test_exit(0);
450       break;
451     case 3:
452       puts( "clock_tick from task level with preempt -- OK" );
453       break;
454  }
455
456  /*
457   *  Test interrupt inline versions
458   */
459  test_interrupt_inline();
460
461  /*
462   *  Test interrupt bodies
463   */
464  puts( "interrupt is in progress (use body)" );
465  in_isr = rtems_interrupt_is_in_progress();
466  if ( in_isr ) {
467    puts( "interrupt reported to be is in progress (body)" );
468    rtems_test_exit( 0 );
469  }
470
471  puts( "interrupt disable (use body)" );
472  _Thread_Disable_dispatch();
473  level = rtems_interrupt_disable();
474  _Thread_Enable_dispatch();
475
476  puts( "interrupt disable (use body)" );
477  _Thread_Disable_dispatch();
478  level = rtems_interrupt_disable();
479  _Thread_Enable_dispatch();
480
481  puts( "interrupt flash (use body)" );
482  _Thread_Disable_dispatch();
483  rtems_interrupt_flash( level );
484  _Thread_Enable_dispatch();
485
486  puts( "interrupt enable (use body)" );
487  _Thread_Disable_dispatch();
488  rtems_interrupt_enable( level );
489  _Thread_Enable_dispatch();
490
491  puts( "interrupt level mode (use body)" );
492  level_mode_body = rtems_interrupt_level_body( level );
493  level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
494  if ( level_mode_macro == level_mode_body ) {
495    puts("test seems to work");
496  }
497
498  /*
499   * Test ISR in progress from actual ISR
500   */
501  isr_in_progress_body   = -1;
502  isr_in_progress_inline = -1;
503
504  status = rtems_timer_fire_after( timer, 10, test_isr_in_progress, NULL );
505  directive_failed( status, "timer_fire_after failed" );
506
507  status = rtems_task_wake_after( 100 );
508  directive_failed( status, "wake_after failed" );
509
510  check_isr_worked( "inline", isr_in_progress_body );
511
512  check_isr_worked( "body", isr_in_progress_body );
513
514  puts( "*** END OF TEST 37 ***" );
515  rtems_test_exit( 0 );
516}
Note: See TracBrowser for help on using the repository browser.