Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include <time.h>
00019 #include <unistd.h>
00020
00021 #include "storage/s_lock.h"
00022
00023 slock_t dummy_spinlock;
00024
00025 static int spins_per_delay = DEFAULT_SPINS_PER_DELAY;
00026
00027
00028
00029
00030
00031 static void
00032 s_lock_stuck(volatile slock_t *lock, const char *file, int line)
00033 {
00034 #if defined(S_LOCK_TEST)
00035 fprintf(stderr,
00036 "\nStuck spinlock (%p) detected at %s:%d.\n",
00037 lock, file, line);
00038 exit(1);
00039 #else
00040 elog(PANIC, "stuck spinlock (%p) detected at %s:%d",
00041 lock, file, line);
00042 #endif
00043 }
00044
00045
00046
00047
00048
00049 int
00050 s_lock(volatile slock_t *lock, const char *file, int line)
00051 {
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 #define MIN_SPINS_PER_DELAY 10
00091 #define MAX_SPINS_PER_DELAY 1000
00092 #define NUM_DELAYS 1000
00093 #define MIN_DELAY_MSEC 1
00094 #define MAX_DELAY_MSEC 1000
00095
00096 int spins = 0;
00097 int delays = 0;
00098 int cur_delay = 0;
00099
00100 while (TAS_SPIN(lock))
00101 {
00102
00103 SPIN_DELAY();
00104
00105
00106 if (++spins >= spins_per_delay)
00107 {
00108 if (++delays > NUM_DELAYS)
00109 s_lock_stuck(lock, file, line);
00110
00111 if (cur_delay == 0)
00112 cur_delay = MIN_DELAY_MSEC;
00113
00114 pg_usleep(cur_delay * 1000L);
00115
00116 #if defined(S_LOCK_TEST)
00117 fprintf(stdout, "*");
00118 fflush(stdout);
00119 #endif
00120
00121
00122 cur_delay += (int) (cur_delay *
00123 ((double) random() / (double) MAX_RANDOM_VALUE) + 0.5);
00124
00125 if (cur_delay > MAX_DELAY_MSEC)
00126 cur_delay = MIN_DELAY_MSEC;
00127
00128 spins = 0;
00129 }
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 if (cur_delay == 0)
00148 {
00149
00150 if (spins_per_delay < MAX_SPINS_PER_DELAY)
00151 spins_per_delay = Min(spins_per_delay + 100, MAX_SPINS_PER_DELAY);
00152 }
00153 else
00154 {
00155 if (spins_per_delay > MIN_SPINS_PER_DELAY)
00156 spins_per_delay = Max(spins_per_delay - 1, MIN_SPINS_PER_DELAY);
00157 }
00158 return delays;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167 void
00168 set_spins_per_delay(int shared_spins_per_delay)
00169 {
00170 spins_per_delay = shared_spins_per_delay;
00171 }
00172
00173
00174
00175
00176
00177
00178 int
00179 update_spins_per_delay(int shared_spins_per_delay)
00180 {
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 return (shared_spins_per_delay * 15 + spins_per_delay) / 16;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 #ifdef HAVE_SPINLOCKS
00206
00207
00208 #if defined(__GNUC__)
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 #if defined(__m68k__) && !defined(__linux__)
00221
00222 static void
00223 tas_dummy()
00224 {
00225 __asm__ __volatile__(
00226 #if defined(__NetBSD__) && defined(__ELF__)
00227
00228 "\
00229 .global tas \n\
00230 tas: \n\
00231 movel %sp@(0x4),%a0 \n\
00232 tas %a0@ \n\
00233 beq _success \n\
00234 moveq #-128,%d0 \n\
00235 rts \n\
00236 _success: \n\
00237 moveq #0,%d0 \n\
00238 rts \n"
00239 #else
00240 "\
00241 .global _tas \n\
00242 _tas: \n\
00243 movel sp@(0x4),a0 \n\
00244 tas a0@ \n\
00245 beq _success \n\
00246 moveq #-128,d0 \n\
00247 rts \n\
00248 _success: \n\
00249 moveq #0,d0 \n\
00250 rts \n"
00251 #endif
00252 );
00253 }
00254 #endif
00255 #else
00256
00257
00258
00259
00260
00261
00262 #if defined(sun3)
00263 static void
00264 tas_dummy()
00265
00266 {
00267 asm("LLA0:");
00268 asm(" .data");
00269 asm(" .text");
00270 asm("|#PROC# 04");
00271 asm(" .globl _tas");
00272 asm("_tas:");
00273 asm("|#PROLOGUE# 1");
00274 asm(" movel sp@(0x4),a0");
00275 asm(" tas a0@");
00276 asm(" beq LLA1");
00277 asm(" moveq #-128,d0");
00278 asm(" rts");
00279 asm("LLA1:");
00280 asm(" moveq #0,d0");
00281 asm(" rts");
00282 asm(" .data");
00283 }
00284 #endif
00285 #endif
00286 #endif
00287
00288
00289
00290
00291 #if defined(S_LOCK_TEST)
00292
00293
00294
00295
00296
00297 struct test_lock_struct
00298 {
00299 char pad1;
00300 slock_t lock;
00301 char pad2;
00302 };
00303
00304 volatile struct test_lock_struct test_lock;
00305
00306 int
00307 main()
00308 {
00309 srandom((unsigned int) time(NULL));
00310
00311 test_lock.pad1 = test_lock.pad2 = 0x44;
00312
00313 S_INIT_LOCK(&test_lock.lock);
00314
00315 if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
00316 {
00317 printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
00318 return 1;
00319 }
00320
00321 if (!S_LOCK_FREE(&test_lock.lock))
00322 {
00323 printf("S_LOCK_TEST: failed, lock not initialized\n");
00324 return 1;
00325 }
00326
00327 S_LOCK(&test_lock.lock);
00328
00329 if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
00330 {
00331 printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
00332 return 1;
00333 }
00334
00335 if (S_LOCK_FREE(&test_lock.lock))
00336 {
00337 printf("S_LOCK_TEST: failed, lock not locked\n");
00338 return 1;
00339 }
00340
00341 S_UNLOCK(&test_lock.lock);
00342
00343 if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
00344 {
00345 printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
00346 return 1;
00347 }
00348
00349 if (!S_LOCK_FREE(&test_lock.lock))
00350 {
00351 printf("S_LOCK_TEST: failed, lock not unlocked\n");
00352 return 1;
00353 }
00354
00355 S_LOCK(&test_lock.lock);
00356
00357 if (test_lock.pad1 != 0x44 || test_lock.pad2 != 0x44)
00358 {
00359 printf("S_LOCK_TEST: failed, declared datatype is wrong size\n");
00360 return 1;
00361 }
00362
00363 if (S_LOCK_FREE(&test_lock.lock))
00364 {
00365 printf("S_LOCK_TEST: failed, lock not re-locked\n");
00366 return 1;
00367 }
00368
00369 printf("S_LOCK_TEST: this will print %d stars and then\n", NUM_DELAYS);
00370 printf(" exit with a 'stuck spinlock' message\n");
00371 printf(" if S_LOCK() and TAS() are working.\n");
00372 fflush(stdout);
00373
00374 s_lock(&test_lock.lock, __FILE__, __LINE__);
00375
00376 printf("S_LOCK_TEST: failed, lock not locked\n");
00377 return 1;
00378 }
00379
00380 #endif