95
95
it and did not see the waiters byte set to 1, a case which would lead the
96
96
other thread to an infinite wait.
98
LEMMA 1: After a thread resets the event of the cell it reserves for waiting
100
for a mutex, some thread will eventually call sync_array_signal_object with
101
the mutex as an argument. Thus no infinite wait is possible.
98
LEMMA 1: After a thread resets the event of a mutex (or rw_lock), some
100
thread will eventually call os_event_set() on that particular event.
101
Thus no infinite wait is possible in this case.
103
103
Proof: After making the reservation the thread sets the waiters field in the
104
104
mutex to 1. Then it checks that the mutex is still reserved by some thread,
105
105
or it reserves the mutex for itself. In any case, some thread (which may be
106
106
also some earlier thread, not necessarily the one currently holding the mutex)
107
107
will set the waiters field to 0 in mutex_exit, and then call
108
sync_array_signal_object with the mutex as an argument.
108
os_event_set() with the mutex as an argument.
111
LEMMA 2: If an os_event_set() call is made after some thread has called
113
the os_event_reset() and before it starts wait on that event, the call
114
will not be lost to the second thread. This is true even if there is an
115
intervening call to os_event_reset() by another thread.
116
Thus no infinite wait is possible in this case.
118
Proof (non-windows platforms): os_event_reset() returns a monotonically
119
increasing value of signal_count. This value is increased at every
120
call of os_event_set() If thread A has called os_event_reset() followed
121
by thread B calling os_event_set() and then some other thread C calling
122
os_event_reset(), the is_set flag of the event will be set to FALSE;
123
but now if thread A calls os_event_wait_low() with the signal_count
124
value returned from the earlier call of os_event_reset(), it will
125
return immediately without waiting.
128
Proof (windows): If there is a writer thread which is forced to wait for
129
the lock, it may be able to set the state of rw_lock to RW_LOCK_WAIT_EX
130
The design of rw_lock ensures that there is one and only one thread
131
that is able to change the state to RW_LOCK_WAIT_EX and this thread is
132
guaranteed to acquire the lock after it is released by the current
133
holders and before any other waiter gets the lock.
134
On windows this thread waits on a separate event i.e.: wait_ex_event.
135
Since only one thread can wait on this event there is no chance
136
of this event getting reset before the writer starts wait on it.
137
Therefore, this thread is guaranteed to catch the os_set_event()
138
signalled unconditionally at the release of the lock.
111
141
/* The number of system calls made in this module. Intended for performance
114
ulint mutex_system_call_count = 0;
144
UNIV_INTERN ulint mutex_system_call_count = 0;
116
146
/* Number of spin waits on mutexes: for performance monitoring */
118
148
/* round=one iteration of a spin loop */
119
ulint mutex_spin_round_count = 0;
120
ulint mutex_spin_wait_count = 0;
121
ulint mutex_os_wait_count = 0;
122
ulint mutex_exit_count = 0;
149
UNIV_INTERN ulint mutex_spin_round_count = 0;
150
UNIV_INTERN ulint mutex_spin_wait_count = 0;
151
UNIV_INTERN ulint mutex_os_wait_count = 0;
152
UNIV_INTERN ulint mutex_exit_count = 0;
124
154
/* The global array of wait cells for implementation of the database's own
125
155
mutexes and read-write locks */
126
sync_array_t* sync_primary_wait_array;
156
UNIV_INTERN sync_array_t* sync_primary_wait_array;
128
158
/* This variable is set to TRUE when sync_init is called */
129
ibool sync_initialized = FALSE;
159
UNIV_INTERN ibool sync_initialized = FALSE;
132
162
typedef struct sync_level_struct sync_level_t;
136
166
/* The latch levels currently owned by threads are stored in this data
137
167
structure; the size of this array is OS_THREAD_MAX_N */
139
sync_thread_t* sync_thread_level_arrays;
169
UNIV_INTERN sync_thread_t* sync_thread_level_arrays;
141
171
/* Mutex protecting sync_thread_level_arrays */
142
mutex_t sync_thread_mutex;
172
UNIV_INTERN mutex_t sync_thread_mutex;
143
173
#endif /* UNIV_SYNC_DEBUG */
145
175
/* Global list of database mutexes (not OS mutexes) created. */
146
ut_list_base_node_t mutex_list;
176
UNIV_INTERN ut_list_base_node_t mutex_list;
148
178
/* Mutex protecting the mutex_list variable */
149
mutex_t mutex_list_mutex;
179
UNIV_INTERN mutex_t mutex_list_mutex;
151
181
#ifdef UNIV_SYNC_DEBUG
152
182
/* Latching order checks start when this is set TRUE */
153
ibool sync_order_checks_on = FALSE;
183
UNIV_INTERN ibool sync_order_checks_on = FALSE;
154
184
#endif /* UNIV_SYNC_DEBUG */
156
186
struct sync_thread_struct{
171
201
/**********************************************************************
172
A noninlined function that reserves a mutex. In ha_innodb.cc we have disabled
173
inlining of InnoDB functions, and no inlined functions should be called from
174
there. That is why we need to duplicate the inlined function here. */
177
mutex_enter_noninline(
178
/*==================*/
179
mutex_t* mutex) /* in: mutex */
184
/**********************************************************************
188
mutex_exit_noninline(
189
/*=================*/
190
mutex_t* mutex) /* in: mutex */
195
/**********************************************************************
196
202
Creates, or rather, initializes a mutex object in a specified memory
197
203
location (which must be appropriately aligned). The mutex is initialized
198
204
in the reset state. Explicit freeing of the mutex with mutex_free is
199
205
necessary only if the memory block containing it is freed. */
202
208
mutex_create_func(
203
209
/*==============*/
1040
1048
/* Do no order checking */
1042
1050
case SYNC_MEM_POOL:
1043
ut_a(sync_thread_levels_g(array, SYNC_MEM_POOL));
1045
1051
case SYNC_MEM_HASH:
1046
ut_a(sync_thread_levels_g(array, SYNC_MEM_HASH));
1048
1052
case SYNC_RECV:
1049
ut_a(sync_thread_levels_g(array, SYNC_RECV));
1051
1053
case SYNC_WORK_QUEUE:
1052
ut_a(sync_thread_levels_g(array, SYNC_WORK_QUEUE));
1055
ut_a(sync_thread_levels_g(array, SYNC_LOG));
1057
1055
case SYNC_THR_LOCAL:
1058
ut_a(sync_thread_levels_g(array, SYNC_THR_LOCAL));
1060
1056
case SYNC_ANY_LATCH:
1061
ut_a(sync_thread_levels_g(array, SYNC_ANY_LATCH));
1063
1057
case SYNC_TRX_SYS_HEADER:
1064
ut_a(sync_thread_levels_g(array, SYNC_TRX_SYS_HEADER));
1058
case SYNC_FILE_FORMAT_TAG:
1066
1059
case SYNC_DOUBLEWRITE:
1067
ut_a(sync_thread_levels_g(array, SYNC_DOUBLEWRITE));
1061
case SYNC_SEARCH_SYS:
1062
case SYNC_TRX_LOCK_HEAP:
1064
case SYNC_IBUF_BITMAP_MUTEX:
1067
case SYNC_PURGE_LATCH:
1068
case SYNC_PURGE_SYS:
1069
case SYNC_DICT_AUTOINC_MUTEX:
1070
case SYNC_DICT_OPERATION:
1071
case SYNC_DICT_HEADER:
1072
case SYNC_TRX_I_S_RWLOCK:
1073
case SYNC_TRX_I_S_LAST_READ:
1074
if (!sync_thread_levels_g(array, level)) {
1076
"InnoDB: sync_thread_levels_g(array, %lu)"
1077
" does not hold!\n", level);
1069
1081
case SYNC_BUF_BLOCK:
1070
1082
ut_a((sync_thread_levels_contain(array, SYNC_BUF_POOL)
1071
1083
&& sync_thread_levels_g(array, SYNC_BUF_BLOCK - 1))
1072
1084
|| sync_thread_levels_g(array, SYNC_BUF_BLOCK));
1075
ut_a(sync_thread_levels_g(array, SYNC_BUF_POOL));
1077
case SYNC_SEARCH_SYS:
1078
ut_a(sync_thread_levels_g(array, SYNC_SEARCH_SYS));
1080
case SYNC_TRX_LOCK_HEAP:
1081
ut_a(sync_thread_levels_g(array, SYNC_TRX_LOCK_HEAP));
1083
1086
case SYNC_REC_LOCK:
1084
1087
ut_a((sync_thread_levels_contain(array, SYNC_KERNEL)
1085
1088
&& sync_thread_levels_g(array, SYNC_REC_LOCK - 1))
1086
1089
|| sync_thread_levels_g(array, SYNC_REC_LOCK));
1089
ut_a(sync_thread_levels_g(array, SYNC_KERNEL));
1091
1091
case SYNC_IBUF_BITMAP:
1092
1092
ut_a((sync_thread_levels_contain(array, SYNC_IBUF_BITMAP_MUTEX)
1093
1093
&& sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1))
1094
1094
|| sync_thread_levels_g(array, SYNC_IBUF_BITMAP));
1096
case SYNC_IBUF_BITMAP_MUTEX:
1097
ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP_MUTEX));
1099
1096
case SYNC_FSP_PAGE:
1100
1097
ut_a(sync_thread_levels_contain(array, SYNC_FSP));
1116
1113
ut_a(sync_thread_levels_contain(array, SYNC_KERNEL)
1117
1114
&& sync_thread_levels_contain(array, SYNC_FSP_PAGE));
1120
ut_a(sync_thread_levels_g(array, SYNC_RSEG));
1123
ut_a(sync_thread_levels_g(array, SYNC_TRX_UNDO));
1125
case SYNC_PURGE_LATCH:
1126
ut_a(sync_thread_levels_g(array, SYNC_PURGE_LATCH));
1128
case SYNC_PURGE_SYS:
1129
ut_a(sync_thread_levels_g(array, SYNC_PURGE_SYS));
1131
1116
case SYNC_TREE_NODE:
1132
1117
ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE)
1118
|| sync_thread_levels_contain(array, SYNC_DICT_OPERATION)
1133
1119
|| sync_thread_levels_g(array, SYNC_TREE_NODE - 1));
1135
1121
case SYNC_TREE_NODE_NEW: