]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/s_lock.c
New pgindent run with fixes suggested by Tom. Patch manually reviewed,
[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-2001, 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.5 2001/11/05 17:46:28 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 static void
120 tas_dummy()
121 {
122         __asm__         __volatile__(
123                                                                                  "\
124                         .globl  tas                     \n\
125                         .globl  _tas            \n\
126 _tas:                                                   \n\
127 tas:                                                    \n\
128                         lwarx   r5,0,r3         \n\
129                         cmpwi   r5,0            \n\
130                         bne     fail            \n\
131                         addi    r5,r5,1         \n\
132                         stwcx.  r5,0,r3         \n\
133                         beq     success         \n\
134 fail:           li              r3,1            \n\
135                         blr                             \n\
136 success:                                                \n\
137                         li              r3,0            \n\
138                         blr                                     \n\
139 ");
140 }
141 #endif   /* __APPLE__ && __ppc__ */
142
143 #if defined(__powerpc__)
144 /* Note: need a nice gcc constrained asm version so it can be inlined */
145 static void
146 tas_dummy()
147 {
148         __asm__         __volatile__(
149                                                                                  "\
150 .global tas                                     \n\
151 tas:                                                    \n\
152                         lwarx   5,0,3           \n\
153                         cmpwi   5,0             \n\
154                         bne     fail            \n\
155                         addi    5,5,1           \n\
156                         stwcx.  5,0,3           \n\
157                         beq     success         \n\
158 fail:           li              3,1             \n\
159                         blr                             \n\
160 success:                                                \n\
161                         li              3,0                     \n\
162                         blr                                     \n\
163 ");
164 }
165 #endif   /* __powerpc__ */
166
167 #if defined(__mips__) && !defined(__sgi)
168 static void
169 tas_dummy()
170 {
171         __asm__         __volatile__(
172                                                                                  "\
173 .global tas                                             \n\
174 tas:                                                    \n\
175                         .frame  $sp, 0, $31     \n\
176                         ll              $14, 0($4)      \n\
177                         or              $15, $14, 1     \n\
178                         sc              $15, 0($4)      \n\
179                         beq             $15, 0, fail\n\
180                         bne             $14, 0, fail\n\
181                         li              $2, 0           \n\
182                         .livereg 0x2000FF0E,0x00000FFF  \n\
183                         j               $31                     \n\
184 fail:                                                   \n\
185                         li              $2, 1           \n\
186                         j       $31                     \n\
187 ");
188 }
189 #endif   /* __mips__ && !__sgi */
190
191 #else                                                   /* not __GNUC__ */
192 /***************************************************************************
193  * All non gcc
194  */
195
196
197
198 #if defined(sun3)
199 static void
200 tas_dummy()                                             /* really means: extern int tas(slock_t
201                                                                  * *lock); */
202 {
203         asm("LLA0:");
204         asm("   .data");
205         asm("   .text");
206         asm("|#PROC# 04");
207         asm("   .globl  _tas");
208         asm("_tas:");
209         asm("|#PROLOGUE# 1");
210         asm("   movel   sp@(0x4),a0");
211         asm("   tas a0@");
212         asm("   beq LLA1");
213         asm("   moveq   #-128,d0");
214         asm("   rts");
215         asm("LLA1:");
216         asm("   moveq   #0,d0");
217         asm("   rts");
218         asm("   .data");
219 }
220 #endif   /* sun3 */
221
222
223
224 #if defined(NEED_SPARC_TAS_ASM)
225 /*
226  * sparc machines not using gcc
227  */
228 static void
229 tas_dummy()                                             /* really means: extern int tas(slock_t
230                                                                  * *lock); */
231 {
232         asm(".seg \"data\"");
233         asm(".seg \"text\"");
234         asm("_tas:");
235
236         /*
237          * Sparc atomic test and set (sparc calls it "atomic load-store")
238          */
239         asm("ldstub [%r8], %r8");
240         asm("retl");
241         asm("nop");
242 }
243 #endif   /* NEED_SPARC_TAS_ASM */
244
245
246
247
248 #if defined(NEED_I386_TAS_ASM)
249 /* non gcc i386 based things */
250 #endif   /* NEED_I386_TAS_ASM */
251 #endif   /* not __GNUC__ */
252
253
254
255
256 /*****************************************************************************/
257 #if defined(S_LOCK_TEST)
258
259 /*
260  * test program for verifying a port.
261  */
262
263 volatile slock_t test_lock;
264
265 void
266 main()
267 {
268         S_INIT_LOCK(&test_lock);
269
270         if (!S_LOCK_FREE(&test_lock))
271         {
272                 printf("S_LOCK_TEST: failed, lock not initialized.\n");
273                 exit(1);
274         }
275
276         S_LOCK(&test_lock);
277
278         if (S_LOCK_FREE(&test_lock))
279         {
280                 printf("S_LOCK_TEST: failed, lock not locked\n");
281                 exit(2);
282         }
283
284         printf("S_LOCK_TEST: this will hang for a few minutes and then abort\n");
285         printf("             with a 'stuck spinlock' message if S_LOCK()\n");
286         printf("             and TAS() are working.\n");
287         s_lock(&test_lock, __FILE__, __LINE__);
288
289         printf("S_LOCK_TEST: failed, lock not locked~\n");
290         exit(3);
291
292 }
293
294 #endif   /* S_LOCK_TEST */