Drizzled Public API Documentation

thr0loc.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "thr0loc.h"
27 #ifdef UNIV_NONINL
28 #include "thr0loc.ic"
29 #endif
30 
31 #include "sync0sync.h"
32 #include "hash0hash.h"
33 #include "mem0mem.h"
34 #include "srv0srv.h"
35 
36 /*
37  IMPLEMENTATION OF THREAD LOCAL STORAGE
38  ======================================
39 
40 The threads sometimes need private data which depends on the thread id.
41 This is implemented as a hash table, where the hash value is calculated
42 from the thread id, to prepare for a large number of threads. The hash table
43 is protected by a mutex. If you need modify the program and put new data to
44 the thread local storage, just add it to struct thr_local_struct in the
45 header file. */
46 
48 static mutex_t thr_local_mutex;
49 
51 static hash_table_t* thr_local_hash = NULL;
52 
54 typedef struct thr_local_struct thr_local_t;
55 
56 #ifdef UNIV_PFS_MUTEX
57 /* Key to register the mutex with performance schema */
58 UNIV_INTERN mysql_pfs_key_t thr_local_mutex_key;
59 #endif /* UNIV_PFS_MUTEX */
60 
67  os_thread_t handle;
68  ulint slot_no;
70  ibool in_ibuf;
72  hash_node_t hash;
73  ulint magic_n;
74 };
75 
77 #define THR_LOCAL_MAGIC_N 1231234
78 
79 #ifdef UNIV_DEBUG
80 /*******************************************************************/
83 static
84 ibool
85 thr_local_validate(
86 /*===============*/
87  const thr_local_t* local)
88 {
89  ut_ad(local->magic_n == THR_LOCAL_MAGIC_N);
90  ut_ad(local->slot_no == ULINT_UNDEFINED
91  || local->slot_no < OS_THREAD_MAX_N);
92  ut_ad(local->in_ibuf == FALSE || local->in_ibuf == TRUE);
93  return(TRUE);
94 }
95 #endif /* UNIV_DEBUG */
96 
97 /*******************************************************************/
100 static
102 thr_local_get(
103 /*==========*/
104  os_thread_id_t id)
105 {
106  thr_local_t* local;
107 
108 try_again:
109  ut_ad(thr_local_hash);
110  ut_ad(mutex_own(&thr_local_mutex));
111 
112  /* Look for the local struct in the hash table */
113 
114  local = NULL;
115 
116  HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id),
117  thr_local_t*, local, ut_ad(thr_local_validate(local)),
118  os_thread_eq(local->id, id));
119  if (local == NULL) {
120  mutex_exit(&thr_local_mutex);
121 
123 
124  mutex_enter(&thr_local_mutex);
125 
126  goto try_again;
127  }
128 
129  ut_ad(thr_local_validate(local));
130 
131  return(local);
132 }
133 
134 /*******************************************************************/
137 UNIV_INTERN
138 ulint
140 /*==================*/
141  os_thread_id_t id)
142 {
143  ulint slot_no;
144  thr_local_t* local;
145 
146  mutex_enter(&thr_local_mutex);
147 
148  local = thr_local_get(id);
149 
150  slot_no = local->slot_no;
151 
152  mutex_exit(&thr_local_mutex);
153 
154  return(slot_no);
155 }
156 
157 /*******************************************************************/
159 UNIV_INTERN
160 void
162 /*==================*/
163  os_thread_id_t id,
164  ulint slot_no)
165 {
166  thr_local_t* local;
167 
168  mutex_enter(&thr_local_mutex);
169 
170  local = thr_local_get(id);
171 
172  local->slot_no = slot_no;
173 
174  mutex_exit(&thr_local_mutex);
175 }
176 
177 /*******************************************************************/
181 UNIV_INTERN
182 ibool*
184 /*=============================*/
185 {
186  thr_local_t* local;
187 
188  mutex_enter(&thr_local_mutex);
189 
190  local = thr_local_get(os_thread_get_curr_id());
191 
192  mutex_exit(&thr_local_mutex);
193 
194  return(&(local->in_ibuf));
195 }
196 
197 /*******************************************************************/
199 UNIV_INTERN
200 void
202 /*==================*/
203 {
204  thr_local_t* local;
205 
206  if (thr_local_hash == NULL) {
207  thr_local_init();
208  }
209 
210  local = static_cast<thr_local_t *>(mem_alloc(sizeof(thr_local_t)));
211 
212  local->id = os_thread_get_curr_id();
213  local->handle = os_thread_get_curr();
214  local->magic_n = THR_LOCAL_MAGIC_N;
215  local->slot_no = ULINT_UNDEFINED;
216  local->in_ibuf = FALSE;
217 
218  mutex_enter(&thr_local_mutex);
219 
220  HASH_INSERT(thr_local_t, hash, thr_local_hash,
222  local);
223 
224  mutex_exit(&thr_local_mutex);
225 }
226 
227 /*******************************************************************/
229 UNIV_INTERN
230 void
232 /*===========*/
233  os_thread_id_t id)
234 {
235  thr_local_t* local;
236 
237  mutex_enter(&thr_local_mutex);
238 
239  /* Look for the local struct in the hash table */
240 
241  HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id),
242  thr_local_t*, local, ut_ad(thr_local_validate(local)),
243  os_thread_eq(local->id, id));
244  if (local == NULL) {
245  mutex_exit(&thr_local_mutex);
246 
247  return;
248  }
249 
250  HASH_DELETE(thr_local_t, hash, thr_local_hash,
251  os_thread_pf(id), local);
252 
253  mutex_exit(&thr_local_mutex);
254 
255  ut_a(local->magic_n == THR_LOCAL_MAGIC_N);
256  ut_ad(thr_local_validate(local));
257 
258  mem_free(local);
259 }
260 
261 /****************************************************************/
263 UNIV_INTERN
264 void
266 /*================*/
267 {
268 
269  ut_a(thr_local_hash == NULL);
270 
271  thr_local_hash = hash_create(OS_THREAD_MAX_N + 100);
272 
273  mutex_create(thr_local_mutex_key,
274  &thr_local_mutex, SYNC_THR_LOCAL);
275 }
276 
277 /********************************************************************
278 Close the thread local storage module. */
279 UNIV_INTERN
280 void
282 /*=================*/
283 {
284  ulint i;
285 
286  ut_a(thr_local_hash != NULL);
287 
288  /* Free the hash elements. We don't remove them from the table
289  because we are going to destroy the table anyway. */
290  for (i = 0; i < hash_get_n_cells(thr_local_hash); i++) {
291  thr_local_t* local;
292 
293  local = static_cast<thr_local_t *>(HASH_GET_FIRST(thr_local_hash, i));
294 
295  while (local) {
296  thr_local_t* prev_local = local;
297 
298  local = static_cast<thr_local_t *>(HASH_GET_NEXT(hash, prev_local));
299  ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N);
300  ut_ad(thr_local_validate(prev_local));
301  mem_free(prev_local);
302  }
303  }
304 
305  hash_table_free(thr_local_hash);
306  thr_local_hash = NULL;
307 }