Changeset 1ccbd052 in rtems


Ignore:
Timestamp:
04/15/15 08:53:29 (8 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, 5, master
Children:
fd53d25
Parents:
6d253941
git-author:
Sebastian Huber <sebastian.huber@…> (04/15/15 08:53:29)
git-committer:
Sebastian Huber <sebastian.huber@…> (05/19/15 10:00:43)
Message:

score: Add Watchdog_Iterator

Rewrite the _Watchdog_Insert(), _Watchdog_Remove() and
_Watchdog_Tickle() functions to use iterator items to synchronize
concurrent operations. This makes it possible to get rid of the global
variables _Watchdog_Sync_level and _Watchdog_Sync_count which are a
blocking point for scalable SMP solutions.

Update #2307.

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • cpukit/rtems/src/timercreate.c

    r6d253941 r1ccbd052  
    3030{
    3131  Timer_server_Control *timer_server;
     32  ISR_Level level;
     33
     34  /* The timer class must not change during the cancel operation */
     35  _ISR_Disable( level );
    3236
    3337  switch ( the_timer->the_class ) {
     
    4751      break;
    4852  }
     53
     54  _ISR_Enable( level );
    4955}
    5056
  • cpukit/score/include/rtems/score/watchdogimpl.h

    r6d253941 r1ccbd052  
    4747
    4848/**
     49 * @brief Iterator item to synchronize concurrent insert, remove and tickle
     50 * operations.
     51 */
     52typedef struct {
     53  /**
     54   * @brief A node for a Watchdog_Header::Iterators chain.
     55   */
     56  Chain_Node Node;
     57
     58  /**
     59   * @brief The current delta interval of the new watchdog to insert.
     60   */
     61  Watchdog_Interval delta_interval;
     62
     63  /**
     64   * @brief The current watchdog of the chain on the way to insert the new
     65   * watchdog.
     66   */
     67  Chain_Node *current;
     68} Watchdog_Iterator;
     69
     70/**
    4971 * @brief Watchdog header.
    5072 */
     
    5981   */
    6082  Chain_Control Watchdogs;
     83
     84  /**
     85   * @brief Currently active iterators.
     86   *
     87   * The iterators are registered in _Watchdog_Insert() and updated in case the
     88   * watchdog chain changes.
     89   */
     90  Chain_Control Iterators;
    6191} Watchdog_Header;
    62 
    63 /**
    64  *  @brief Watchdog synchronization level.
    65  *
    66  *  This used for synchronization purposes
    67  *  during an insert on a watchdog delta chain.
    68  */
    69 SCORE_EXTERN volatile uint32_t    _Watchdog_Sync_level;
    70 
    71 /**
    72  *  @brief Watchdog synchronization count.
    73  *
    74  *  This used for synchronization purposes
    75  *  during an insert on a watchdog delta chain.
    76  */
    77 SCORE_EXTERN volatile uint32_t    _Watchdog_Sync_count;
    7892
    7993/**
     
    135149 */
    136150Watchdog_States _Watchdog_Remove (
     151  Watchdog_Header  *header,
     152  Watchdog_Control *the_watchdog
     153);
     154
     155/**
     156 * @brief Actually removes an WATCHDOG_ACTIVE or WATCHDOG_REMOVE_IT watchdog.
     157 *
     158 * @see _Watchdog_Remove() and _Watchdog_Tickle().
     159 */
     160void _Watchdog_Remove_it(
    137161  Watchdog_Header  *header,
    138162  Watchdog_Control *the_watchdog
     
    438462)
    439463{
     464  _ISR_lock_Initialize( &header->Lock, "Watchdog" );
    440465  _Chain_Initialize_empty( &header->Watchdogs );
     466  _Chain_Initialize_empty( &header->Iterators );
    441467}
    442468
  • cpukit/score/src/watchdog.c

    r6d253941 r1ccbd052  
    2626void _Watchdog_Handler_initialization( void )
    2727{
    28   _Watchdog_Sync_count = 0;
    29   _Watchdog_Sync_level = 0;
    3028  _Watchdog_Ticks_since_boot = 0;
    3129
  • cpukit/score/src/watchdoginsert.c

    r6d253941 r1ccbd052  
    2020
    2121#include <rtems/score/watchdogimpl.h>
    22 #include <rtems/score/isrlevel.h>
    23 #include <rtems/score/percpu.h>
     22
     23static void _Watchdog_Insert_fixup(
     24  Watchdog_Header   *header,
     25  Watchdog_Control  *next_watchdog,
     26  Watchdog_Interval  delta
     27)
     28{
     29  const Chain_Node *iterator_tail;
     30  Chain_Node       *iterator_node;
     31
     32  next_watchdog->delta_interval -= delta;
     33
     34  iterator_node = _Chain_First( &header->Iterators );
     35  iterator_tail = _Chain_Immutable_tail( &header->Iterators );
     36
     37  while ( iterator_node != iterator_tail ) {
     38    Watchdog_Iterator *iterator;
     39
     40    iterator = (Watchdog_Iterator *) iterator_node;
     41
     42    if ( iterator->current == &next_watchdog->Node ) {
     43      iterator->delta_interval -= delta;
     44    }
     45
     46    iterator_node = _Chain_Next( iterator_node );
     47  }
     48}
    2449
    2550void _Watchdog_Insert(
    26   Watchdog_Header       *header,
    27   Watchdog_Control      *the_watchdog
     51  Watchdog_Header  *header,
     52  Watchdog_Control *the_watchdog
    2853)
    2954{
    30   ISR_lock_Context   lock_context;
    31   Watchdog_Control  *after;
    32   uint32_t           insert_isr_nest_level;
    33   Watchdog_Interval  delta_interval;
    34 
    35 
    36   insert_isr_nest_level   = _ISR_Nest_level;
     55  ISR_lock_Context lock_context;
    3756
    3857  _Watchdog_Acquire( header, &lock_context );
    3958
    40   /*
    41    *  Check to see if the watchdog has just been inserted by a
    42    *  higher priority interrupt.  If so, abandon this insert.
    43    */
     59  if ( the_watchdog->state == WATCHDOG_INACTIVE ) {
     60    Watchdog_Iterator  iterator;
     61    Chain_Node        *current;
     62    Chain_Node        *next;
     63    Watchdog_Interval  delta;
    4464
    45   if ( the_watchdog->state != WATCHDOG_INACTIVE ) {
    46     _Watchdog_Release( header, &lock_context );
    47     return;
     65    the_watchdog->state = WATCHDOG_BEING_INSERTED;
     66
     67    _Chain_Append_unprotected( &header->Iterators, &iterator.Node );
     68
     69    delta = the_watchdog->initial;
     70    current = _Chain_Head( &header->Watchdogs );
     71
     72    while (
     73      ( next = _Chain_Next( current ) ) != _Chain_Tail( &header->Watchdogs )
     74    ) {
     75      Watchdog_Control  *next_watchdog;
     76      Watchdog_Interval  delta_next;
     77
     78      next_watchdog = (Watchdog_Control *) next;
     79      delta_next = next_watchdog->delta_interval;
     80
     81      if ( delta < delta_next ) {
     82        _Watchdog_Insert_fixup( header, next_watchdog, delta );
     83        break;
     84      }
     85
     86      iterator.delta_interval = delta - delta_next;
     87      iterator.current = next;
     88
     89      _Watchdog_Flash( header, &lock_context );
     90
     91      if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
     92        goto abort_insert;
     93      }
     94
     95      delta = iterator.delta_interval;
     96      current = iterator.current;
     97    }
     98
     99    the_watchdog->delta_interval = delta;
     100    the_watchdog->start_time = _Watchdog_Ticks_since_boot;
     101    _Watchdog_Activate( the_watchdog );
     102    _Chain_Insert_unprotected( current, &the_watchdog->Node );
     103
     104abort_insert:
     105
     106    _Chain_Extract_unprotected( &iterator.Node );
    48107  }
    49108
    50   the_watchdog->state = WATCHDOG_BEING_INSERTED;
    51   _Watchdog_Sync_count++;
    52 
    53 restart:
    54   delta_interval = the_watchdog->initial;
    55 
    56   for ( after = _Watchdog_First( header ) ;
    57         ;
    58         after = _Watchdog_Next( after ) ) {
    59 
    60      if ( delta_interval == 0 || !_Watchdog_Next( after ) )
    61        break;
    62 
    63      if ( delta_interval < after->delta_interval ) {
    64        after->delta_interval -= delta_interval;
    65        break;
    66      }
    67 
    68      delta_interval -= after->delta_interval;
    69 
    70      _Watchdog_Flash( header, &lock_context );
    71 
    72      if ( the_watchdog->state != WATCHDOG_BEING_INSERTED ) {
    73        goto exit_insert;
    74      }
    75 
    76      if ( _Watchdog_Sync_level > insert_isr_nest_level ) {
    77        _Watchdog_Sync_level = insert_isr_nest_level;
    78        goto restart;
    79      }
    80   }
    81 
    82   _Watchdog_Activate( the_watchdog );
    83 
    84   the_watchdog->delta_interval = delta_interval;
    85 
    86   _Chain_Insert_unprotected( after->Node.previous, &the_watchdog->Node );
    87 
    88   the_watchdog->start_time = _Watchdog_Ticks_since_boot;
    89 
    90 exit_insert:
    91   _Watchdog_Sync_level = insert_isr_nest_level;
    92   _Watchdog_Sync_count--;
    93109  _Watchdog_Release( header, &lock_context );
    94110}
  • cpukit/score/src/watchdogremove.c

    r6d253941 r1ccbd052  
    1919#endif
    2020
    21 #include <rtems/system.h>
    22 #include <rtems/score/isr.h>
    2321#include <rtems/score/watchdogimpl.h>
     22#include <rtems/score/assert.h>
     23
     24void _Watchdog_Remove_it(
     25  Watchdog_Header   *header,
     26  Watchdog_Control  *the_watchdog
     27)
     28{
     29  Chain_Node        *next;
     30  Watchdog_Interval  delta;
     31  const Chain_Node  *iterator_tail;
     32  Chain_Node        *iterator_node;
     33
     34  _Assert(
     35    the_watchdog->state == WATCHDOG_ACTIVE
     36      || the_watchdog->state == WATCHDOG_REMOVE_IT
     37  );
     38
     39  the_watchdog->state = WATCHDOG_INACTIVE;
     40  the_watchdog->stop_time = _Watchdog_Ticks_since_boot;
     41
     42  next = _Chain_Next( &the_watchdog->Node );
     43  delta = the_watchdog->delta_interval;
     44
     45  if ( next != _Chain_Tail( &header->Watchdogs ) ) {
     46    Watchdog_Control *next_watchdog;
     47
     48    next_watchdog = (Watchdog_Control *) next;
     49    next_watchdog->delta_interval += delta;
     50  }
     51
     52  _Chain_Extract_unprotected( &the_watchdog->Node );
     53
     54  iterator_node = _Chain_First( &header->Iterators );
     55  iterator_tail = _Chain_Immutable_tail( &header->Iterators );
     56
     57  while ( iterator_node != iterator_tail ) {
     58    Watchdog_Iterator *iterator;
     59
     60    iterator = (Watchdog_Iterator *) iterator_node;
     61
     62    if ( iterator->current == next ) {
     63      iterator->delta_interval += delta;
     64    }
     65
     66    if ( iterator->current == &the_watchdog->Node ) {
     67      iterator->current = _Chain_Previous( &the_watchdog->Node );
     68    }
     69
     70    iterator_node = _Chain_Next( iterator_node );
     71  }
     72}
    2473
    2574Watchdog_States _Watchdog_Remove(
     
    3079  ISR_lock_Context  lock_context;
    3180  Watchdog_States   previous_state;
    32   Watchdog_Control *next_watchdog;
     81  Watchdog_Interval now;
    3382
    3483  _Watchdog_Acquire( header, &lock_context );
     
    4594       */
    4695      the_watchdog->state = WATCHDOG_INACTIVE;
     96      now = _Watchdog_Ticks_since_boot;
     97      the_watchdog->start_time = now;
     98      the_watchdog->stop_time = now;
    4799      break;
    48100
    49101    case WATCHDOG_ACTIVE:
    50102    case WATCHDOG_REMOVE_IT:
    51 
    52       the_watchdog->state = WATCHDOG_INACTIVE;
    53       next_watchdog = _Watchdog_Next( the_watchdog );
    54 
    55       if ( _Watchdog_Next(next_watchdog) )
    56         next_watchdog->delta_interval += the_watchdog->delta_interval;
    57 
    58       if ( _Watchdog_Sync_count )
    59         _Watchdog_Sync_level = _ISR_Nest_level;
    60 
    61       _Chain_Extract_unprotected( &the_watchdog->Node );
     103      _Watchdog_Remove_it( header, the_watchdog );
    62104      break;
    63105  }
    64   the_watchdog->stop_time = _Watchdog_Ticks_since_boot;
    65106
    66107  _Watchdog_Release( header, &lock_context );
  • cpukit/score/src/watchdogtickle.c

    r6d253941 r1ccbd052  
    2020
    2121#include <rtems/score/watchdogimpl.h>
    22 #include <rtems/score/isrlevel.h>
    2322
    2423void _Watchdog_Tickle(
     
    2625)
    2726{
    28   ISR_lock_Context  lock_context;
    29   Watchdog_Control *the_watchdog;
    30   Watchdog_States   watchdog_state;
    31 
    32   /*
    33    * See the comment in watchdoginsert.c and watchdogadjust.c
    34    * about why it's safe not to declare header a pointer to
    35    * volatile data - till, 2003/7
    36    */
     27  ISR_lock_Context lock_context;
    3728
    3829  _Watchdog_Acquire( header, &lock_context );
    3930
    40   if ( _Watchdog_Is_empty( header ) )
    41     goto leave;
     31  if ( !_Watchdog_Is_empty( header ) ) {
     32    Watchdog_Control  *first;
     33    Watchdog_Interval  delta;
    4234
    43   the_watchdog = _Watchdog_First( header );
     35    first = _Watchdog_First( header );
     36    delta = first->delta_interval;
    4437
    45   /*
    46    * For some reason, on rare occasions the_watchdog->delta_interval
    47    * of the head of the watchdog chain is 0.  Before this test was
    48    * added, on these occasions an event (which usually was supposed
    49    * to have a timeout of 1 tick would have a delta_interval of 0, which
    50    * would be decremented to 0xFFFFFFFF by the unprotected
    51    * "the_watchdog->delta_interval--;" operation.
    52    * This would mean the event would not timeout, and also the chain would
    53    * be blocked, because a timeout with a very high number would be at the
    54    * head, rather than at the end.
    55    * The test "if (the_watchdog->delta_interval != 0)"
    56    * here prevents this from occuring.
    57    *
    58    * We were not able to categorically identify the situation that causes
    59    * this, but proved it to be true empirically.  So this check causes
    60    * correct behaviour in this circumstance.
    61    *
    62    * The belief is that a race condition exists whereby an event at the head
    63    * of the chain is removed (by a pending ISR or higher priority task)
    64    * during the _ISR_Flash( level ); in _Watchdog_Insert, but the watchdog
    65    * to be inserted has already had its delta_interval adjusted to 0, and
    66    * so is added to the head of the chain with a delta_interval of 0.
    67    *
    68    * Steven Johnson - 12/2005 (gcc-3.2.3 -O3 on powerpc)
    69    */
    70   if (the_watchdog->delta_interval != 0) {
    71     the_watchdog->delta_interval--;
    72     if ( the_watchdog->delta_interval != 0 )
    73       goto leave;
     38    /*
     39     * Although it is forbidden to insert watchdogs with a delta interval of
     40     * zero it is possible to observe watchdogs with a delta interval of zero
     41     * at this point.  For example lets have a watchdog chain of one watchdog
     42     * with a delta interval of one and insert a new one with an initial value
     43     * of one.  At the start of the insert procedure it will advance one step
     44     * and reduce its delta interval by one yielding zero.  Now a tick happens.
     45     * This will remove the watchdog on the chain and update the insert
     46     * iterator.  Now the insert operation continues and will insert the new
     47     * watchdog with a delta interval of zero.
     48     */
     49    if ( delta > 0 ) {
     50      --delta;
     51      first->delta_interval = delta;
     52    }
     53
     54    while ( delta == 0 ) {
     55      bool                            run;
     56      Watchdog_Service_routine_entry  routine;
     57      Objects_Id                      id;
     58      void                           *user_data;
     59
     60      run = ( first->state == WATCHDOG_ACTIVE );
     61
     62      _Watchdog_Remove_it( header, first );
     63
     64      routine = first->routine;
     65      id = first->id;
     66      user_data = first->user_data;
     67
     68      _Watchdog_Release( header, &lock_context );
     69
     70      if ( run ) {
     71        (*routine)( id, user_data );
     72      }
     73
     74      _Watchdog_Acquire( header, &lock_context );
     75
     76      if ( _Watchdog_Is_empty( header ) ) {
     77        break;
     78      }
     79
     80      first = _Watchdog_First( header );
     81      delta = first->delta_interval;
     82    }
    7483  }
    7584
    76   do {
    77      watchdog_state = _Watchdog_Remove( header, the_watchdog );
    78 
    79      _Watchdog_Release( header, &lock_context );
    80 
    81      switch( watchdog_state ) {
    82        case WATCHDOG_ACTIVE:
    83          (*the_watchdog->routine)(
    84            the_watchdog->id,
    85            the_watchdog->user_data
    86          );
    87          break;
    88 
    89        case WATCHDOG_INACTIVE:
    90          /*
    91           *  This state indicates that the watchdog is not on any chain.
    92           *  Thus, it is NOT on a chain being tickled.  This case should
    93           *  never occur.
    94           */
    95          break;
    96 
    97        case WATCHDOG_BEING_INSERTED:
    98          /*
    99           *  This state indicates that the watchdog is in the process of
    100           *  BEING inserted on the chain.  Thus, it can NOT be on a chain
    101           *  being tickled.  This case should never occur.
    102           */
    103          break;
    104 
    105        case WATCHDOG_REMOVE_IT:
    106          break;
    107      }
    108 
    109      _Watchdog_Acquire( header, &lock_context );
    110 
    111      the_watchdog = _Watchdog_First( header );
    112    } while ( !_Watchdog_Is_empty( header ) &&
    113              (the_watchdog->delta_interval == 0) );
    114 
    115 leave:
    116    _Watchdog_Release( header, &lock_context );
     85  _Watchdog_Release( header, &lock_context );
    11786}
  • testsuites/sptests/spsize/size.c

    r6d253941 r1ccbd052  
    400400/*userext.h*/   (sizeof _User_extensions_List)            +
    401401
    402 /*watchdog.h*/  (sizeof _Watchdog_Sync_level)             +
    403                 (sizeof _Watchdog_Sync_count)             +
    404                 (sizeof _Watchdog_Ticks_since_boot)       +
     402/*watchdog.h*/  (sizeof _Watchdog_Ticks_since_boot)       +
    405403                (sizeof _Watchdog_Ticks_header)           +
    406404                (sizeof _Watchdog_Seconds_header)         +
  • testsuites/sptests/spwatchdog/init.c

    r6d253941 r1ccbd052  
    3333
    3434  rtems_test_assert( 0 );
     35}
     36
     37static void init_watchdogs(
     38  Watchdog_Header *header,
     39  Watchdog_Control watchdogs[3]
     40)
     41{
     42  Watchdog_Control *a = &watchdogs[0];
     43  Watchdog_Control *b = &watchdogs[1];
     44  Watchdog_Control *c = &watchdogs[2];
     45  Watchdog_Control *d = &watchdogs[3];
     46
     47  _Watchdog_Header_initialize( header );
     48  rtems_test_assert( _Watchdog_Is_empty( header ) );
     49  rtems_test_assert( _Chain_Is_empty( &header->Iterators ) );
     50
     51  _Watchdog_Initialize( c, NULL, 0, NULL );
     52  c->initial = 6;
     53  _Watchdog_Insert( header, c );
     54  rtems_test_assert( c->delta_interval == 6 );
     55
     56  rtems_test_assert( !_Watchdog_Is_empty( header ) );
     57  rtems_test_assert( _Chain_Is_empty( &header->Iterators ) );
     58
     59  _Watchdog_Initialize( a, NULL, 0, NULL );
     60  a->initial = 2;
     61  _Watchdog_Insert( header, a );
     62  rtems_test_assert( a->delta_interval == 2 );
     63  rtems_test_assert( c->delta_interval == 4 );
     64
     65  _Watchdog_Initialize( b, NULL, 0, NULL );
     66  b->initial = 4;
     67  _Watchdog_Insert( header, b );
     68  rtems_test_assert( a->delta_interval == 2 );
     69  rtems_test_assert( b->delta_interval == 2 );
     70  rtems_test_assert( c->delta_interval == 2 );
     71
     72  _Watchdog_Initialize( d, NULL, 0, NULL );
     73}
     74
     75static void destroy_watchdogs(
     76  Watchdog_Header *header
     77)
     78{
     79  _ISR_lock_Destroy( &header->Lock );
     80}
     81
     82static void add_iterator(
     83  Watchdog_Header *header,
     84  Watchdog_Iterator *i,
     85  Watchdog_Control *w
     86)
     87{
     88  _Chain_Append_unprotected( &header->Iterators, &i->Node );
     89  i->delta_interval = 2;
     90  i->current = &w->Node;
     91}
     92
     93static void test_watchdog_insert_and_remove( void )
     94{
     95  Watchdog_Header header;
     96  Watchdog_Control watchdogs[4];
     97  Watchdog_Control *a = &watchdogs[0];
     98  Watchdog_Control *b = &watchdogs[1];
     99  Watchdog_Control *c = &watchdogs[2];
     100  Watchdog_Control *d = &watchdogs[3];
     101  Watchdog_Iterator i;
     102
     103  init_watchdogs( &header, watchdogs );
     104  add_iterator( &header, &i, c );
     105
     106  /* Remove next watchdog of iterator */
     107  _Watchdog_Remove( &header, c );
     108  rtems_test_assert( i.delta_interval == 2 );
     109  rtems_test_assert( i.current == &b->Node );
     110
     111  /* Remove watchdog before the current watchdog of iterator */
     112  _Watchdog_Remove( &header, a );
     113  rtems_test_assert( i.delta_interval == 4 );
     114  rtems_test_assert( i.current == &b->Node );
     115
     116  /* Remove current (= last) watchdog of iterator */
     117  _Watchdog_Remove( &header, b );
     118  rtems_test_assert( i.delta_interval == 4 );
     119  rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) );
     120
     121  /* Insert first watchdog */
     122  a->initial = 1;
     123  _Watchdog_Insert( &header, a );
     124  rtems_test_assert( i.delta_interval == 4 );
     125  rtems_test_assert( i.current == _Chain_Head( &header.Watchdogs ) );
     126
     127  destroy_watchdogs( &header );
     128  init_watchdogs( &header, watchdogs );
     129  add_iterator( &header, &i, b );
     130
     131  /* Insert right before current watchdog of iterator */
     132  d->initial = 3;
     133  _Watchdog_Insert( &header, d );
     134  rtems_test_assert( i.delta_interval == 1 );
     135  rtems_test_assert( i.current == &b->Node );
     136
     137  destroy_watchdogs( &header );
     138  init_watchdogs( &header, watchdogs );
     139  add_iterator( &header, &i, b );
     140
     141  /* Insert right after current watchdog of iterator */
     142  d->initial = 5;
     143  _Watchdog_Insert( &header, d );
     144  rtems_test_assert( i.delta_interval == 2 );
     145  rtems_test_assert( i.current == &b->Node );
     146
     147  destroy_watchdogs( &header );
    35148}
    36149
     
    71184
    72185  test_watchdog_static_init();
     186  test_watchdog_insert_and_remove();
    73187
    74188  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
Note: See TracChangeset for help on using the changeset viewer.