source: rtems/cpukit/score/src/smplock.c @ 35453000

4.115
Last change on this file since 35453000 was 35453000, checked in by Jennifer Averett <Jennifer.Averett@…>, on Oct 17, 2011 at 6:51:44 PM

2011-10-17 Daniel Hellstrom <daniel@…>

PR 1935/cpukit

  • score/include/rtems/score/smplock.h, score/src/smplock.c: SMP nested count variable was being overritten when nested lock was taken more than once.
  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 *  COPYRIGHT (c) 1989-2011.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  $Id$
10 */
11
12#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <rtems/system.h>
17#include <rtems/score/smplock.h>
18#include <rtems/score/smp.h>
19#include <rtems/score/isr.h>
20
21/*
22 * Some debug stuff that is being left in, but disabled.  This will keep
23 * a log of lock/unlock sequences that can be printed out when the
24 * lockcount appears to have gotten off track.
25 */
26/* #define SMPLOCK_DEBUG */
27#if defined (SMPLOCK_DEBUG)
28  #include <rtems/score/thread.h>
29  #include <rtems/bspIo.h>
30  #include <rtems/score/percpu.h>
31  #if (0)
32    #define  ENABLE_ONESHOT_DEBUG_LOGGING
33  #else
34    #define ENABLE_LOOPED_DEBUG_LOGGING
35  #endif
36  #define ENABLE_DEBUG_LOGGING
37#endif
38
39/*
40 * Prototypes and structures used in the debug lock/unlock error log.
41 */
42#if defined(ENABLE_DEBUG_LOGGING)
43  typedef struct {
44    char      action;
45    char      lock;
46    char      cpu;
47    char      count;
48    uint32_t  nest_level;
49    void      *ret1;
50    void      *ret2;
51    void      *ret3;
52    void      *ret4;
53  } debug_spinlog_t;
54
55  extern void start(void);
56  extern void _fini(void);
57
58  #define DEBUG_SPINLOG_MAX 1024
59  debug_spinlog_t DEBUG_SPINLOG[DEBUG_SPINLOG_MAX];
60  int DEBUG_SPINLOG_INDEX = 0;
61
62  static void debug_logit(
63    char                             act,
64    SMP_lock_spinlock_nested_Control *lock
65  );
66  static void debug_dump_log(void);
67#else
68  #define debug_logit( _act, _lock )
69  #define debug_dump_log()
70#endif
71
72/*
73 * SMP spinlock simple methods
74 */
75void _SMP_lock_spinlock_simple_Initialize(
76  SMP_lock_spinlock_simple_Control *lock
77)
78{
79  *lock = 0;
80}
81
82ISR_Level _SMP_lock_spinlock_simple_Obtain(
83  SMP_lock_spinlock_simple_Control *lock
84)
85{
86   ISR_Level  level = 0;
87   uint32_t   value = 1;
88   uint32_t   previous;
89
90   /* Note: Disable provides an implicit memory barrier. */
91  _ISR_Disable_on_this_core( level );
92   do {
93     RTEMS_COMPILER_MEMORY_BARRIER();
94     SMP_CPU_SWAP( lock, value, previous );
95     RTEMS_COMPILER_MEMORY_BARRIER();
96   } while (previous == 1);
97
98  return level;
99}
100
101void _SMP_lock_spinlock_simple_Release(
102  SMP_lock_spinlock_simple_Control *lock,
103  ISR_Level                        level
104)
105{
106   *lock = 0;
107   _ISR_Enable_on_this_core( level );
108}
109
110/*
111 * SMP spinlock nested methods.
112 */
113void _SMP_lock_spinlock_nested_Initialize(
114  SMP_lock_spinlock_nested_Control *lock
115)
116{
117  lock->lock = 0;
118  lock->count = 0;
119  lock->cpu_id = -1;
120}
121
122void _SMP_lock_spinlock_nested_Release(
123  SMP_lock_spinlock_nested_Control *lock,
124  ISR_Level                        level
125)
126{
127  #if defined (RTEMS_DEBUG) || defined(SMPLOCK_DEBUG)
128    if ( lock->count == 0 ) {
129      printk(
130        "\ncpu %d lock %d Releasing spinlock when count is already "
131        "zero (%p from %p,%p)?!?!\n",
132        bsp_smp_processor_id(), 
133        lock->cpu_id,
134        lock,
135        __builtin_return_address(0),
136        __builtin_return_address(1)
137      );
138      debug_dump_log();
139      return;
140    }
141  #endif
142
143  /* assume we actually have it */
144  if (lock->count == 1) {
145    lock->cpu_id = -1;
146    debug_logit( 'U', lock );
147    lock->count  = 0;
148    RTEMS_COMPILER_MEMORY_BARRIER();
149    lock->lock = 0;
150  } else {
151    debug_logit( 'u', lock );
152    lock->count--;
153  }
154
155  _ISR_Enable_on_this_core( level ); 
156}
157
158ISR_Level _SMP_lock_spinlock_nested_Obtain(
159  SMP_lock_spinlock_nested_Control *lock
160)
161{
162  ISR_Level  level = 0;
163  uint32_t   value = 1;
164  uint32_t   previous;
165  int        cpu_id;
166
167  /* Note: Disable provides an implicit memory barrier. */
168  _ISR_Disable_on_this_core( level ); 
169
170  cpu_id = bsp_smp_processor_id();
171
172  /*
173   *  Attempt to obtain the lock.  If we do not get it immediately, then
174   *  do a single "monitor" iteration.  This should allow the loop to back
175   *  off the bus a bit and allow the other core to finish sooner.
176   */
177  while (1) {
178    RTEMS_COMPILER_MEMORY_BARRIER();
179    SMP_CPU_SWAP( &lock->lock, value, previous );
180    RTEMS_COMPILER_MEMORY_BARRIER();
181    if ( previous == 0 ) {
182      /* was not locked */
183      break;
184    }
185
186    /* Deal with nested calls from one cpu */
187    if (cpu_id == lock->cpu_id) {
188      lock->count++;
189      debug_logit( 'l', lock );
190      return level;
191    }
192  }
193
194  lock->cpu_id = cpu_id;
195  lock->count = 1;
196  debug_logit( 'L', lock );
197
198  return level;
199}
200
201/*
202 * Debug log for debugging nested lock/unlock problems.
203 */
204#if defined(ENABLE_DEBUG_LOGGING)
205  static void debug_logit(
206    char                             act,
207    SMP_lock_spinlock_nested_Control *lock
208  )
209  { 
210    debug_debug_spinlog_t *sp;
211    if ( DEBUG_SPINLOG_INDEX == DEBUG_SPINLOG_MAX )
212      #if defined (ENABLE_LOOPED_DEBUG_LOGGING)
213        DEBUG_SPINLOG_INDEX = 0;
214      #else
215        return;
216      #endif
217
218    sp = &DEBUG_SPINLOG[ DEBUG_SPINLOG_INDEX++ ];
219    sp->action = act;
220
221    #if 0
222      if ( lock == &_ISR_SMP_Lock )
223        sp->lock = 'I';
224      else
225    #endif
226    if ( lock == &_Thread_Dispatch_disable_level_lock )
227      sp->lock   = 'D';
228    sp->cpu    = bsp_smp_processor_id() + '0';
229    sp->count  = lock->count;
230    #if 0
231      if ( sp->lock == 'I' ) {
232        if ( _Thread_Dispatch_smp_spin_lock.id == 0 )
233          printk( "not nested %p from %p %p %p %p\n", sp,
234          __builtin_return_address(0), __builtin_return_address(1),
235          __builtin_return_address(2), __builtin_return_address(3)
236        );
237      }
238    #endif
239    sp->nest_level =  _ISR_Nest_level; 
240    sp->ret1 = 0;
241    sp->ret2 = 0;
242    sp->ret3 = 0;
243    sp->ret4 = 0;
244    sp->ret1 = __builtin_return_address(0);
245    if ( sp->ret1 >= start && sp->ret1 <= _fini ) {
246      sp->ret2   = __builtin_return_address(1);
247      if ( sp->ret2 >= start && sp->ret2 <= _fini ) {
248        sp->ret3   = __builtin_return_address(2);
249        if ( sp->ret3 >= start && sp->ret3 <= _fini ) {
250          sp->ret4   = __builtin_return_address(3);
251        }
252      }
253    }
254  }
255 
256  static void debug_dump_log(void)
257  { 
258    debug_debug_spinlog_t *sp;
259    int       index;
260    bool      done =false;
261   
262    #if defined (ENABLE_ONESHOT_DEBUG_LOGGING)
263      index = 0;
264    #else
265      if (DEBUG_SPINLOG_INDEX >= DEBUG_SPINLOG_MAX)
266        index = 0;
267      else
268        index = DEBUG_SPINLOG_INDEX;
269    #endif
270
271
272    do {
273      sp = &DEBUG_SPINLOG[ index ];
274      printk("%d) act %c lock %c cpu %c count=%d nest %d (%p, %p, %p, %p)\n",
275        index, sp->action, sp->lock, sp->cpu, sp->count, sp->nest_level, 
276        sp->ret1, sp->ret2, sp->ret3, sp->ret4
277      );
278
279      index++;
280      if (index == DEBUG_SPINLOG_INDEX)
281        break;
282      if (index >= DEBUG_SPINLOG_MAX)
283        index = 0;
284    } while (1);
285  }
286#endif
Note: See TracBrowser for help on using the repository browser.