PostgreSQL Source Code  git master
s_lock.c File Reference
#include "postgres.h"
#include <time.h>
#include <unistd.h>
#include "common/pg_prng.h"
#include "port/atomics.h"
#include "storage/s_lock.h"
#include "utils/wait_event.h"
Include dependency graph for s_lock.c:

Go to the source code of this file.

Macros

#define MIN_SPINS_PER_DELAY   10
 
#define MAX_SPINS_PER_DELAY   1000
 
#define NUM_DELAYS   1000
 
#define MIN_DELAY_USEC   1000L
 
#define MAX_DELAY_USEC   1000000L
 

Functions

static void s_lock_stuck (const char *file, int line, const char *func)
 
int s_lock (volatile slock_t *lock, const char *file, int line, const char *func)
 
void s_unlock (volatile slock_t *lock)
 
void perform_spin_delay (SpinDelayStatus *status)
 
void finish_spin_delay (SpinDelayStatus *status)
 
void set_spins_per_delay (int shared_spins_per_delay)
 
int update_spins_per_delay (int shared_spins_per_delay)
 

Variables

static int spins_per_delay = DEFAULT_SPINS_PER_DELAY
 

Macro Definition Documentation

◆ MAX_DELAY_USEC

#define MAX_DELAY_USEC   1000000L

Definition at line 62 of file s_lock.c.

◆ MAX_SPINS_PER_DELAY

#define MAX_SPINS_PER_DELAY   1000

Definition at line 59 of file s_lock.c.

◆ MIN_DELAY_USEC

#define MIN_DELAY_USEC   1000L

Definition at line 61 of file s_lock.c.

◆ MIN_SPINS_PER_DELAY

#define MIN_SPINS_PER_DELAY   10

Definition at line 58 of file s_lock.c.

◆ NUM_DELAYS

#define NUM_DELAYS   1000

Definition at line 60 of file s_lock.c.

Function Documentation

◆ finish_spin_delay()

void finish_spin_delay ( SpinDelayStatus status)

Definition at line 187 of file s_lock.c.

188 {
189  if (status->cur_delay == 0)
190  {
191  /* we never had to delay */
194  }
195  else
196  {
199  }
200 }
#define Min(x, y)
Definition: c.h:1007
#define Max(x, y)
Definition: c.h:1001
#define MAX_SPINS_PER_DELAY
Definition: s_lock.c:59
#define MIN_SPINS_PER_DELAY
Definition: s_lock.c:58
static int spins_per_delay
Definition: s_lock.c:73

References SpinDelayStatus::cur_delay, Max, MAX_SPINS_PER_DELAY, Min, MIN_SPINS_PER_DELAY, and spins_per_delay.

Referenced by LockBufHdr(), LWLockWaitListLock(), s_lock(), and WaitBufHdrUnlocked().

◆ perform_spin_delay()

void perform_spin_delay ( SpinDelayStatus status)

Definition at line 127 of file s_lock.c.

