1
/*****************************************************************************
3
Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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
17
*****************************************************************************/
19
/**************************************************//**
21
The thread local storage
23
Created 10/5/1995 Heikki Tuuri
24
*******************************************************/
31
#include "sync0sync.h"
32
#include "hash0hash.h"
37
IMPLEMENTATION OF THREAD LOCAL STORAGE
38
======================================
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
47
/** Mutex protecting thr_local_hash */
48
static mutex_t thr_local_mutex;
50
/** The hash table. The module is not yet initialized when it is NULL. */
51
static hash_table_t* thr_local_hash = NULL;
53
/** Thread local data */
54
typedef struct thr_local_struct thr_local_t;
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 */
61
/** @brief Thread local data.
62
The private data for each thread should be put to
63
the structure below and the accessor functions written
65
struct thr_local_struct{
66
os_thread_id_t id; /*!< id of the thread which owns this struct */
67
os_thread_t handle; /*!< operating system handle to the thread */
68
ulint slot_no;/*!< the index of the slot in the thread table
70
ibool in_ibuf;/*!< TRUE if the the thread is doing an ibuf
72
hash_node_t hash; /*!< hash chain node */
73
ulint magic_n;/*!< magic number (THR_LOCAL_MAGIC_N) */
76
/** The value of thr_local_struct::magic_n */
77
#define THR_LOCAL_MAGIC_N 1231234
80
/*******************************************************************//**
81
Validates thread local data.
82
@return TRUE if valid */
87
const thr_local_t* local) /*!< in: data to validate */
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);
95
#endif /* UNIV_DEBUG */
97
/*******************************************************************//**
98
Returns the local storage struct for a thread.
99
@return local storage */
104
os_thread_id_t id) /*!< in: thread id of the thread */
109
ut_ad(thr_local_hash);
110
ut_ad(mutex_own(&thr_local_mutex));
112
/* Look for the local struct in the hash table */
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));
120
mutex_exit(&thr_local_mutex);
124
mutex_enter(&thr_local_mutex);
129
ut_ad(thr_local_validate(local));
134
/*******************************************************************//**
135
Gets the slot number in the thread table of a thread.
136
@return slot number */
139
thr_local_get_slot_no(
140
/*==================*/
141
os_thread_id_t id) /*!< in: thread id of the thread */
146
mutex_enter(&thr_local_mutex);
148
local = thr_local_get(id);
150
slot_no = local->slot_no;
152
mutex_exit(&thr_local_mutex);
157
/*******************************************************************//**
158
Sets the slot number in the thread table of a thread. */
161
thr_local_set_slot_no(
162
/*==================*/
163
os_thread_id_t id, /*!< in: thread id of the thread */
164
ulint slot_no)/*!< in: slot number */
168
mutex_enter(&thr_local_mutex);
170
local = thr_local_get(id);
172
local->slot_no = slot_no;
174
mutex_exit(&thr_local_mutex);
177
/*******************************************************************//**
178
Returns pointer to the 'in_ibuf' field within the current thread local
180
@return pointer to the in_ibuf field */
183
thr_local_get_in_ibuf_field(void)
184
/*=============================*/
188
mutex_enter(&thr_local_mutex);
190
local = thr_local_get(os_thread_get_curr_id());
192
mutex_exit(&thr_local_mutex);
194
return(&(local->in_ibuf));
197
/*******************************************************************//**
198
Creates a local storage struct for the calling new thread. */
201
thr_local_create(void)
202
/*==================*/
206
if (thr_local_hash == NULL) {
210
local = static_cast<thr_local_t *>(mem_alloc(sizeof(thr_local_t)));
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;
218
mutex_enter(&thr_local_mutex);
220
HASH_INSERT(thr_local_t, hash, thr_local_hash,
221
os_thread_pf(os_thread_get_curr_id()),
224
mutex_exit(&thr_local_mutex);
227
/*******************************************************************//**
228
Frees the local storage struct for the specified thread. */
233
os_thread_id_t id) /*!< in: thread id */
237
mutex_enter(&thr_local_mutex);
239
/* Look for the local struct in the hash table */
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));
245
mutex_exit(&thr_local_mutex);
250
HASH_DELETE(thr_local_t, hash, thr_local_hash,
251
os_thread_pf(id), local);
253
mutex_exit(&thr_local_mutex);
255
ut_a(local->magic_n == THR_LOCAL_MAGIC_N);
256
ut_ad(thr_local_validate(local));
261
/****************************************************************//**
262
Initializes the thread local storage module. */
269
ut_a(thr_local_hash == NULL);
271
thr_local_hash = hash_create(OS_THREAD_MAX_N + 100);
273
mutex_create(thr_local_mutex_key,
274
&thr_local_mutex, SYNC_THR_LOCAL);
277
/********************************************************************
278
Close the thread local storage module. */
281
thr_local_close(void)
282
/*=================*/
286
ut_a(thr_local_hash != NULL);
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++) {
293
local = static_cast<thr_local_t *>(HASH_GET_FIRST(thr_local_hash, i));
296
thr_local_t* prev_local = local;
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);
305
hash_table_free(thr_local_hash);
306
thr_local_hash = NULL;