]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/s_lock.c
> > I'll re-check that with the ppc architecture guy here.
[postgresql] / src / backend / storage / lmgr / s_lock.c
1 /*-------------------------------------------------------------------------
2  *
3  * s_lock.c
4  *         Hardware-dependent implementation of spinlocks.
5  *
6  *
7  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  *        $Header: /cvsroot/pgsql/src/backend/storage/lmgr/s_lock.c,v 1.10 2002/11/10 00:33:43 momjian Exp $
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17
18 #include <sys/time.h>
19 #include <unistd.h>
20
21 #include "storage/s_lock.h"
22
23
24 /*
25  * s_lock_stuck() - complain about a stuck spinlock
26  */
27 static void
28 s_lock_stuck(volatile slock_t *lock, const char *file, int line)
29 {
30         fprintf(stderr,
31                         "\nFATAL: s_lock(%p) at %s:%d, stuck spinlock. Aborting.\n",
32                         lock, file, line);
33         fprintf(stdout,
34                         "\nFATAL: s_lock(%p) at %s:%d, stuck spinlock. Aborting.\n",
35                         lock, file, line);
36         abort();
37 }
38
39
40 /*
41  * s_lock(lock) - platform-independent portion of waiting for a spinlock.
42  */
43 void
44 s_lock(volatile slock_t *lock, const char *file, int line)
45 {
46         unsigned        spins = 0;
47         unsigned        delays = 0;
48         struct timeval delay;
49
50         /*
51          * We loop tightly for awhile, then delay using select() and try
52          * again. Preferably, "awhile" should be a small multiple of the
53          * maximum time we expect a spinlock to be held.  100 iterations seems
54          * about right.
55          *
56          * We use a 10 millisec select delay because that is the lower limit on
57          * many platforms.      The timeout is figured on this delay only, and so
58          * the nominal 1 minute is a lower bound.
59          */
60 #define SPINS_PER_DELAY         100
61 #define DELAY_MSEC                      10
62 #define TIMEOUT_MSEC            (60 * 1000)
63
64         while (TAS(lock))
65         {
66                 if (++spins > SPINS_PER_DELAY)
67                 {
68                         if (++delays > (TIMEOUT_MSEC / DELAY_MSEC))
69                                 s_lock_stuck(lock, file, line);
70
71                         delay.tv_sec = 0;
72                         delay.tv_usec = DELAY_MSEC * 1000;
73                         (void) select(0, NULL, NULL, NULL, &delay);
74
75                         spins = 0;
76                 }
77         }
78 }
79
80 /*
81  * Various TAS implementations that cannot live in s_lock.h as no inline
82  * definition exists (yet).
83  * In the future, get rid of tas.[cso] and fold it into this file.
84  */
85
86
87 #if defined(__GNUC__)
88 /*************************************************************************
89  * All the gcc flavors that are not inlined
90  */
91
92
93 #if defined(__m68k__)
94 static void
95 tas_dummy()                                             /* really means: extern int tas(slock_t
96                                                                  * **lock); */
97 {
98         __asm__         __volatile__(
99                                                                                  "\
100 .global         _tas                            \n\
101 _tas:                                                   \n\
102                         movel   sp@(0x4),a0     \n\
103                         tas     a0@                     \n\
104                         beq     _success        \n\
105                         moveq   #-128,d0        \n\
106                         rts                                     \n\
107 _success:                                               \n\
108                         moveq   #0,d0           \n\
109                         rts                                     \n\
110 ");
111 }
112 #endif   /* __m68k__ */
113
114 #if defined(__APPLE__) && defined(__ppc__)
115 /* used in darwin. */
116 /* We key off __APPLE__ here because this function differs from
117  * the LinuxPPC implementation only in compiler syntax.
118  *
119  * NOTE: per the Enhanced PowerPC Architecture manual, v1.0 dated 7-May-2002,
120  * an isync is a sufficient synchronization barrier after a lwarx/stwcx loop.
121  */
122 static void
123 tas_dummy()
124 {
125         __asm__         __volatile__(
126                                                                                  "\
127                         .globl  tas                     \n\
128                         .globl  _tas            \n\
129 _tas:                                                   \n\
130 tas:                                                    \n\
131                         lwarx   r5,0,r3         \n\
132                         cmpwi   r5,0            \n\
133                         bne     fail            \n\
134                         addi    r5,r5,1         \n\
135                         stwcx.  r5,0,r3         \n\
136                         beq     success         \n\
137 fail:           li              r3,1            \n\
138                         blr                             \n\
139 success:                                                \n\
140                         isync                           \n\
141                         li              r3,0            \n\
142                         blr                                     \n\
143 ");
144 }
145 #endif   /* __APPLE__ && __ppc__ */
146
147 #if defined(__mips__) && !defined(__sgi)
148 static void
149 tas_dummy()
150 {
151         __asm__         __volatile__(
152                                                                                  "\
153 .global tas                                             \n\
154 tas:                                                    \n\
155                         .frame  $sp, 0, $31     \n\
156                         .set push               \n\
157                         .set mips2              \n\
158                         ll              $14, 0($4)      \n\
159                         or              $15, $14, 1     \n\
160                         sc              $15, 0($4)      \n\
161                         .set pop                        \n\
162                         beq             $15, 0, fail\n\
163                         bne             $14, 0, fail\n\
164                         li              $2, 0           \n\
165                         .livereg 0x2000FF0E,0x00000FFF  \n\
166                         j               $31                     \n\
167 fail:                                                   \n\
168                         li              $2, 1           \n\
169                         j       $31                     \n\
170 ");
171 }
172 #endif   /* __mips__ && !__sgi */
173
174 #else                                                   /* not __GNUC__ */
175 /***************************************************************************
176  * All non gcc
177  */
178
179
180
181 #if defined(sun3)
182 static void
183 tas_dummy()                                             /* really means: extern int tas(slock_t
184                                                                  * *lock); */
185 {
186         asm("LLA0:");
187         asm("   .data");
188         asm("   .text");
189         asm("|#PROC# 04");
190         asm("   .globl  _tas");
191         asm("_tas:");
192         asm("|#PROLOGUE# 1");
193         asm("   movel   sp@(0x4),a0");
194         asm("   tas a0@");
195         asm("   beq LLA1");
196         asm("   moveq   #-128,d0");
197         asm("   rts");
198         asm("LLA1:");
199         asm("   moveq   #0,d0");
200         asm("   rts");
201         asm("   .data");
202 }
203 #endif   /* sun3 */
204
205
206
207 #if defined(NEED_SPARC_TAS_ASM)
208 /*
209  * sparc machines not using gcc
210  */
211 static void
212 tas_dummy()                                             /* really means: extern int tas(slock_t
213                                                                  * *lock); */
214 {
215         asm(".seg \"data\"");
216         asm(".seg \"text\"");
217         asm("_tas:");
218
219         /*
220          * Sparc atomic test and set (sparc calls it "atomic load-store")
221          */
222         asm("ldstub [%r8], %r8");
223         asm("retl");
224         asm("nop");
225 }
226 #endif   /* NEED_SPARC_TAS_ASM */
227
228
229
230
231 #if defined(NEED_I386_TAS_ASM)
232 /* non gcc i386 based things */
233 #endif   /* NEED_I386_TAS_ASM */
234 #endif   /* not __GNUC__ */
235
236
237
238
239 /*****************************************************************************/
240 #if defined(S_LOCK_TEST)
241
242 /*
243  * test program for verifying a port.
244  */
245
246 volatile slock_t test_lock;
247
248 void
249 main()
250 {
251         S_INIT_LOCK(&test_lock);
252
253         if (!S_LOCK_FREE(&test_lock))
254         {
255                 printf("S_LOCK_TEST: failed, lock not initialized.\n");
256                 exit(1);
257         }
258
259         S_LOCK(&test_lock);
260
261         if (S_LOCK_FREE(&test_lock))
262         {
263                 printf("S_LOCK_TEST: failed, lock not locked\n");
264                 exit(2);
265         }
266
267         printf("S_LOCK_TEST: this will hang for a few minutes and then abort\n");
268         printf("             with a 'stuck spinlock' message if S_LOCK()\n");
269         printf("             and TAS() are working.\n");
270         s_lock(&test_lock, __FILE__, __LINE__);
271
272         printf("S_LOCK_TEST: failed, lock not locked~\n");
273         exit(3);
274
275 }
276
277 #endif   /* S_LOCK_TEST */