mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / include / sync0sync.ic
blobee640abefa652d4961eb781e9aa9e7de46c3a1e3
1 /******************************************************
2 Mutex, the basic synchronization primitive
4 (c) 1995 Innobase Oy
6 Created 9/5/1995 Heikki Tuuri
7 *******************************************************/
9 #if defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86)
10 /* %z0: Use the size of operand %0 which in our case is *m to determine
11 instruction size, it should end up as xchgl. "1" in the input constraint,
12 says that "in" has to go in the same place as "out".*/
13 #define TAS(m, in, out) \
14         asm volatile ("xchg%z0 %2, %0" \
15         : "=g" (*(m)), "=r" (out) \
16         : "1" (in))     /* Note: "1" here refers to "=r" (out) */
17 #endif
19 /**********************************************************************
20 Sets the waiters field in a mutex. */
22 void
23 mutex_set_waiters(
24 /*==============*/
25         mutex_t*        mutex,  /* in: mutex */
26         ulint           n);     /* in: value to set */
27 /**********************************************************************
28 Reserves a mutex for the current thread. If the mutex is reserved, the
29 function spins a preset time (controlled by SYNC_SPIN_ROUNDS) waiting
30 for the mutex before suspending the thread. */
32 void
33 mutex_spin_wait(
34 /*============*/
35         mutex_t*        mutex,          /* in: pointer to mutex */
36         const char*     file_name,      /* in: file name where mutex
37                                         requested */
38         ulint           line);          /* in: line where requested */
39 #ifdef UNIV_SYNC_DEBUG
40 /**********************************************************************
41 Sets the debug information for a reserved mutex. */
43 void
44 mutex_set_debug_info(
45 /*=================*/
46         mutex_t*        mutex,          /* in: mutex */
47         const char*     file_name,      /* in: file where requested */
48         ulint           line);          /* in: line where requested */
49 #endif /* UNIV_SYNC_DEBUG */
50 /**********************************************************************
51 Releases the threads waiting in the primary wait array for this mutex. */
53 void
54 mutex_signal_object(
55 /*================*/
56         mutex_t*        mutex); /* in: mutex */
58 /**********************************************************************
59 Performs an atomic test-and-set instruction to the lock_word field of a
60 mutex. */
61 UNIV_INLINE
62 ulint
63 mutex_test_and_set(
64 /*===============*/
65                                 /* out: the previous value of lock_word: 0 or
66                                 1 */
67         mutex_t*        mutex)  /* in: mutex */
69 #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
70         ulint   res;
71         ulint*  lw;             /* assembler code is used to ensure that
72                                 lock_word is loaded from memory */
73         ut_ad(mutex);
74         ut_ad(sizeof(ulint) == 4);
76         lw = &(mutex->lock_word);
78         __asm   MOV     ECX, lw
79                 __asm   MOV     EDX, 1
80                 __asm   XCHG    EDX, DWORD PTR [ECX]
81                 __asm   MOV     res, EDX
83                 /* The fence below would prevent this thread from
84                 reading the data structure protected by the mutex
85                 before the test-and-set operation is committed, but
86                 the fence is apparently not needed:
88                 In a posting to comp.arch newsgroup (August 10, 1997)
89                 Andy Glew said that in P6 a LOCKed instruction like
90                 XCHG establishes a fence with respect to memory reads
91                 and writes and thus an explicit fence is not
92                 needed. In P5 he seemed to agree with a previous
93                 newsgroup poster that LOCKed instructions serialize
94                 all instruction execution, and, consequently, also
95                 memory operations. This is confirmed in Intel Software
96                 Dev. Manual, Vol. 3. */
98                 /* mutex_fence(); */
100                 return(res);
101 #elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86)
102         ulint   res;
104         TAS(&mutex->lock_word, 1, res);
106         return(res);
107 #else
108         ibool   ret;
110         ret = os_fast_mutex_trylock(&(mutex->os_fast_mutex));
112         if (ret == 0) {
113                 /* We check that os_fast_mutex_trylock does not leak
114                 and allow race conditions */
115                 ut_a(mutex->lock_word == 0);
117                 mutex->lock_word = 1;
118         }
120         return(ret);
121 #endif
124 /**********************************************************************
125 Performs a reset instruction to the lock_word field of a mutex. This
126 instruction also serializes memory operations to the program order. */
127 UNIV_INLINE
128 void
129 mutex_reset_lock_word(
130 /*==================*/
131         mutex_t*        mutex)  /* in: mutex */
133 #if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
134         ulint*  lw;             /* assembler code is used to ensure that
135                                 lock_word is loaded from memory */
136         ut_ad(mutex);
138         lw = &(mutex->lock_word);
140         __asm   MOV     EDX, 0
141                 __asm   MOV     ECX, lw
142                 __asm   XCHG    EDX, DWORD PTR [ECX]
143 #elif defined(not_defined) && defined(__GNUC__) && defined(UNIV_INTEL_X86)
144         ulint   res;
146         TAS(&mutex->lock_word, 0, res);
147 #else
148         mutex->lock_word = 0;
150         os_fast_mutex_unlock(&(mutex->os_fast_mutex));
151 #endif
154 /**********************************************************************
155 Gets the value of the lock word. */
156 UNIV_INLINE
157 ulint
158 mutex_get_lock_word(
159 /*================*/
160         const mutex_t*  mutex)  /* in: mutex */
162         const volatile ulint*   ptr;    /* declared volatile to ensure that
163                                         lock_word is loaded from memory */
164         ut_ad(mutex);
166         ptr = &(mutex->lock_word);
168         return(*ptr);
171 /**********************************************************************
172 Gets the waiters field in a mutex. */
173 UNIV_INLINE
174 ulint
175 mutex_get_waiters(
176 /*==============*/
177                                 /* out: value to set */
178         const mutex_t*  mutex)  /* in: mutex */
180         const volatile ulint*   ptr;    /* declared volatile to ensure that
181                                         the value is read from memory */
182         ut_ad(mutex);
184         ptr = &(mutex->waiters);
186         return(*ptr);           /* Here we assume that the read of a single
187                                 word from memory is atomic */
190 /**********************************************************************
191 Unlocks a mutex owned by the current thread. */
192 UNIV_INLINE
193 void
194 mutex_exit(
195 /*=======*/
196         mutex_t*        mutex)  /* in: pointer to mutex */
198         ut_ad(mutex_own(mutex));
200         ut_d(mutex->thread_id = (os_thread_id_t) ULINT_UNDEFINED);
202 #ifdef UNIV_SYNC_DEBUG
203         sync_thread_reset_level(mutex);
204 #endif
205         mutex_reset_lock_word(mutex);
207         /* A problem: we assume that mutex_reset_lock word
208         is a memory barrier, that is when we read the waiters
209         field next, the read must be serialized in memory
210         after the reset. A speculative processor might
211         perform the read first, which could leave a waiting
212         thread hanging indefinitely.
214         Our current solution call every second
215         sync_arr_wake_threads_if_sema_free()
216         to wake up possible hanging threads if
217         they are missed in mutex_signal_object. */
219         if (mutex_get_waiters(mutex) != 0) {
221                 mutex_signal_object(mutex);
222         }
224 #ifdef UNIV_SYNC_PERF_STAT
225         mutex_exit_count++;
226 #endif
229 /**********************************************************************
230 Locks a mutex for the current thread. If the mutex is reserved, the function
231 spins a preset time (controlled by SYNC_SPIN_ROUNDS), waiting for the mutex
232 before suspending the thread. */
233 UNIV_INLINE
234 void
235 mutex_enter_func(
236 /*=============*/
237         mutex_t*        mutex,          /* in: pointer to mutex */
238         const char*     file_name,      /* in: file name where locked */
239         ulint           line)           /* in: line where locked */
241         ut_ad(mutex_validate(mutex));
242         ut_ad(!mutex_own(mutex));
244         /* Note that we do not peek at the value of lock_word before trying
245         the atomic test_and_set; we could peek, and possibly save time. */
247 #if defined UNIV_DEBUG && !defined UNIV_HOTBACKUP
248         mutex->count_using++;
249 #endif /* UNIV_DEBUG && !UNIV_HOTBACKUP */
251         if (!mutex_test_and_set(mutex)) {
252                 ut_d(mutex->thread_id = os_thread_get_curr_id());
253 #ifdef UNIV_SYNC_DEBUG
254                 mutex_set_debug_info(mutex, file_name, line);
255 #endif
256                 return; /* Succeeded! */
257         }
259         mutex_spin_wait(mutex, file_name, line);