Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * spin.c
4 : * Hardware-independent implementation of spinlocks.
5 : *
6 : *
7 : * For machines that have test-and-set (TAS) instructions, s_lock.h/.c
8 : * define the spinlock implementation. This file contains only a stub
9 : * implementation for spinlocks using PGSemaphores. Unless semaphores
10 : * are implemented in a way that doesn't involve a kernel call, this
11 : * is too slow to be very useful :-(
12 : *
13 : *
14 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
15 : * Portions Copyright (c) 1994, Regents of the University of California
16 : *
17 : *
18 : * IDENTIFICATION
19 : * src/backend/storage/lmgr/spin.c
20 : *
21 : *-------------------------------------------------------------------------
22 : */
23 : #include "postgres.h"
24 :
25 : #include "storage/pg_sema.h"
26 : #include "storage/shmem.h"
27 : #include "storage/spin.h"
28 :
29 :
30 : #ifndef HAVE_SPINLOCKS
31 : PGSemaphore *SpinlockSemaArray;
32 : #endif
33 :
34 : /*
35 : * Report the amount of shared memory needed to store semaphores for spinlock
36 : * support.
37 : */
38 : Size
39 5 : SpinlockSemaSize(void)
40 : {
41 5 : return SpinlockSemas() * sizeof(PGSemaphore);
42 : }
43 :
44 : #ifdef HAVE_SPINLOCKS
45 :
46 : /*
47 : * Report number of semaphores needed to support spinlocks.
48 : */
49 : int
50 10 : SpinlockSemas(void)
51 : {
52 10 : return 0;
53 : }
54 : #else /* !HAVE_SPINLOCKS */
55 :
56 : /*
57 : * No TAS, so spinlocks are implemented as PGSemaphores.
58 : */
59 :
60 :
61 : /*
62 : * Report number of semaphores needed to support spinlocks.
63 : */
64 : int
65 : SpinlockSemas(void)
66 : {
67 : return NUM_SPINLOCK_SEMAPHORES + NUM_ATOMICS_SEMAPHORES;
68 : }
69 :
70 : /*
71 : * Initialize spinlock emulation.
72 : *
73 : * This must be called after PGReserveSemaphores().
74 : */
75 : void
76 : SpinlockSemaInit(void)
77 : {
78 : PGSemaphore *spinsemas;
79 : int nsemas = SpinlockSemas();
80 : int i;
81 :
82 : /*
83 : * We must use ShmemAllocUnlocked(), since the spinlock protecting
84 : * ShmemAlloc() obviously can't be ready yet.
85 : */
86 : spinsemas = (PGSemaphore *) ShmemAllocUnlocked(SpinlockSemaSize());
87 : for (i = 0; i < nsemas; ++i)
88 : spinsemas[i] = PGSemaphoreCreate();
89 : SpinlockSemaArray = spinsemas;
90 : }
91 :
92 : /*
93 : * s_lock.h hardware-spinlock emulation using semaphores
94 : *
95 : * We map all spinlocks onto a set of NUM_SPINLOCK_SEMAPHORES semaphores.
96 : * It's okay to map multiple spinlocks onto one semaphore because no process
97 : * should ever hold more than one at a time. We just need enough semaphores
98 : * so that we aren't adding too much extra contention from that.
99 : *
100 : * slock_t is just an int for this implementation; it holds the spinlock
101 : * number from 1..NUM_SPINLOCK_SEMAPHORES. We intentionally ensure that 0
102 : * is not a valid value, so that testing with this code can help find
103 : * failures to initialize spinlocks.
104 : */
105 :
106 : void
107 : s_init_lock_sema(volatile slock_t *lock, bool nested)
108 : {
109 : static int counter = 0;
110 :
111 : *lock = ((++counter) % NUM_SPINLOCK_SEMAPHORES) + 1;
112 : }
113 :
114 : void
115 : s_unlock_sema(volatile slock_t *lock)
116 : {
117 : int lockndx = *lock;
118 :
119 : if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
120 : elog(ERROR, "invalid spinlock number: %d", lockndx);
121 : PGSemaphoreUnlock(SpinlockSemaArray[lockndx - 1]);
122 : }
123 :
124 : bool
125 : s_lock_free_sema(volatile slock_t *lock)
126 : {
127 : /* We don't currently use S_LOCK_FREE anyway */
128 : elog(ERROR, "spin.c does not support S_LOCK_FREE()");
129 : return false;
130 : }
131 :
132 : int
133 : tas_sema(volatile slock_t *lock)
134 : {
135 : int lockndx = *lock;
136 :
137 : if (lockndx <= 0 || lockndx > NUM_SPINLOCK_SEMAPHORES)
138 : elog(ERROR, "invalid spinlock number: %d", lockndx);
139 : /* Note that TAS macros return 0 if *success* */
140 : return !PGSemaphoreTryLock(SpinlockSemaArray[lockndx - 1]);
141 : }
142 :
143 : #endif /* !HAVE_SPINLOCKS */
|