PostgreSQL Source Code  git master
s_lock.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  SpinDelayStatus
 

Macros

#define S_LOCK_FREE(lock)   s_lock_free_sema(lock)
 
#define S_UNLOCK(lock)   s_unlock_sema(lock)
 
#define S_INIT_LOCK(lock)   s_init_lock_sema(lock, false)
 
#define TAS(lock)   tas_sema(lock)
 
#define S_LOCK(lock)    (TAS(lock) ? s_lock((lock), __FILE__, __LINE__, __func__) : 0)
 
#define SPIN_DELAY()   ((void) 0)
 
#define TAS_SPIN(lock)   TAS(lock)
 
#define DEFAULT_SPINS_PER_DELAY   100
 
#define init_local_spin_delay(status)   init_spin_delay(status, __FILE__, __LINE__, __func__)
 

Typedefs

typedef int slock_t
 

Functions

bool s_lock_free_sema (volatile slock_t *lock)
 
void s_unlock_sema (volatile slock_t *lock)
 
void s_init_lock_sema (volatile slock_t *lock, bool nested)
 
int tas_sema (volatile slock_t *lock)
 
int s_lock (volatile slock_t *lock, const char *file, int line, const char *func)
 
void set_spins_per_delay (int shared_spins_per_delay)
 
int update_spins_per_delay (int shared_spins_per_delay)
 
static void init_spin_delay (SpinDelayStatus *status, const char *file, int line, const char *func)
 
void perform_spin_delay (SpinDelayStatus *status)
 
void finish_spin_delay (SpinDelayStatus *status)
 

Variables

PGDLLIMPORT slock_t dummy_spinlock
 

Macro Definition Documentation

◆ DEFAULT_SPINS_PER_DELAY

#define DEFAULT_SPINS_PER_DELAY   100

Definition at line 832 of file s_lock.h.

◆ init_local_spin_delay

#define init_local_spin_delay (   status)    init_spin_delay(status, __FILE__, __LINE__, __func__)

Definition at line 863 of file s_lock.h.

◆ S_INIT_LOCK

#define S_INIT_LOCK (   lock)    s_init_lock_sema(lock, false)

Definition at line 763 of file s_lock.h.

◆ S_LOCK

#define S_LOCK (   lock)     (TAS(lock) ? s_lock((lock), __FILE__, __LINE__, __func__) : 0)

Definition at line 775 of file s_lock.h.

◆ S_LOCK_FREE

#define S_LOCK_FREE (   lock)    s_lock_free_sema(lock)

Definition at line 761 of file s_lock.h.

◆ S_UNLOCK

#define S_UNLOCK (   lock)    s_unlock_sema(lock)

Definition at line 762 of file s_lock.h.

◆ SPIN_DELAY

#define SPIN_DELAY ( )    ((void) 0)

Definition at line 810 of file s_lock.h.

◆ TAS

#define TAS (   lock)    tas_sema(lock)

Definition at line 764 of file s_lock.h.

◆ TAS_SPIN

#define TAS_SPIN (   lock)    TAS(lock)

Definition at line 821 of file s_lock.h.

Typedef Documentation

◆ slock_t

typedef int slock_t

Definition at line 754 of file s_lock.h.

Function Documentation

◆ finish_spin_delay()

void finish_spin_delay ( SpinDelayStatus status)

Definition at line 186 of file s_lock.c.

187 {
188  if (status->cur_delay == 0)
189  {
190  /* we never had to delay */
193  }
194  else
195  {
198  }
199 }
#define Min(x, y)
Definition: c.h:993
#define Max(x, y)
Definition: c.h:987
#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:67

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().

◆ init_spin_delay()

static void init_spin_delay ( SpinDelayStatus status,
const char *  file,
int  line,
const char *  func 
)
inlinestatic

Definition at line 852 of file s_lock.h.

854 {
855  status->spins = 0;
856  status->delays = 0;
857  status->cur_delay = 0;
858  status->file = file;
859  status->line = line;
860  status->func = func;
861 }
const char * file
Definition: s_lock.h:846
const char * func
Definition: s_lock.h:848

References SpinDelayStatus::cur_delay, SpinDelayStatus::delays, SpinDelayStatus::file, SpinDelayStatus::func, SpinDelayStatus::line, and SpinDelayStatus::spins.

Referenced by s_lock().

◆ perform_spin_delay()

void perform_spin_delay ( SpinDelayStatus status)

