]> granicus.if.org Git - postgresql/blob - src/backend/storage/lmgr/s_lock.c
Update copyrights to 2003.
[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-2003, 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.13 2003/08/04 02:40:03 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 #if defined(S_LOCK_TEST)
31         fprintf(stderr,
32                         "\nFATAL: stuck spinlock (%p) detected at %s:%d.\n",
33                         lock, file, line);
34         abort();
35 #else
36         elog(PANIC, "stuck spinlock (%p) detected at %s:%d",
37                  lock, file, line);
38 #endif
39 }
40
41
42 /*
43  * s_lock(lock) - platform-independent portion of waiting for a spinlock.
44  */
45 void
46 s_lock(volatile slock_t *lock, const char *file, int line)
47 {
48         unsigned        spins = 0;
49         unsigned        delays = 0;
50         struct timeval delay;
51
52         /*
53          * We loop tightly for awhile, then delay using select() and try
54          * again. Preferably, "awhile" should be a small multiple of the
55          * maximum time we expect a spinlock to be held.  100 iterations seems
56          * about right.
57          *
58          * We use a 10 millisec select delay because that is the lower limit on
59          * many platforms.      The timeout is figured on this delay only, and so
60          * the nominal 1 minute is a lower bound.
61          */
62 #define SPINS_PER_DELAY         100
63 #define DELAY_MSEC                      10
64 #define TIMEOUT_MSEC            (60 * 1000)
65
66         while (TAS(lock))
67         {
68                 if (++spins > SPINS_PER_DELAY)
69                 {
70                         if (++delays > (TIMEOUT_MSEC / DELAY_MSEC))
71                                 s_lock_stuck(lock, file, line);
72
73                         delay.tv_sec = 0;
74                         delay.tv_usec = DELAY_MSEC * 1000;
75                         (void) select(0, NULL, NULL, NULL, &delay);
76
77                         spins = 0;
78                 }
79         }
80 }
81
82 /*
83  * Various TAS implementations that cannot live in s_lock.h as no inline
84  * definition exists (yet).
85  * In the future, get rid of tas.[cso] and fold it into this file.
86  */
87
88
89 #if defined(__GNUC__)
90 /*************************************************************************
91  * All the gcc flavors that are not inlined
92  */
93
94
95 #if defined(__m68k__)
96 static void
97 tas_dummy()                                             /* really means: extern int tas(slock_t
98                                                                  * **lock); */
99 {
100         __asm__         __volatile__(
101                                                                                  "\
102 .global         _tas                            \n\
103 _tas:                                                   \n\
104                         movel   sp@(0x4),a0     \n\
105                         tas     a0@                     \n\
106                         beq     _success        \n\
107                         moveq   #-128,d0        \n\
108                         rts                                     \n\
109 _success:                                               \n\
110                         moveq   #0,d0           \n\
111                         rts                                     \n\
112 ");
113 }
114 #endif   /* __m68k__ */
115
116 #if defined(__mips__) && !defined(__sgi)
117 static void
118 tas_dummy()
119 {
120         __asm__         __volatile__(
121                                                                                  "\
122 .global tas                                             \n\
123 tas:                                                    \n\
124                         .frame  $sp, 0, $31     \n\
125                         .set push               \n\
126                         .set mips2              \n\
127                         ll              $14, 0($4)      \n\
128                         or              $15, $14, 1     \n\
129                         sc              $15, 0($4)      \n\
130                         .set pop                        \n\
131                         beq             $15, 0, fail\n\
132                         bne             $14, 0, fail\n\
133                         li              $2, 0           \n\
134                         .livereg 0x2000FF0E,0x00000FFF  \n\
135                         j               $31                     \n\
136 fail:                                                   \n\
137                         li              $2, 1           \n\
138                         j       $31                     \n\
139 ");
140 }
141 #endif   /* __mips__ && !__sgi */
142
143 #else                                                   /* not __GNUC__ */
144 /***************************************************************************
145  * All non gcc
146  */
147
148
149
150 #if defined(sun3)
151 static void
152 tas_dummy()                                             /* really means: extern int tas(slock_t
153                                                                  * *lock); */
154 {
155         asm("LLA0:");
156         asm("   .data");
157         asm("   .text");
158         asm("|#PROC# 04");
159         asm("   .globl  _tas");
160         asm("_tas:");
161         asm("|#PROLOGUE# 1");
162         asm("   movel   sp@(0x4),a0");
163         asm("   tas a0@");
164         asm("   beq LLA1");
165         asm("   moveq   #-128,d0");
166         asm("   rts");
167         asm("LLA1:");
168         asm("   moveq   #0,d0");
169         asm("   rts");
170         asm("   .data");
171 }
172 #endif   /* sun3 */
173
174
175
176 #if defined(NEED_SPARC_TAS_ASM)
177 /*
178  * sparc machines not using gcc
179  */
180 static void
181 tas_dummy()                                             /* really means: extern int tas(slock_t
182                                                                  * *lock); */
183 {
184         asm(".seg \"data\"");
185         asm(".seg \"text\"");
186         asm("_tas:");
187
188         /*
189          * Sparc atomic test and set (sparc calls it "atomic load-store")
190          */
191         asm("ldstub [%r8], %r8");
192         asm("retl");
193         asm("nop");
194 }
195 #endif   /* NEED_SPARC_TAS_ASM */
196
197
198
199
200 #if defined(NEED_I386_TAS_ASM)
201 /* non gcc i386 based things */
202 #endif   /* NEED_I386_TAS_ASM */
203 #endif   /* not __GNUC__ */
204
205
206
207
208 /*****************************************************************************/
209 #if defined(S_LOCK_TEST)
210
211 /*
212  * test program for verifying a port.
213  */
214
215 volatile slock_t test_lock;
216
217 void
218 main()
219 {
220         S_INIT_LOCK(&test_lock);
221
222         if (!S_LOCK_FREE(&test_lock))
223         {
224                 printf("S_LOCK_TEST: failed, lock not initialized.\n");
225                 exit(1);
226         }
227
228         S_LOCK(&test_lock);
229
230         if (S_LOCK_FREE(&test_lock))
231         {
232                 printf("S_LOCK_TEST: failed, lock not locked\n");
233                 exit(2);
234         }
235
236         printf("S_LOCK_TEST: this will hang for a few minutes and then abort\n");
237         printf("             with a 'stuck spinlock' message if S_LOCK()\n");
238         printf("             and TAS() are working.\n");
239         s_lock(&test_lock, __FILE__, __LINE__);
240
241         printf("S_LOCK_TEST: failed, lock not locked~\n");
242         exit(3);
243 }
244
245 #endif   /* S_LOCK_TEST */