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

4.115
Last change on this file since dad36c52 was dad36c52, checked in by Jennifer Averett <Jennifer.Averett@…>, on Aug 22, 2011 at 6:26:08 PM

2011-08-22 Jennifer Averett <Jennifer.Averett@…>

PR 1876

  • score/Makefile.am, score/include/rtems/score/isr.h, score/src/isr.c, score/src/smp.c, score/src/smplock.c, score/src/threaddispatch.c, score/src/threaddispatchdisablelevel.c: Add smp isr support.
  • score/src/isrsmp.c: New file.
  • 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->count = 0;
118  lock->cpu_id = -1;
119}
120
121void _SMP_lock_spinlock_nested_Release(
122  SMP_lock_spinlock_nested_Control *lock,
123  ISR_Level                        level
124)
125{
126  #if defined (RTEMS_DEBUG) || defined(SMPLOCK_DEBUG)
127    if ( lock->count == 0 ) {
128      printk(
129        "\ncpu %d lock %d Releasing spinlock when count is already "
130        "zero (%p from %p,%p)?!?!\n",
131        bsp_smp_processor_id(), 
132        lock->cpu_id,
133        lock,
134        __builtin_return_address(0),
135        __builtin_return_address(1)
136      );
137      debug_dump_log();
138      return;
139    }
140  #endif
141
142  /* assume we actually have it */
143  if (lock->count == 1) {
144    lock->cpu_id = -1;
145    debug_logit( 'U', lock );
146    RTEMS_COMPILER_MEMORY_BARRIER();
147    lock->count  = 0;
148  } else {
149    debug_logit( 'u', lock );
150    lock->count--;
151  }
152
153  _ISR_Enable_on_this_core( level ); 
154}
155
156ISR_Level _SMP_lock_spinlock_nested_Obtain(
157  SMP_lock_spinlock_nested_Control *lock
158)
159{
160  ISR_Level  level = 0;
161  uint32_t   value = 1;
162  uint32_t   previous;
163  int        cpu_id;
164
165  /* Note: Disable provides an implicit memory barrier. */
166  _ISR_Disable_on_this_core( level ); 
167
168  cpu_id = bsp_smp_processor_id();
169
170  /*
171   *  Attempt to obtain the lock.  If we do not get it immediately, then
172   *  do a single "monitor" iteration.  This should allow the loop to back
173   *  off the bus a bit and allow the other core to finish sooner.
174   */
175  while (1) {
176    RTEMS_COMPILER_MEMORY_BARRIER();
177    SMP_CPU_SWAP( &lock->count, value, previous );
178    RTEMS_COMPILER_MEMORY_BARRIER();
179    if ( previous == 0 ) {
180      /* was not locked */
181      break;
182    }
183
184    /* Deal with nested calls from one cpu */
185    if (cpu_id == lock->cpu_id) {
186      lock->count++;
187      debug_logit( 'l', lock );
188      return level;
189    }
190  }
191
192  lock->cpu_id = cpu_id;
193  debug_logit( 'L', lock );
194
195  return level;
196}
197
198/*
199 * Debug log for debugging nested lock/unlock problems.
200 */
201#if defined(ENABLE_DEBUG_LOGGING)
202  static void debug_logit(
203    char                             act,
204    SMP_lock_spinlock_nested_Control *lock
205  )
206  { 
207    debug_debug_spinlog_t *sp;
208    if ( DEBUG_SPINLOG_INDEX == DEBUG_SPINLOG_MAX )
209      #if defined (ENABLE_LOOPED_DEBUG_LOGGING)
210        DEBUG_SPINLOG_INDEX = 0;
211      #else
212        return;
213      #endif
214
215    sp = &DEBUG_SPINLOG[ DEBUG_SPINLOG_INDEX++ ];
216    sp->action = act;
217
218    #if 0
219      if ( lock == &_ISR_SMP_Lock )
220        sp->lock = 'I';
221      else
222    #endif
223    if ( lock == &_Thread_Dispatch_disable_level_lock )
224      sp->lock   = 'D';
225    sp->cpu    = bsp_smp_processor_id() + '0';
226    sp->count  = lock->count;
227    #if 0
228      if ( sp->lock == 'I' ) {
229        if ( _Thread_Dispatch_smp_spin_lock.id == 0 )
230          printk( "not nested %p from %p %p %p %p\n", sp,
231          __builtin_return_address(0), __builtin_return_address(1),
232          __builtin_return_address(2), __builtin_return_address(3)
233        );
234      }
235    #endif
236    sp->nest_level =  _ISR_Nest_level; 
237    sp->ret1 = 0;
238    sp->ret2 = 0;
239    sp->ret3 = 0;
240    sp->ret4 = 0;
241    sp->ret1 = __builtin_return_address(0);
242    if ( sp->ret1 >= start && sp->ret1 <= _fini ) {
243      sp->ret2   = __builtin_return_address(1);
244      if ( sp->ret2 >= start && sp->ret2 <= _fini ) {
245        sp->ret3   = __builtin_return_address(2);
246        if ( sp->ret3 >= start && sp->ret3 <= _fini ) {
247          sp->ret4   = __builtin_return_address(3);
248        }
249      }
250    }
251  }
252 
253  static void debug_dump_log(void)
254  { 
255    debug_debug_spinlog_t *sp;
256    int       index;
257    bool      done =false;
258   
259    #if defined (ENABLE_ONESHOT_DEBUG_LOGGING)
260      index = 0;
261    #else
262      if (DEBUG_SPINLOG_INDEX >= DEBUG_SPINLOG_MAX)
263        index = 0;
264      else
265        index = DEBUG_SPINLOG_INDEX;
266    #endif
267
268
269    do {
270      sp = &DEBUG_SPINLOG[ index ];
271      printk("%d) act %c lock %c cpu %c count=%d nest %d (%p, %p, %p, %p)\n",
272        index, sp->action, sp->lock, sp->cpu, sp->count, sp->nest_level, 
273        sp->ret1, sp->ret2, sp->ret3, sp->ret4
274      );
275
276      index++;
277      if (index == DEBUG_SPINLOG_INDEX)
278        break;
279      if (index >= DEBUG_SPINLOG_MAX)
280        index = 0;
281    } while (1);
282  }
283#endif
Note: See TracBrowser for help on using the repository browser.