128 {
129  /* CPU-specific delay each time through the loop */
130  SPIN_DELAY();
131 
132  /* Block the process every spins_per_delay tries */
133  if (++(status->spins) >= spins_per_delay)
134  {
135  if (++(status->delays) > NUM_DELAYS)
136  s_lock_stuck(status->file, status->line, status->func);
137 
138  if (status->cur_delay == 0) /* first time to delay? */
139  status->cur_delay = MIN_DELAY_USEC;
140 
141  /*
142  * Once we start sleeping, the overhead of reporting a wait event is
143  * justified. Actively spinning easily stands out in profilers, but
144  * sleeping with an exponential backoff is harder to spot...
145  *
146  * We might want to report something more granular at some point, but
147  * this is better than nothing.
148  */
149  pgstat_report_wait_start(WAIT_EVENT_SPIN_DELAY);
150  pg_usleep(status->cur_delay);
152 
153 #if defined(S_LOCK_TEST)
154  fprintf(stdout, "*");
155  fflush(stdout);
156 #endif
157 
158  /* increase delay by a random fraction between 1X and 2X */
159  status->cur_delay += (int) (status->cur_delay *
161  /* wrap back to minimum delay when max is exceeded */
162  if (status->cur_delay > MAX_DELAY_USEC)
163  status->cur_delay = MIN_DELAY_USEC;
164 
165  status->spins = 0;
166  }
167 }
static void const char fflush(stdout)
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:268
pg_prng_state pg_global_prng_state
Definition: pg_prng.c:34
#define fprintf
Definition: port.h:242
#define MIN_DELAY_USEC
Definition: s_lock.c:61
#define NUM_DELAYS
Definition: s_lock.c:60
#define MAX_DELAY_USEC
Definition: s_lock.c:62
static void s_lock_stuck(const char *file, int line, const char *func)
Definition: s_lock.c:80
#define SPIN_DELAY()
Definition: s_lock.h:693
void pg_usleep(long microsec)
Definition: signal.c:53
const char * file
Definition: s_lock.h:728
const char * func
Definition: s_lock.h:730
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:85
static void pgstat_report_wait_end(void)
Definition: wait_event.h:101

References SpinDelayStatus::cur_delay, SpinDelayStatus::delays, fflush(), SpinDelayStatus::file, fprintf, SpinDelayStatus::func, SpinDelayStatus::line, MAX_DELAY_USEC, MIN_DELAY_USEC, NUM_DELAYS, pg_global_prng_state, pg_prng_double(), pg_usleep(), pgstat_report_wait_end(), pgstat_report_wait_start(), s_lock_stuck(), SPIN_DELAY, SpinDelayStatus::spins, spins_per_delay, and generate_unaccent_rules::stdout.

Referenced by LockBufHdr(), LWLockWaitListLock(), s_lock(), and WaitBufHdrUnlocked().

◆ s_lock()

int s_lock ( volatile slock_t *  lock,
const char *  file,
int  line,
const char *  func 
)

Definition at line 99 of file s_lock.c.

100 {
101  SpinDelayStatus delayStatus;
102 
103  init_spin_delay(&delayStatus, file, line, func);
104 
105  while (TAS_SPIN(lock))
106  {
107  perform_spin_delay(&delayStatus);
108  }
109 
110  finish_spin_delay(&delayStatus);
111 
112  return delayStatus.delays;
113 }
void perform_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:127
void finish_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:187
#define TAS_SPIN(lock)
Definition: s_lock.h:704
static void init_spin_delay(SpinDelayStatus *status, const char *file, int line, const char *func)
Definition: s_lock.h:734

References SpinDelayStatus::delays, finish_spin_delay(), init_spin_delay(), perform_spin_delay(), and TAS_SPIN.

Referenced by test_spinlock().

◆ s_lock_stuck()

static void s_lock_stuck ( const char *  file,
int  line,
const char *  func 
)
static

Definition at line 80 of file s_lock.c.

81 {
82  if (!func)
83  func = "(unknown)";
84 #if defined(S_LOCK_TEST)
85  fprintf(stderr,
86  "\nStuck spinlock detected at %s, %s:%d.\n",
87  func, file, line);
88  exit(1);
89 #else
90  elog(PANIC, "stuck spinlock detected at %s, %s:%d",
91  func, file, line);
92 #endif
93 }
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:225
exit(1)

References elog, exit(), fprintf, and PANIC.

Referenced by perform_spin_delay().

◆ s_unlock()

void s_unlock ( volatile slock_t *  lock)

Definition at line 117 of file s_lock.c.

118 {
119  *lock = 0;
120 }

◆ set_spins_per_delay()

void set_spins_per_delay ( int  shared_spins_per_delay)

Definition at line 208 of file s_lock.c.

209 {
210  spins_per_delay = shared_spins_per_delay;
211 }

References spins_per_delay.

Referenced by InitAuxiliaryProcess(), and InitProcess().

◆ update_spins_per_delay()

int update_spins_per_delay ( int  shared_spins_per_delay)

Definition at line 219 of file s_lock.c.

220 {
221  /*
222  * We use an exponential moving average with a relatively slow adaption
223  * rate, so that noise in any one backend's result won't affect the shared
224  * value too much. As long as both inputs are within the allowed range,
225  * the result must be too, so we need not worry about clamping the result.
226  *
227  * We deliberately truncate rather than rounding; this is so that single
228  * adjustments inside a backend can affect the shared estimate (see the
229  * asymmetric adjustment rules above).
230  */
231  return (shared_spins_per_delay * 15 + spins_per_delay) / 16;
232 }

References spins_per_delay.

Referenced by AuxiliaryProcKill(), and ProcKill().

Variable Documentation

◆ spins_per_delay

int spins_per_delay = DEFAULT_SPINS_PER_DELAY
static