Definition at line 126 of file s_lock.c.

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

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_init_lock_sema()

void s_init_lock_sema ( volatile slock_t lock,
bool  nested 
)

Definition at line 121 of file spin.c.

122 {
123  static uint32 counter = 0;
124  uint32 offset;
125  uint32 sema_total;
126  uint32 idx;
127 
128  if (nested)
129  {
130  /*
131  * To allow nesting atomics inside spinlocked sections, use a
132  * different spinlock. See comment above.
133  */
134  offset = 1 + NUM_SPINLOCK_SEMAPHORES;
135  sema_total = NUM_ATOMICS_SEMAPHORES;
136  }
137  else
138  {
139  offset = 1;
140  sema_total = NUM_SPINLOCK_SEMAPHORES;
141  }
142 
143  idx = (counter++ % sema_total) + offset;
144 
145  /* double check we did things correctly */
147 
148  *lock = idx;
149 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
unsigned int uint32
Definition: c.h:495
#define NUM_ATOMICS_SEMAPHORES
#define NUM_SPINLOCK_SEMAPHORES
static void s_check_valid(int lockndx)
Definition: spin.c:114

References idx(), NUM_ATOMICS_SEMAPHORES, NUM_SPINLOCK_SEMAPHORES, and s_check_valid().

Referenced by pg_atomic_init_flag_impl(), pg_atomic_init_u32_impl(), and pg_atomic_init_u64_impl().

◆ s_lock()

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

Definition at line 93 of file s_lock.c.

94 {
95  SpinDelayStatus delayStatus;
96 
97  init_spin_delay(&delayStatus, file, line, func);
98 
99  while (TAS_SPIN(lock))
100  {
101  perform_spin_delay(&delayStatus);
102  }
103 
104  finish_spin_delay(&delayStatus);
105 
106  return delayStatus.delays;
107 }
void perform_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:126
void finish_spin_delay(SpinDelayStatus *status)
Definition: s_lock.c:186
#define TAS_SPIN(lock)
Definition: s_lock.h:821
static void init_spin_delay(SpinDelayStatus *status, const char *file, int line, const char *func)
Definition: s_lock.h:852

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

Referenced by test_spinlock().

◆ s_lock_free_sema()

bool s_lock_free_sema ( volatile slock_t lock)

Definition at line 162 of file spin.c.

163 {
164  /* We don't currently use S_LOCK_FREE anyway */
165  elog(ERROR, "spin.c does not support S_LOCK_FREE()");
166  return false;
167 }
#define ERROR
Definition: elog.h:39

References elog(), and ERROR.

◆ s_unlock_sema()

void s_unlock_sema ( volatile slock_t lock)

Definition at line 152 of file spin.c.

153 {
154  int lockndx = *lock;
155 
156  s_check_valid(lockndx);
157 
158  PGSemaphoreUnlock(SpinlockSemaArray[lockndx - 1]);
159 }
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: posix_sema.c:340
PGSemaphore * SpinlockSemaArray
Definition: spin.c:42

References PGSemaphoreUnlock(), s_check_valid(), and SpinlockSemaArray.

◆ set_spins_per_delay()

void set_spins_per_delay ( int  shared_spins_per_delay)

Definition at line 207 of file s_lock.c.

208 {
209  spins_per_delay = shared_spins_per_delay;
210 }

References spins_per_delay.

Referenced by InitAuxiliaryProcess(), and InitProcess().

◆ tas_sema()

int tas_sema ( volatile slock_t lock)

Definition at line 170 of file spin.c.

171 {
172  int lockndx = *lock;
173 
174  s_check_valid(lockndx);
175 
176  /* Note that TAS macros return 0 if *success* */
177  return !PGSemaphoreTryLock(SpinlockSemaArray[lockndx - 1]);
178 }
bool PGSemaphoreTryLock(PGSemaphore sema)
Definition: posix_sema.c:365

References PGSemaphoreTryLock(), s_check_valid(), and SpinlockSemaArray.

◆ update_spins_per_delay()

int update_spins_per_delay ( int  shared_spins_per_delay)

Definition at line 218 of file s_lock.c.

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

References spins_per_delay.

Referenced by AuxiliaryProcKill(), and ProcKill().

Variable Documentation

◆ dummy_spinlock

PGDLLIMPORT slock_t dummy_spinlock
extern

Definition at line 65 of file s_lock.c.

Referenced by startup_hacks().