From a51280725c911164b47e10b0cd2a62caaacc6e3f Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 23 Sep 2009 15:15:35 +0200 Subject: [PATCH 01/21] WL#5105, ptr_cmp optimised on Solaris, more efficient to use memcmp on Solaris than native impl. --- mysys/ptr_cmp.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 24ab6a1ea9c..9f053f0b3b4 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -22,16 +22,39 @@ #include "mysys_priv.h" #include +#ifdef UNIV_SOLARIS +/* + * On Solaris, memcmp() is normally faster than the unrolled ptr_compare_N + * functions, as memcmp() is usually a platform-specific implementation + * written in assembler, provided in /usr/lib/libc/libc_hwcap*.so.1. + * This implementation is also usually faster than the built-in memcmp + * supplied by GCC, so it is recommended to build with "-fno-builtin-memcmp" + * in CFLAGS if building with GCC on Solaris. + */ + +#include + +static int native_compare(size_t *length, unsigned char **a, unsigned char **b) +{ + return memcmp(*a, *b, *length); +} + +#else /* UNIV_SOLARIS */ + static int ptr_compare(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_2(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_3(size_t *compare_length, uchar **a, uchar **b); +#endif /* UNIV_SOLARIS */ /* Get a pointer to a optimal byte-compare function for a given size */ qsort2_cmp get_ptr_compare (size_t size) { +#ifdef UNIV_SOLARIS + return (qsort2_cmp) native_compare; +#else if (size < 4) return (qsort2_cmp) ptr_compare; switch (size & 3) { @@ -41,6 +64,7 @@ qsort2_cmp get_ptr_compare (size_t size) case 3: return (qsort2_cmp) ptr_compare_3; } return 0; /* Impossible */ +#endif /* UNIV_SOLARIS */ } From a4785fc4a2abeb3f8fbc253b78f558540b949482 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 9 Oct 2009 14:21:29 +0200 Subject: [PATCH 02/21] Moved atomics from 6.0 codebase to prepare for using atomic increments in places where LOCK_thread_count previously was used --- include/atomic/gcc_builtins.h | 10 +- include/atomic/generic-msvc.h | 116 ++++++++++++++ include/atomic/nolock.h | 49 +++--- include/atomic/solaris.h | 8 +- include/atomic/x86-gcc.h | 35 ++-- include/atomic/x86-msvc.h | 96 ----------- include/my_atomic.h | 289 +++++++++++++++++++++++++--------- 7 files changed, 394 insertions(+), 209 deletions(-) create mode 100644 include/atomic/generic-msvc.h delete mode 100644 include/atomic/x86-msvc.h diff --git a/include/atomic/gcc_builtins.h b/include/atomic/gcc_builtins.h index 509701b30a5..100ff80cacd 100644 --- a/include/atomic/gcc_builtins.h +++ b/include/atomic/gcc_builtins.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_GCC_BUILTINS_INCLUDED +#define ATOMIC_GCC_BUILTINS_INCLUDED + /* Copyright (C) 2008 MySQL AB This program is free software; you can redistribute it and/or modify @@ -15,7 +18,7 @@ #define make_atomic_add_body(S) \ v= __sync_fetch_and_add(a, v); -#define make_atomic_swap_body(S) \ +#define make_atomic_fas_body(S) \ v= __sync_lock_test_and_set(a, v); #define make_atomic_cas_body(S) \ int ## S sav; \ @@ -25,9 +28,14 @@ #ifdef MY_ATOMIC_MODE_DUMMY #define make_atomic_load_body(S) ret= *a #define make_atomic_store_body(S) *a= v +#define MY_ATOMIC_MODE "gcc-builtins-up" + #else +#define MY_ATOMIC_MODE "gcc-builtins-smp" #define make_atomic_load_body(S) \ ret= __sync_fetch_and_or(a, 0); #define make_atomic_store_body(S) \ (void) __sync_lock_test_and_set(a, v); #endif + +#endif /* ATOMIC_GCC_BUILTINS_INCLUDED */ diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h new file mode 100644 index 00000000000..f1e1b0e88c9 --- /dev/null +++ b/include/atomic/generic-msvc.h @@ -0,0 +1,116 @@ +/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _atomic_h_cleanup_ +#define _atomic_h_cleanup_ "atomic/generic-msvc.h" + +/* + We don't implement anything specific for MY_ATOMIC_MODE_DUMMY, always use + intrinsics. + 8 and 16-bit atomics are not implemented, but it can be done if necessary. +*/ +#undef MY_ATOMIC_HAS_8_16 + +/* + x86 compilers (both VS2003 or VS2005) never use instrinsics, but generate + function calls to kernel32 instead, even in the optimized build. + We force intrinsics as described in MSDN documentation for + _InterlockedCompareExchange. +*/ +#ifdef _M_IX86 + +#if (_MSC_VER >= 1500) +#include +#else +C_MODE_START +/*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/ +LONG _InterlockedExchange (LONG volatile *Target,LONG Value); +LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp); +LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value); +C_MODE_END + +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchange) +#endif + +#define InterlockedExchange _InterlockedExchange +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedCompareExchange _InterlockedCompareExchange +/* + No need to do something special for InterlockedCompareExchangePointer + as it is a #define to InterlockedCompareExchange. The same applies to + InterlockedExchangePointer. +*/ +#endif /*_M_IX86*/ + +#define MY_ATOMIC_MODE "msvc-intrinsics" +#define IL_EXCHG_ADD32(X,Y) InterlockedExchangeAdd((volatile LONG *)(X),(Y)) +#define IL_COMP_EXCHG32(X,Y,Z) InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z)) +#define IL_COMP_EXCHGptr InterlockedCompareExchangePointer +#define IL_EXCHG32(X,Y) InterlockedExchange((volatile LONG *)(X),(Y)) +#define IL_EXCHGptr InterlockedExchangePointer +#define make_atomic_add_body(S) \ + v= IL_EXCHG_ADD ## S (a, v) +#define make_atomic_cas_body(S) \ + int ## S initial_cmp= *cmp; \ + int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \ + if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a; +#define make_atomic_swap_body(S) \ + v= IL_EXCHG ## S (a, v) +#define make_atomic_load_body(S) \ + ret= 0; /* avoid compiler warning */ \ + ret= IL_COMP_EXCHG ## S (a, ret, ret); + +/* + my_yield_processor (equivalent of x86 PAUSE instruction) should be used + to improve performance on hyperthreaded CPUs. Intel recommends to use it in + spin loops also on non-HT machines to reduce power consumption (see e.g + http://softwarecommunity.intel.com/articles/eng/2004.htm) + + Running benchmarks for spinlocks implemented with InterlockedCompareExchange + and YieldProcessor shows that much better performance is achieved by calling + YieldProcessor in a loop - that is, yielding longer. On Intel boxes setting + loop count in the range 200-300 brought best results. + */ +#ifndef YIELD_LOOPS +#define YIELD_LOOPS 200 +#endif + +static __inline int my_yield_processor() +{ + int i; + for(i=0; i Date: Fri, 9 Oct 2009 14:22:22 +0200 Subject: [PATCH 03/21] A minor change to MySQL's hash where calculation of hash can be done separately to avoid doing it under contended mutex locks --- include/hash.h | 9 +++++++++ mysys/hash.c | 29 +++++++++++++++++++++++++++-- sql/sql_base.cc | 9 +++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/include/hash.h b/include/hash.h index 629b404e8a7..b6fc365ab76 100644 --- a/include/hash.h +++ b/include/hash.h @@ -45,6 +45,7 @@ extern "C" { #define hash_element my_hash_element #define hash_search my_hash_search #define hash_first my_hash_first +#define hash_first_from_hash_value my_hash_first_from_hash_value #define hash_next my_hash_next #define hash_insert my_hash_insert #define hash_delete my_hash_delete @@ -94,8 +95,16 @@ void my_hash_free(HASH *tree); void my_hash_reset(HASH *hash); uchar *my_hash_element(HASH *hash, ulong idx); uchar *my_hash_search(const HASH *info, const uchar *key, size_t length); +uchar *my_hash_search_using_hash_value(const HASH *info, uint hash_value, + const uchar *key, size_t length); +uint my_calc_hash(const HASH *info, const uchar *key, size_t length); uchar *my_hash_first(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); +uchar *my_hash_first_from_hash_value(const HASH *info, + uint hash_value, + const uchar *key, + size_t length, + HASH_SEARCH_STATE *state); uchar *my_hash_next(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); my_bool my_hash_insert(HASH *info, const uchar *data); diff --git a/mysys/hash.c b/mysys/hash.c index 63933abb085..367ac8713dd 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -214,6 +214,20 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length) return my_hash_first(hash, key, length, &state); } +uchar* my_hash_search_using_hash_value(const HASH *hash, + uint hash_value, + const uchar *key, + size_t length) +{ + HASH_SEARCH_STATE state; + return my_hash_first_from_hash_value(hash, hash_value, + key, length, &state); +} + +uint my_calc_hash(const HASH *hash, const uchar *key, size_t length) +{ + return calc_hash(hash, key, length ? length : hash->key_length); +} /* Search after a record based on a key @@ -223,15 +237,26 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length) uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length, HASH_SEARCH_STATE *current_record) +{ + return my_hash_first_from_hash_value(hash, + calc_hash(hash, key, length ? length : hash->key_length), + key, length, current_record); +} + +uchar* my_hash_first_from_hash_value(const HASH *hash, + uint hash_value, + const uchar *key, + size_t length, + HASH_SEARCH_STATE *current_record) { HASH_LINK *pos; uint flag,idx; - DBUG_ENTER("my_hash_first"); + DBUG_ENTER("my_hash_first_from_hash_value"); flag=1; if (hash->records) { - idx= my_hash_mask(calc_hash(hash, key, length ? length : hash->key_length), + idx= my_hash_mask(hash_value, hash->blength, hash->records); do { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b81070000b3..064d277e0b4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2513,6 +2513,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, char key[MAX_DBKEY_LENGTH]; uint key_length; char *alias= table_list->alias; + uint hash_value; HASH_SEARCH_STATE state; DBUG_ENTER("open_table"); @@ -2702,6 +2703,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, on disk. */ + hash_value= my_calc_hash(&open_cache, (uchar*) key, key_length); VOID(pthread_mutex_lock(&LOCK_open)); /* @@ -2744,8 +2746,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, an implicit "pending locks queue" - see wait_for_locked_table_names for details. */ - for (table= (TABLE*) hash_first(&open_cache, (uchar*) key, key_length, - &state); + for (table= (TABLE*) hash_first_from_hash_value(&open_cache, + hash_value, + (uchar*) key, + key_length, + &state); table && table->in_use ; table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length, &state)) From bae553cfcd9ad8b9df8b5305736f6810fbaed43b Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 12 Oct 2009 11:00:39 +0200 Subject: [PATCH 04/21] Backported my_atomic from 6.0-codebase and added support for 64-bit atomics to enable removal of LOCK_thread_count from every query, removed LOCK_thread_count from use in dispatch_command and close of query which is used in every query, now uses atomic increments/decrements instead --- include/Makefile.am | 2 +- include/atomic/rwlock.h | 31 ++++-- include/atomic/x86-gcc.h | 32 +++++- include/my_atomic.h | 12 ++- include/my_global.h | 2 + sql/event_scheduler.cc | 17 ++- sql/log_event.cc | 12 +-- sql/mysql_priv.h | 45 +++++++- sql/mysqld.cc | 6 +- sql/sp_head.cc | 4 +- sql/sql_parse.cc | 57 +++++----- unittest/mysys/my_atomic-t.c | 192 +++++++++++++++------------------- unittest/mysys/thr_template.c | 92 ++++++++++++++++ 13 files changed, 337 insertions(+), 167 deletions(-) create mode 100644 unittest/mysys/thr_template.c diff --git a/include/Makefile.am b/include/Makefile.am index dd6f53f7ca2..d698b1323b8 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -38,7 +38,7 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \ thr_lock.h t_ctype.h violite.h my_md5.h base64.h \ my_handler.h my_time.h \ my_vle.h my_user.h my_atomic.h atomic/nolock.h \ - atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \ + atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \ atomic/solaris.h \ atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h diff --git a/include/atomic/rwlock.h b/include/atomic/rwlock.h index 18b77e93d80..29e22fcb3d5 100644 --- a/include/atomic/rwlock.h +++ b/include/atomic/rwlock.h @@ -1,3 +1,6 @@ +#ifndef ATOMIC_RWLOCK_INCLUDED +#define ATOMIC_RWLOCK_INCLUDED + /* Copyright (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify @@ -13,7 +16,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t; +typedef struct {pthread_mutex_t rw;} my_atomic_rwlock_t; +#define MY_ATOMIC_MODE_RWLOCKS 1 #ifdef MY_ATOMIC_MODE_DUMMY /* @@ -31,18 +35,27 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t; #define my_atomic_rwlock_wrunlock(name) #define MY_ATOMIC_MODE "dummy (non-atomic)" #else -#define my_atomic_rwlock_destroy(name) pthread_rwlock_destroy(& (name)->rw) -#define my_atomic_rwlock_init(name) pthread_rwlock_init(& (name)->rw, 0) -#define my_atomic_rwlock_rdlock(name) pthread_rwlock_rdlock(& (name)->rw) -#define my_atomic_rwlock_wrlock(name) pthread_rwlock_wrlock(& (name)->rw) -#define my_atomic_rwlock_rdunlock(name) pthread_rwlock_unlock(& (name)->rw) -#define my_atomic_rwlock_wrunlock(name) pthread_rwlock_unlock(& (name)->rw) -#define MY_ATOMIC_MODE "rwlocks" +/* + we're using read-write lock macros but map them to mutex locks, and they're + faster. Still, having semantically rich API we can change the + underlying implementation, if necessary. +*/ +#define my_atomic_rwlock_destroy(name) pthread_mutex_destroy(& (name)->rw) +#define my_atomic_rwlock_init(name) pthread_mutex_init(& (name)->rw, 0) +#define my_atomic_rwlock_rdlock(name) pthread_mutex_lock(& (name)->rw) +#define my_atomic_rwlock_wrlock(name) pthread_mutex_lock(& (name)->rw) +#define my_atomic_rwlock_rdunlock(name) pthread_mutex_unlock(& (name)->rw) +#define my_atomic_rwlock_wrunlock(name) pthread_mutex_unlock(& (name)->rw) +#define MY_ATOMIC_MODE "mutex" +#ifndef MY_ATOMIC_MODE_RWLOCKS +#define MY_ATOMIC_MODE_RWLOCKS 1 +#endif #endif #define make_atomic_add_body(S) int ## S sav; sav= *a; *a+= v; v=sav; -#define make_atomic_swap_body(S) int ## S sav; sav= *a; *a= v; v=sav; +#define make_atomic_fas_body(S) int ## S sav; sav= *a; *a= v; v=sav; #define make_atomic_cas_body(S) if ((ret= (*a == *cmp))) *a= set; else *cmp=*a; #define make_atomic_load_body(S) ret= *a; #define make_atomic_store_body(S) *a= v; +#endif /* ATOMIC_RWLOCK_INCLUDED */ diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h index c11483b4083..ba7e7eb572f 100644 --- a/include/atomic/x86-gcc.h +++ b/include/atomic/x86-gcc.h @@ -42,15 +42,37 @@ #endif #ifndef MY_ATOMIC_NO_XADD -#define make_atomic_add_body(S) \ - asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a)) +#define make_atomic_add_body(S) make_atomic_add_body ## S +#define make_atomic_cas_body(S) make_atomic_cas_body ## S #endif -#define make_atomic_fas_body(S) \ - asm volatile ("xchg %0, %1;" : "+q" (v) , "+m" (*a)) -#define make_atomic_cas_body(S) \ + +#define make_atomic_add_body32 \ + asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a)) + +#define make_atomic_cas_body32 \ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \ : "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set)) +#define make_atomic_cas_bodyptr make_atomic_cas_body32 + +#ifndef __x86_64__ +#define make_atomic_add_body64 make_atomic_add_body32 +#define make_atomic_cas_body64 make_atomic_cas_body32 +#else +#define make_atomic_add_body64 \ + int64 tmp=*a; \ + while (!my_atomic_cas64(a, &tmp, tmp+v)); \ + v=tmp; +#define make_atomic_cas_body64 \ + int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \ + asm volatile (LOCK_prefix "; cmpxchg8b %0; setz %2;" \ + : "+m" (*a), "+A" (*cmp), "=q" (ret) \ + :"b" (ebx), "c" (ecx)) +#endif + +#define make_atomic_fas_body(S) \ + asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a)) + #ifdef MY_ATOMIC_MODE_DUMMY #define make_atomic_load_body(S) ret=*a #define make_atomic_store_body(S) *a=v diff --git a/include/my_atomic.h b/include/my_atomic.h index f62d3e32b42..4170e45fe8c 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -37,7 +37,7 @@ my_atomic_store#(&var, what) store 'what' in *var - '#' is substituted by a size suffix - 8, 16, 32, or ptr + '#' is substituted by a size suffix - 8, 16, 32, 64, or ptr (e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr). NOTE This operations are not always atomic, so they always must be @@ -129,6 +129,7 @@ make_transparent_unions(8) make_transparent_unions(16) make_transparent_unions(32) +make_transparent_unions(64) make_transparent_unions(ptr) #undef uintptr #undef make_transparent_unions @@ -140,10 +141,12 @@ make_transparent_unions(ptr) #define U_8 int8 #define U_16 int16 #define U_32 int32 +#define U_64 int64 #define U_ptr intptr #define Uv_8 int8 #define Uv_16 int16 #define Uv_32 int32 +#define Uv_64 int64 #define Uv_ptr intptr #define U_a volatile *a #define U_cmp *cmp @@ -217,6 +220,7 @@ make_atomic_cas(8) make_atomic_cas(16) #endif make_atomic_cas(32) +make_atomic_cas(64) make_atomic_cas(ptr) #ifdef MY_ATOMIC_HAS_8_16 @@ -224,12 +228,14 @@ make_atomic_add(8) make_atomic_add(16) #endif make_atomic_add(32) +make_atomic_add(64) #ifdef MY_ATOMIC_HAS_8_16 make_atomic_load(8) make_atomic_load(16) #endif make_atomic_load(32) +make_atomic_load(64) make_atomic_load(ptr) #ifdef MY_ATOMIC_HAS_8_16 @@ -237,6 +243,7 @@ make_atomic_fas(8) make_atomic_fas(16) #endif make_atomic_fas(32) +make_atomic_fas(64) make_atomic_fas(ptr) #ifdef MY_ATOMIC_HAS_8_16 @@ -244,6 +251,7 @@ make_atomic_store(8) make_atomic_store(16) #endif make_atomic_store(32) +make_atomic_store(64) make_atomic_store(ptr) #ifdef _atomic_h_cleanup_ @@ -254,10 +262,12 @@ make_atomic_store(ptr) #undef U_8 #undef U_16 #undef U_32 +#undef U_64 #undef U_ptr #undef Uv_8 #undef Uv_16 #undef Uv_32 +#undef Uv_64 #undef Uv_ptr #undef a #undef cmp diff --git a/include/my_global.h b/include/my_global.h index 4ad851e9e5d..25d3a9e461b 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -832,6 +832,8 @@ typedef SOCKET_SIZE_TYPE size_socket; #endif #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ +#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL) +#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL #define INT_MIN32 (~0x7FFFFFFFL) #define INT_MAX32 0x7FFFFFFFL #define UINT_MAX32 0xFFFFFFFFL diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 8c0025f9ed4..9c825078370 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -132,9 +132,10 @@ post_init_event_thread(THD *thd) pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); thread_count++; - thread_running++; pthread_mutex_unlock(&LOCK_thread_count); - + my_atomic_rwlock_wrlock(&global_query_id_lock); + inc_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); return FALSE; } @@ -156,10 +157,12 @@ deinit_event_thread(THD *thd) DBUG_PRINT("exit", ("Event thread finishing")); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; delete thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); + my_atomic_rwlock_wrlock(&global_query_id_lock); + dec_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); } @@ -417,10 +420,12 @@ Event_scheduler::start() net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); + my_atomic_rwlock_wrlock(&global_query_id_lock); + dec_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); } end: UNLOCK_DATA(); @@ -550,10 +555,12 @@ error: net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - thread_running--; delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); + my_atomic_rwlock_wrlock(&global_query_id_lock); + dec_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); } delete event_name; DBUG_RETURN(TRUE); diff --git a/sql/log_event.cc b/sql/log_event.cc index e7cbbaba38e..5b286d94c0b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3026,9 +3026,9 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, { thd->set_time((time_t)when); thd->set_query((char*)query_arg, q_len_arg); - VOID(pthread_mutex_lock(&LOCK_thread_count)); + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id = next_query_id(); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s",thd->query)); @@ -4504,9 +4504,9 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, if (rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - VOID(pthread_mutex_lock(&LOCK_thread_count)); + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id = next_query_id(); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + my_atomic_rwlock_wrunlock(&global_query_id_lock); /* Initing thd->row_count is not necessary in theory as this variable has no influence in the case of the slave SQL thread (it is used to generate a @@ -8025,9 +8025,9 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) DBUG_ASSERT(rli->sql_thd == thd); /* Step the query id to mark what columns that are actually used. */ - pthread_mutex_lock(&LOCK_thread_count); + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); - pthread_mutex_unlock(&LOCK_thread_count); + my_atomic_rwlock_wrunlock(&global_query_id_lock); if (!(memory= my_multi_malloc(MYF(MY_WME), &table_list, (uint) sizeof(RPL_TABLE_LIST), diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index cd1a31f0fab..ff6d3578406 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -43,6 +43,7 @@ #include "sql_array.h" #include "sql_plugin.h" #include "scheduler.h" +#include class Parser_state; @@ -75,11 +76,49 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */ typedef ulonglong nested_join_map; /* query_id */ -typedef ulonglong query_id_t; +typedef int64 query_id_t; extern query_id_t global_query_id; +extern int32 thread_running; +extern my_atomic_rwlock_t global_query_id_lock; /* increment query_id and return it. */ -inline query_id_t next_query_id() { return global_query_id++; } +inline query_id_t next_query_id() +{ + query_id_t id; + id= my_atomic_add64(&global_query_id, 1); + return (id+1); +} + +inline query_id_t get_query_id() +{ + query_id_t id; + id= my_atomic_load64(&global_query_id); + return id; +} + +inline int32 +inc_thread_running() +{ + int32 num_thread_running; + num_thread_running= my_atomic_add32(&thread_running, 1); + return (num_thread_running+1); +} + +inline int32 +dec_thread_running() +{ + int32 num_thread_running; + num_thread_running= my_atomic_add32(&thread_running, -1); + return (num_thread_running-1); +} + +inline int32 +get_thread_running() +{ + int32 num_thread_running; + num_thread_running= my_atomic_load32(&thread_running); + return num_thread_running; +} /* useful constants */ extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty; @@ -1994,7 +2033,7 @@ extern bool opt_ignore_builtin_innodb; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; extern bool in_bootstrap; -extern uint volatile thread_count, thread_running, global_read_lock; +extern uint volatile thread_count, global_read_lock; extern uint connection_count; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5dad29a1ab7..1389f0b32f4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -523,7 +523,8 @@ uint mysqld_port_timeout; uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; -uint volatile thread_count, thread_running; +uint volatile thread_count; +int32 thread_running; ulonglong thd_startup_options; ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; @@ -539,6 +540,7 @@ ulonglong max_binlog_cache_size=0; ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; +my_atomic_rwlock_t global_query_id_lock; ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; @@ -1349,6 +1351,7 @@ void clean_up(bool print_message) DBUG_PRINT("quit", ("Error messages freed")); /* Tell main we are ready */ logger.cleanup_end(); + my_atomic_rwlock_destroy(&global_query_id_lock); (void) pthread_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("got thread count lock")); ready_to_exit=1; @@ -7730,6 +7733,7 @@ static int mysql_init_variables(void) what_to_log= ~ (1L << (uint) COM_TIME); refresh_version= 1L; /* Increments on each reload */ global_query_id= thread_id= 1L; + my_atomic_rwlock_init(&global_query_id_lock); strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; myisam_stats_method_str= "nulls_unequal"; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index aed19b76011..83f886a2fdb 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2702,9 +2702,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, */ thd->lex= m_lex; - VOID(pthread_mutex_lock(&LOCK_thread_count)); + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + my_atomic_rwlock_wrunlock(&global_query_id_lock); if (thd->prelocked_mode == NON_PRELOCKED) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a09fed98d65..b0dcc9aff13 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -505,7 +505,9 @@ pthread_handler_t handle_bootstrap(void *arg) We don't need to obtain LOCK_thread_count here because in bootstrap mode we have only one thread. */ + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id=next_query_id(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->set_time(); mysql_parse(thd, thd->query, length, & found_semicolon); close_thread_tables(thd); // Free tables @@ -971,29 +973,30 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id= global_query_id; - - switch( command ) { - /* Ignore these statements. */ - case COM_STATISTICS: - case COM_PING: - break; - /* Only increase id on these statements but don't count them. */ - case COM_STMT_PREPARE: - case COM_STMT_CLOSE: - case COM_STMT_RESET: - next_query_id(); - break; - /* Increase id and count all other statements. */ - default: - statistic_increment(thd->status_var.questions, &LOCK_status); - next_query_id(); + my_atomic_rwlock_wrlock(&global_query_id_lock); + { + query_id_t query_id; + switch( command ) { + /* Ignore these statements. */ + case COM_STATISTICS: + case COM_PING: + query_id= get_query_id(); + break; + /* Only increase id on these statements but don't count them. */ + case COM_STMT_PREPARE: + case COM_STMT_CLOSE: + case COM_STMT_RESET: + query_id= next_query_id() - 1; + break; + /* Increase id and count all other statements. */ + default: + statistic_increment(thd->status_var.questions, &LOCK_status); + query_id= next_query_id() - 1; + } + thd->query_id= query_id; } - - thread_running++; - /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + inc_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); /** Clear the set of flags that are expected to be cleared at the @@ -1259,15 +1262,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (char *) thd->security_ctx->host_or_ip); thd->set_query(beginning_of_next_stmt, length); - VOID(pthread_mutex_lock(&LOCK_thread_count)); /* Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); + my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ - VOID(pthread_mutex_unlock(&LOCK_thread_count)); mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt); } @@ -1610,9 +1613,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd_proc_info(thd, "cleaning up"); thd->set_query(NULL, 0); thd->command=COM_SLEEP; - VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list - thread_running--; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + my_atomic_rwlock_wrlock(&global_query_id_lock); + dec_thread_running(); + my_atomic_rwlock_wrunlock(&global_query_id_lock); thd_proc_info(thd, 0); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c index f2bcd360508..9853d3cf964 100644 --- a/unittest/mysys/my_atomic-t.c +++ b/unittest/mysys/my_atomic-t.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,10 +13,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include -#include +#include "thr_template.c" /* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */ #if __GNUC__ == 3 && __GNUC_MINOR__ == 4 @@ -25,181 +22,162 @@ #define GCC_BUG_WORKAROUND #endif -int32 a32,b32,c32; +volatile uint32 b32; +volatile int32 c32; my_atomic_rwlock_t rwl; -pthread_attr_t thr_attr; -pthread_mutex_t mutex; -pthread_cond_t cond; -int N; - /* add and sub a random number in a loop. Must get 0 at the end */ -pthread_handler_t test_atomic_add_handler(void *arg) +pthread_handler_t test_atomic_add(void *arg) { - int m=*(int *)arg; + int m= (*(int *)arg)/2; GCC_BUG_WORKAROUND int32 x; - for (x=((int)((long)(&m))); m ; m--) + for (x= ((int)(intptr)(&m)); m ; m--) { - x=x*m+0x87654321; + x= (x*m+0x87654321) & INT_MAX32; my_atomic_rwlock_wrlock(&rwl); - my_atomic_add32(&a32, x); + my_atomic_add32(&bad, x); my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrlock(&rwl); - my_atomic_add32(&a32, -x); + my_atomic_add32(&bad, -x); my_atomic_rwlock_wrunlock(&rwl); } pthread_mutex_lock(&mutex); - N--; - if (!N) pthread_cond_signal(&cond); + if (!--running_threads) pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); return 0; } +volatile int64 a64; +/* add and sub a random number in a loop. Must get 0 at the end */ +pthread_handler_t test_atomic_add64(void *arg) +{ + int m= (*(int *)arg)/2; + GCC_BUG_WORKAROUND int64 x; + for (x= ((int64)(intptr)(&m)); m ; m--) + { + x= (x*m+0xfdecba987654321LL) & INT_MAX64; + my_atomic_rwlock_wrlock(&rwl); + my_atomic_add64(&a64, x); + my_atomic_rwlock_wrunlock(&rwl); + + my_atomic_rwlock_wrlock(&rwl); + my_atomic_add64(&a64, -x); + my_atomic_rwlock_wrunlock(&rwl); + } + pthread_mutex_lock(&mutex); + if (!--running_threads) + { + bad= (a64 != 0); + pthread_cond_signal(&cond); + } + pthread_mutex_unlock(&mutex); + return 0; +} + + /* 1. generate thread number 0..N-1 from b32 - 2. add it to a32 + 2. add it to bad 3. swap thread numbers in c32 4. (optionally) one more swap to avoid 0 as a result - 5. subtract result from a32 - must get 0 in a32 at the end + 5. subtract result from bad + must get 0 in bad at the end */ -pthread_handler_t test_atomic_swap_handler(void *arg) +pthread_handler_t test_atomic_fas(void *arg) { - int m=*(int *)arg; - int32 x; + int m= *(int *)arg; + int32 x; my_atomic_rwlock_wrlock(&rwl); - x=my_atomic_add32(&b32, 1); + x= my_atomic_add32(&b32, 1); my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrlock(&rwl); - my_atomic_add32(&a32, x); + my_atomic_add32(&bad, x); my_atomic_rwlock_wrunlock(&rwl); for (; m ; m--) { my_atomic_rwlock_wrlock(&rwl); - x=my_atomic_swap32(&c32, x); + x= my_atomic_fas32(&c32, x); my_atomic_rwlock_wrunlock(&rwl); } if (!x) { my_atomic_rwlock_wrlock(&rwl); - x=my_atomic_swap32(&c32, x); + x= my_atomic_fas32(&c32, x); my_atomic_rwlock_wrunlock(&rwl); } my_atomic_rwlock_wrlock(&rwl); - my_atomic_add32(&a32, -x); + my_atomic_add32(&bad, -x); my_atomic_rwlock_wrunlock(&rwl); pthread_mutex_lock(&mutex); - N--; - if (!N) pthread_cond_signal(&cond); + if (!--running_threads) pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); return 0; } /* - same as test_atomic_add_handler, but my_atomic_add32 is emulated with - (slower) my_atomic_cas32 + same as test_atomic_add, but my_atomic_add32 is emulated with + my_atomic_cas32 - notice that the slowdown is proportional to the + number of CPUs */ -pthread_handler_t test_atomic_cas_handler(void *arg) +pthread_handler_t test_atomic_cas(void *arg) { - int m=*(int *)arg, ok; - GCC_BUG_WORKAROUND int32 x,y; - for (x=((int)((long)(&m))); m ; m--) + int m= (*(int *)arg)/2, ok= 0; + GCC_BUG_WORKAROUND int32 x, y; + for (x= ((int)(intptr)(&m)); m ; m--) { my_atomic_rwlock_wrlock(&rwl); - y=my_atomic_load32(&a32); + y= my_atomic_load32(&bad); my_atomic_rwlock_wrunlock(&rwl); - - x=x*m+0x87654321; + x= (x*m+0x87654321) & INT_MAX32; do { my_atomic_rwlock_wrlock(&rwl); - ok=my_atomic_cas32(&a32, &y, y+x); + ok= my_atomic_cas32(&bad, &y, (uint32)y+x); my_atomic_rwlock_wrunlock(&rwl); - } while (!ok); + } while (!ok) ; do { my_atomic_rwlock_wrlock(&rwl); - ok=my_atomic_cas32(&a32, &y, y-x); + ok= my_atomic_cas32(&bad, &y, y-x); my_atomic_rwlock_wrunlock(&rwl); - } while (!ok); + } while (!ok) ; } pthread_mutex_lock(&mutex); - N--; - if (!N) pthread_cond_signal(&cond); + if (!--running_threads) pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); return 0; } -void test_atomic(const char *test, pthread_handler handler, int n, int m) + +void do_tests() { - pthread_t t; - ulonglong now=my_getsystime(); + plan(6); - a32= 0; - b32= 0; - c32= 0; + bad= my_atomic_initialize(); + ok(!bad, "my_atomic_initialize() returned %d", bad); - diag("Testing %s with %d threads, %d iterations... ", test, n, m); - for (N=n ; n ; n--) - { - if (pthread_create(&t, &thr_attr, handler, &m) != 0) - { - diag("Could not create thread"); - a32= 1; - goto err; - } - } - - pthread_mutex_lock(&mutex); - while (N) - pthread_cond_wait(&cond, &mutex); - pthread_mutex_unlock(&mutex); - now=my_getsystime()-now; -err: - ok(a32 == 0, "tested %s in %g secs", test, ((double)now)/1e7); -} - -int main() -{ - int err; - MY_INIT("my_atomic-t.c"); - - diag("N CPUs: %d", my_getncpus()); - err= my_atomic_initialize(); - - plan(4); - ok(err == 0, "my_atomic_initialize() returned %d", err); - - pthread_attr_init(&thr_attr); - pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); - pthread_mutex_init(&mutex, 0); - pthread_cond_init(&cond, 0); my_atomic_rwlock_init(&rwl); -#ifdef HPUX11 -#define CYCLES 1000 -#else -#define CYCLES 10000 -#endif -#define THREADS 100 - test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS, CYCLES); - test_atomic("my_atomic_swap32", test_atomic_swap_handler, THREADS, CYCLES); - test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS, CYCLES); - /* - workaround until we know why it crashes randomly on some machine - (BUG#22320). - */ - sleep(2); + b32= c32= 0; + test_concurrently("my_atomic_add32", test_atomic_add, THREADS, CYCLES); + b32= c32= 0; + test_concurrently("my_atomic_fas32", test_atomic_fas, THREADS, CYCLES); + b32= c32= 0; + test_concurrently("my_atomic_cas32", test_atomic_cas, THREADS, CYCLES); + + { + int64 b=0x1000200030004000LL; + a64=0; + my_atomic_add64(&a64, b); + ok(a64==b, "add64"); + } + a64=0; + test_concurrently("my_atomic_add64", test_atomic_add64, THREADS, CYCLES); - pthread_mutex_destroy(&mutex); - pthread_cond_destroy(&cond); - pthread_attr_destroy(&thr_attr); my_atomic_rwlock_destroy(&rwl); - return exit_status(); } - diff --git a/unittest/mysys/thr_template.c b/unittest/mysys/thr_template.c new file mode 100644 index 00000000000..1ac03e474fd --- /dev/null +++ b/unittest/mysys/thr_template.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include + +volatile uint32 bad; +pthread_attr_t thr_attr; +pthread_mutex_t mutex; +pthread_cond_t cond; +uint running_threads; + +void do_tests(); + +void test_concurrently(const char *test, pthread_handler handler, int n, int m) +{ + pthread_t t; + ulonglong now= my_getsystime(); + + bad= 0; + + diag("Testing %s with %d threads, %d iterations... ", test, n, m); + for (running_threads= n ; n ; n--) + { + if (pthread_create(&t, &thr_attr, handler, &m) != 0) + { + diag("Could not create thread"); + abort(); + } + } + pthread_mutex_lock(&mutex); + while (running_threads) + pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + + now= my_getsystime()-now; + ok(!bad, "tested %s in %g secs (%d)", test, ((double)now)/1e7, bad); +} + +int main(int argc __attribute__((unused)), char **argv) +{ + MY_INIT("thd_template"); + + if (argv[1] && *argv[1]) + DBUG_SET_INITIAL(argv[1]); + + pthread_mutex_init(&mutex, 0); + pthread_cond_init(&cond, 0); + pthread_attr_init(&thr_attr); + pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); + +#ifdef MY_ATOMIC_MODE_RWLOCKS +#if defined(HPUX11) || defined(__POWERPC__) /* showed to be very slow (scheduler-related) */ +#define CYCLES 300 +#else +#define CYCLES 3000 +#endif +#else +#define CYCLES 3000 +#endif +#define THREADS 30 + + diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE); + + do_tests(); + + /* + workaround until we know why it crashes randomly on some machine + (BUG#22320). + */ + sleep(2); + pthread_mutex_destroy(&mutex); + pthread_cond_destroy(&cond); + pthread_attr_destroy(&thr_attr); + my_end(0); + return exit_status(); +} + From 73f9d9c3718be5e2a137c054f9eeeee5da823373 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 15 Oct 2009 15:03:43 +0200 Subject: [PATCH 05/21] Bug fixes to my_atomic infrastructure --- unittest/mysys/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/unittest/mysys/Makefile.am b/unittest/mysys/Makefile.am index be91ef31c9d..118643bb061 100644 --- a/unittest/mysys/Makefile.am +++ b/unittest/mysys/Makefile.am @@ -16,6 +16,8 @@ AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap +noinst_HEADERS = thr_template.c + LDADD = $(top_builddir)/unittest/mytap/libmytap.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/dbug/libdbug.a \ From 58494ba0dfb4fad76deb712383f71c684bb97091 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 10 Nov 2009 15:09:44 +0100 Subject: [PATCH 06/21] Review comments for LOCK_open patch --- include/hash.h | 10 ++++++---- mysys/hash.c | 26 ++++++++++++++++---------- sql/sql_base.cc | 12 ++++++------ 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/include/hash.h b/include/hash.h index b6fc365ab76..80408f75f4d 100644 --- a/include/hash.h +++ b/include/hash.h @@ -45,7 +45,6 @@ extern "C" { #define hash_element my_hash_element #define hash_search my_hash_search #define hash_first my_hash_first -#define hash_first_from_hash_value my_hash_first_from_hash_value #define hash_next my_hash_next #define hash_insert my_hash_insert #define hash_delete my_hash_delete @@ -65,6 +64,7 @@ extern "C" { /* flags for hash_init */ #define HASH_UNIQUE 1 /* hash_insert fails on duplicate key */ +typedef uint my_hash_value_type; typedef uchar *(*my_hash_get_key)(const uchar *,size_t*,my_bool); typedef void (*my_hash_free_key)(void *); @@ -95,13 +95,15 @@ void my_hash_free(HASH *tree); void my_hash_reset(HASH *hash); uchar *my_hash_element(HASH *hash, ulong idx); uchar *my_hash_search(const HASH *info, const uchar *key, size_t length); -uchar *my_hash_search_using_hash_value(const HASH *info, uint hash_value, +uchar *my_hash_search_using_hash_value(const HASH *info, + my_hash_value_type hash_value, const uchar *key, size_t length); -uint my_calc_hash(const HASH *info, const uchar *key, size_t length); +my_hash_value_type my_calc_hash(const HASH *info, + const uchar *key, size_t length); uchar *my_hash_first(const HASH *info, const uchar *key, size_t length, HASH_SEARCH_STATE *state); uchar *my_hash_first_from_hash_value(const HASH *info, - uint hash_value, + my_hash_value_type hash_value, const uchar *key, size_t length, HASH_SEARCH_STATE *state); diff --git a/mysys/hash.c b/mysys/hash.c index 367ac8713dd..ae754e5bd93 100644 --- a/mysys/hash.c +++ b/mysys/hash.c @@ -33,16 +33,18 @@ typedef struct st_hash_info { uchar *data; /* data for current entry */ } HASH_LINK; -static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength); +static uint my_hash_mask(my_hash_value_type hashnr, + size_t buffmax, size_t maxlength); static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink); static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, size_t length); -static uint calc_hash(const HASH *hash, const uchar *key, size_t length) +static my_hash_value_type calc_hash(const HASH *hash, + const uchar *key, size_t length) { ulong nr1=1, nr2=4; hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2); - return nr1; + return (my_hash_value_type)nr1; } /** @@ -179,7 +181,8 @@ my_hash_key(const HASH *hash, const uchar *record, size_t *length, /* Calculate pos according to keys */ -static uint my_hash_mask(size_t hashnr, size_t buffmax, size_t maxlength) +static uint my_hash_mask(my_hash_value_type hashnr, size_t buffmax, + size_t maxlength) { if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1)); return (hashnr & ((buffmax >> 1) -1)); @@ -200,7 +203,7 @@ static #if !defined(__USLC__) && !defined(__sgi) inline #endif -unsigned int rec_hashnr(HASH *hash,const uchar *record) +my_hash_value_type rec_hashnr(HASH *hash,const uchar *record) { size_t length; uchar *key= (uchar*) my_hash_key(hash, record, &length, 0); @@ -215,7 +218,7 @@ uchar* my_hash_search(const HASH *hash, const uchar *key, size_t length) } uchar* my_hash_search_using_hash_value(const HASH *hash, - uint hash_value, + my_hash_value_type hash_value, const uchar *key, size_t length) { @@ -224,7 +227,8 @@ uchar* my_hash_search_using_hash_value(const HASH *hash, key, length, &state); } -uint my_calc_hash(const HASH *hash, const uchar *key, size_t length) +my_hash_value_type my_calc_hash(const HASH *hash, + const uchar *key, size_t length) { return calc_hash(hash, key, length ? length : hash->key_length); } @@ -244,7 +248,7 @@ uchar* my_hash_first(const HASH *hash, const uchar *key, size_t length, } uchar* my_hash_first_from_hash_value(const HASH *hash, - uint hash_value, + my_hash_value_type hash_value, const uchar *key, size_t length, HASH_SEARCH_STATE *current_record) @@ -356,7 +360,8 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key, my_bool my_hash_insert(HASH *info, const uchar *record) { int flag; - size_t idx,halfbuff,hash_nr,first_index; + size_t idx,halfbuff,first_index; + my_hash_value_type hash_nr; uchar *ptr_to_rec,*ptr_to_rec2; HASH_LINK *data,*empty,*gpos,*gpos2,*pos; @@ -497,7 +502,8 @@ my_bool my_hash_insert(HASH *info, const uchar *record) my_bool my_hash_delete(HASH *hash, uchar *record) { - uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index; + uint blength,pos2,idx,empty_index; + my_hash_value_type pos_hashnr, lastpos_hashnr; HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty; DBUG_ENTER("my_hash_delete"); if (!hash->records) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 064d277e0b4..9116d89ceed 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2513,7 +2513,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, char key[MAX_DBKEY_LENGTH]; uint key_length; char *alias= table_list->alias; - uint hash_value; + my_hash_value_type hash_value; HASH_SEARCH_STATE state; DBUG_ENTER("open_table"); @@ -2746,11 +2746,11 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, an implicit "pending locks queue" - see wait_for_locked_table_names for details. */ - for (table= (TABLE*) hash_first_from_hash_value(&open_cache, - hash_value, - (uchar*) key, - key_length, - &state); + for (table= (TABLE*) my_hash_first_from_hash_value(&open_cache, + hash_value, + (uchar*) key, + key_length, + &state); table && table->in_use ; table= (TABLE*) hash_next(&open_cache, (uchar*) key, key_length, &state)) From a11a7b7a8db6b2151321ae2b3f4a9702de72160a Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 12 Nov 2009 12:17:31 +0100 Subject: [PATCH 07/21] WL#4949, Remove use of LOCK_alarm by instead using SO_SNDTIME0/SO_RCVTIME0 --- configure.in | 67 +++++++++++++++++++++++++++++++++++++++++++++++-- sql/net_serv.cc | 2 ++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 9fe5c741a03..227f7844037 100644 --- a/configure.in +++ b/configure.in @@ -859,10 +859,73 @@ AC_CHECK_DECLS(MHA_MAPSIZE_VA, #include ] ) - - fi +dnl Use of ALARMs to wakeup on timeout on sockets +dnl +dnl This feature makes use of a mutex and is a scalability hog we +dnl try to avoid using. However we need support for SO_SNDTIMEO and +dnl SO_RCVTIMEO socket options for this to work. So we will check +dnl if this feature is supported by a simple AC_RUN_IFELSE macro. However +dnl on some OS's there is support for setting those variables but +dnl they are silently ignored. For those OS's we will not attempt +dnl o use SO_SNDTIMEO and SO_RCVTIMEO even if it is said to work. +dnl See Bug#29093 for the problem with SO_SND/RCVTIMEO on HP/UX. +dnl To use alarm is simple, simply avoid setting anything. + + +AC_CACHE_CHECK([whether SO_SNDTIMEO and SO_RCVTIMEO work], + [mysql_cv_socket_timeout], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([[ + #include + #include + #include + ]],[[ + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct timeval tv; + int ret= 0; + tv.tv_sec= 2; + tv.tv_usec= 0; + ret|= setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + ret|= setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + return !!ret; + ]])], + [mysql_cv_socket_timeout=yes], + [mysql_cv_socket_timeout=no], + [mysql_cv_socket_timeout=no + AC_MSG_WARN([Socket timeout options disabled due to cross-compiling])]) + ]) + +use_alarm=yes + +if test "$mysql_cv_socket_timeout" = yes; then + case $SYSTEM_TYPE in + dnl We trust the result from the following systems + *solaris*) use_alarm=no ;; + *freebsd*) use_alarm=no ;; + *darwin*) use_alarm=no ;; + *) + dnl We trust the result from Linux also + if test "$TARGET_LINUX" = "true"; then + use_alarm=no + fi + dnl We trust no one else for the moment + dnl (Windows is hardcoded to not use alarms) + ;; + esac +fi + +AC_ARG_WITH(alarm, + AS_HELP_STRING([--with-alarm], [Use alarm to implement socket timeout.]), + [use_alarm=$withval], []) + +AC_MSG_CHECKING(whether to use alarms to implement socket timeout) +if test "$use_alarm" = no ; then + AC_DEFINE([NO_ALARM], [1], [No need to use alarm for socket timeout]) +fi +AC_MSG_RESULT($use_alarm) + #-------------------------------------------------------------------- # Check for TCP wrapper support #-------------------------------------------------------------------- diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 5cf3597c638..d54ff1d2779 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -71,8 +71,10 @@ #if defined(__WIN__) || !defined(MYSQL_SERVER) /* The following is because alarms doesn't work on windows. */ +#ifndef NO_ALARM #define NO_ALARM #endif +#endif #ifndef NO_ALARM #include "my_pthread.h" From c9442b67f61e94a2489a360f2f627f5b82341d90 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 20 Nov 2009 16:43:21 +0100 Subject: [PATCH 08/21] WL#5138, review fixes --- sql/event_scheduler.cc | 18 +++++++++--------- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 880bccdd67e..411be5a9d20 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -158,12 +158,12 @@ deinit_event_thread(THD *thd) DBUG_PRINT("exit", ("Event thread finishing")); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - delete thd; - pthread_cond_broadcast(&COND_thread_count); - pthread_mutex_unlock(&LOCK_thread_count); my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); my_atomic_rwlock_wrunlock(&global_query_id_lock); + delete thd; + pthread_cond_broadcast(&COND_thread_count); + pthread_mutex_unlock(&LOCK_thread_count); } @@ -421,12 +421,12 @@ Event_scheduler::start() net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - delete new_thd; - pthread_cond_broadcast(&COND_thread_count); - pthread_mutex_unlock(&LOCK_thread_count); my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); my_atomic_rwlock_wrunlock(&global_query_id_lock); + delete new_thd; + pthread_cond_broadcast(&COND_thread_count); + pthread_mutex_unlock(&LOCK_thread_count); } end: UNLOCK_DATA(); @@ -556,12 +556,12 @@ error: net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - delete new_thd; - pthread_cond_broadcast(&COND_thread_count); - pthread_mutex_unlock(&LOCK_thread_count); my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); my_atomic_rwlock_wrunlock(&global_query_id_lock); + delete new_thd; + pthread_cond_broadcast(&COND_thread_count); + pthread_mutex_unlock(&LOCK_thread_count); } delete event_name; DBUG_RETURN(TRUE); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0caf3197fb8..b816f692320 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -86,9 +86,9 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */ typedef ulonglong nested_join_map; /* query_id */ -typedef int64 query_id_t; +typedef uint64 query_id_t; extern query_id_t global_query_id; -extern int32 thread_running; +extern uint32 thread_running; extern my_atomic_rwlock_t global_query_id_lock; /* increment query_id and return it. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ddc6d53e019..253ed36ce31 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -532,7 +532,7 @@ uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; uint volatile thread_count; -int32 thread_running; +uint32 thread_running; ulonglong thd_startup_options; ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; From 0e613ab88486f275f2fed06dea3f85109d90e248 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 20 Nov 2009 18:42:15 +0100 Subject: [PATCH 09/21] WL#5138, reverted some review fixes --- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b816f692320..0caf3197fb8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -86,9 +86,9 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */ typedef ulonglong nested_join_map; /* query_id */ -typedef uint64 query_id_t; +typedef int64 query_id_t; extern query_id_t global_query_id; -extern uint32 thread_running; +extern int32 thread_running; extern my_atomic_rwlock_t global_query_id_lock; /* increment query_id and return it. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 253ed36ce31..ddc6d53e019 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -532,7 +532,7 @@ uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; uint volatile thread_count; -uint32 thread_running; +int32 thread_running; ulonglong thd_startup_options; ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; From 1ab1e21ef640a50044a5d800c7b402d73d07003e Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 20 Nov 2009 20:01:43 +0100 Subject: [PATCH 10/21] WL#5105, review fix --- mysys/ptr_cmp.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c index 9f053f0b3b4..2005e3eb2b7 100644 --- a/mysys/ptr_cmp.c +++ b/mysys/ptr_cmp.c @@ -22,7 +22,7 @@ #include "mysys_priv.h" #include -#ifdef UNIV_SOLARIS +#ifdef TARGET_OS_SOLARIS /* * On Solaris, memcmp() is normally faster than the unrolled ptr_compare_N * functions, as memcmp() is usually a platform-specific implementation @@ -39,20 +39,20 @@ static int native_compare(size_t *length, unsigned char **a, unsigned char **b) return memcmp(*a, *b, *length); } -#else /* UNIV_SOLARIS */ +#else /* TARGET_OS_SOLARIS */ static int ptr_compare(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_0(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_1(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_2(size_t *compare_length, uchar **a, uchar **b); static int ptr_compare_3(size_t *compare_length, uchar **a, uchar **b); -#endif /* UNIV_SOLARIS */ +#endif /* TARGET_OS_SOLARIS */ /* Get a pointer to a optimal byte-compare function for a given size */ qsort2_cmp get_ptr_compare (size_t size) { -#ifdef UNIV_SOLARIS +#ifdef TARGET_OS_SOLARIS return (qsort2_cmp) native_compare; #else if (size < 4) @@ -64,7 +64,7 @@ qsort2_cmp get_ptr_compare (size_t size) case 3: return (qsort2_cmp) ptr_compare_3; } return 0; /* Impossible */ -#endif /* UNIV_SOLARIS */ +#endif /* TARGET_OS_SOLARIS */ } From 39703a1b933779436cbb2b0d2fcdd99a0864855b Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 23 Nov 2009 17:57:21 +0100 Subject: [PATCH 11/21] WL#5138, fixed review comments --- sql/event_scheduler.cc | 10 +--------- sql/log_event.cc | 6 ------ sql/mysql_priv.h | 11 +++++++++++ sql/mysqld.cc | 3 +++ sql/sp_head.cc | 2 -- sql/sql_parse.cc | 8 -------- 6 files changed, 15 insertions(+), 25 deletions(-) diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 411be5a9d20..69e5f30ad31 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -133,10 +133,8 @@ post_init_event_thread(THD *thd) pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); thread_count++; - pthread_mutex_unlock(&LOCK_thread_count); - my_atomic_rwlock_wrlock(&global_query_id_lock); inc_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); + pthread_mutex_unlock(&LOCK_thread_count); return FALSE; } @@ -158,9 +156,7 @@ deinit_event_thread(THD *thd) DBUG_PRINT("exit", ("Event thread finishing")); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); delete thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); @@ -421,9 +417,7 @@ Event_scheduler::start() net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); @@ -556,9 +550,7 @@ error: net_end(&new_thd->net); pthread_mutex_lock(&LOCK_thread_count); thread_count--; - my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); delete new_thd; pthread_cond_broadcast(&COND_thread_count); pthread_mutex_unlock(&LOCK_thread_count); diff --git a/sql/log_event.cc b/sql/log_event.cc index 31908a818be..58ed5aa6a60 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3056,9 +3056,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, { thd->set_time((time_t)when); thd->set_query((char*)query_arg, q_len_arg); - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id = next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s", thd->query())); @@ -4581,9 +4579,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, if (rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id = next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->warning_info->opt_clear_warning_info(thd->query_id); TABLE_LIST tables; @@ -8072,9 +8068,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) DBUG_ASSERT(rli->sql_thd == thd); /* Step the query id to mark what columns that are actually used. */ - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); if (!(memory= my_multi_malloc(MYF(MY_WME), &table_list, (uint) sizeof(RPL_TABLE_LIST), diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0caf3197fb8..ec6aa274e49 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -90,19 +90,24 @@ typedef int64 query_id_t; extern query_id_t global_query_id; extern int32 thread_running; extern my_atomic_rwlock_t global_query_id_lock; +extern my_atomic_rwlock_t thread_running_lock; /* increment query_id and return it. */ inline query_id_t next_query_id() { query_id_t id; + my_atomic_rwlock_wrlock(&global_query_id_lock); id= my_atomic_add64(&global_query_id, 1); + my_atomic_rwlock_wrunlock(&global_query_id_lock); return (id+1); } inline query_id_t get_query_id() { query_id_t id; + my_atomic_rwlock_wrlock(&global_query_id_lock); id= my_atomic_load64(&global_query_id); + my_atomic_rwlock_wrunlock(&global_query_id_lock); return id; } @@ -110,7 +115,9 @@ inline int32 inc_thread_running() { int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); num_thread_running= my_atomic_add32(&thread_running, 1); + my_atomic_rwlock_wrunlock(&thread_running_lock); return (num_thread_running+1); } @@ -118,7 +125,9 @@ inline int32 dec_thread_running() { int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); num_thread_running= my_atomic_add32(&thread_running, -1); + my_atomic_rwlock_wrunlock(&thread_running_lock); return (num_thread_running-1); } @@ -126,7 +135,9 @@ inline int32 get_thread_running() { int32 num_thread_running; + my_atomic_rwlock_wrlock(&thread_running_lock); num_thread_running= my_atomic_load32(&thread_running); + my_atomic_rwlock_wrunlock(&thread_running_lock); return num_thread_running; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ddc6d53e019..e841f869b95 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -549,6 +549,7 @@ ulong query_cache_size=0; ulong refresh_version; /* Increments on each reload */ query_id_t global_query_id; my_atomic_rwlock_t global_query_id_lock; +my_atomic_rwlock_t thread_running_lock; ulong aborted_threads, aborted_connects; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; @@ -1383,6 +1384,7 @@ void clean_up(bool print_message) /* Tell main we are ready */ logger.cleanup_end(); my_atomic_rwlock_destroy(&global_query_id_lock); + my_atomic_rwlock_destroy(&thread_running_lock); (void) pthread_mutex_lock(&LOCK_thread_count); DBUG_PRINT("quit", ("got thread count lock")); ready_to_exit=1; @@ -7799,6 +7801,7 @@ static int mysql_init_variables(void) refresh_version= 1L; /* Increments on each reload */ global_query_id= thread_id= 1L; my_atomic_rwlock_init(&global_query_id_lock); + my_atomic_rwlock_init(&thread_running_lock); strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; myisam_stats_method_str= "nulls_unequal"; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index d0453c08a00..705fd2f702b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2736,9 +2736,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, */ thd->lex= m_lex; - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); if (thd->prelocked_mode == NON_PRELOCKED) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7b5df421785..83a54d1a59f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -495,9 +495,7 @@ static void handle_bootstrap_impl(THD *thd) We don't need to obtain LOCK_thread_count here because in bootstrap mode we have only one thread. */ - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id=next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->set_time(); mysql_parse(thd, thd->query(), length, & found_semicolon); close_thread_tables(thd); // Free tables @@ -991,7 +989,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->enable_slow_log= TRUE; thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->set_time(); - my_atomic_rwlock_wrlock(&global_query_id_lock); { query_id_t query_id; switch( command ) { @@ -1014,7 +1011,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->query_id= query_id; } inc_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); /** Clear the set of flags that are expected to be cleared at the @@ -1284,9 +1280,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); - my_atomic_rwlock_wrlock(&global_query_id_lock); thd->query_id= next_query_id(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt); @@ -1604,9 +1598,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd_proc_info(thd, "cleaning up"); thd->set_query(NULL, 0); thd->command=COM_SLEEP; - my_atomic_rwlock_wrlock(&global_query_id_lock); dec_thread_running(); - my_atomic_rwlock_wrunlock(&global_query_id_lock); thd_proc_info(thd, 0); thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); From 9ea65e5fa98ad56925d709d853a621de38cf1a71 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 24 Nov 2009 14:28:38 +0100 Subject: [PATCH 12/21] WL#5138, Fixed according to code review comments from Davi --- sql/log_event.cc | 5 ++--- sql/sp_head.cc | 4 ++-- sql/sql_class.cc | 20 ++++++++++++++++++++ sql/sql_class.h | 5 ++++- sql/sql_cursor.cc | 2 +- sql/sql_parse.cc | 8 +++----- 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 58ed5aa6a60..608f4d25cf4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3055,8 +3055,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, rpl_filter->db_ok(thd->db)) { thd->set_time((time_t)when); - thd->set_query((char*)query_arg, q_len_arg); - thd->query_id = next_query_id(); + thd->set_query_and_id((char*)query_arg, q_len_arg, next_query_id()); thd->variables.pseudo_thread_id= thread_id; // for temp tables DBUG_PRINT("query",("%s", thd->query())); @@ -8068,7 +8067,7 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) DBUG_ASSERT(rli->sql_thd == thd); /* Step the query id to mark what columns that are actually used. */ - thd->query_id= next_query_id(); + thd->set_query_id(next_query_id()); if (!(memory= my_multi_malloc(MYF(MY_WME), &table_list, (uint) sizeof(RPL_TABLE_LIST), diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 705fd2f702b..dae4a03c7f5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1338,7 +1338,7 @@ sp_head::execute(THD *thd) /* To avoid wiping out thd->change_list on old_change_list destruction */ old_change_list.empty(); thd->lex= old_lex; - thd->query_id= old_query_id; + thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; thd->variables.sql_mode= save_sql_mode; @@ -2736,7 +2736,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, */ thd->lex= m_lex; - thd->query_id= next_query_id(); + thd->set_query_id(next_query_id()); if (thd->prelocked_mode == NON_PRELOCKED) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 60aed4ce53b..d8fb64878aa 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3273,6 +3273,26 @@ void THD::set_query(char *query_arg, uint32 query_length_arg) pthread_mutex_unlock(&LOCK_thd_data); } +/** Assign a new value to thd->query and thd->query_id. */ + +void THD::set_query_and_id(char *query_arg, uint32 query_length_arg, + query_id_t new_query_id) +{ + pthread_mutex_lock(&LOCK_thd_data); + set_query_inner(query_arg, query_length_arg); + query_id= new_query_id; + pthread_mutex_unlock(&LOCK_thd_data); +} + +/** Assign a new value to thd->query_id. */ + +void THD::set_query_id(query_id_t new_query_id) +{ + pthread_mutex_lock(&LOCK_thd_data); + query_id= new_query_id; + pthread_mutex_unlock(&LOCK_thd_data); +} + /** Mark transaction to rollback and mark error as fatal to a sub-statement. diff --git a/sql/sql_class.h b/sql/sql_class.h index 2dd45997ee1..79e87a5ca3d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2324,10 +2324,13 @@ public: virtual void set_statement(Statement *stmt); /** - Assign a new value to thd->query. + Assign a new value to thd->query and thd->query_id. Protected with LOCK_thd_data mutex. */ void set_query(char *query_arg, uint32 query_length_arg); + void set_query_and_id(char *query_arg, uint32 query_length_arg, + query_id_t new_query_id); + void set_query_id(query_id_t new_query_id); private: /** The current internal error handler for this thread, or NULL. */ Internal_error_handler *m_internal_handler; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index ffc3fafe55f..533b47e61da 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -438,7 +438,7 @@ Sensitive_cursor::fetch(ulong num_rows) thd->derived_tables= derived_tables; thd->open_tables= open_tables; thd->lock= lock; - thd->query_id= query_id; + thd->set_query_id(query_id); thd->change_list= change_list; /* save references to memory allocated during fetch */ thd->set_n_backup_active_arena(this, &backup_arena); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 83a54d1a59f..f2b9d613e3a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -484,7 +484,7 @@ static void handle_bootstrap_impl(THD *thd) query= (char *) thd->memdup_w_gap(buff, length + 1, thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); - thd->set_query(query, length); + thd->set_query_and_id(query, length, next_query_id()); DBUG_PRINT("query",("%-.4096s",thd->query())); #if defined(ENABLED_PROFILING) thd->profiling.start_new_query(); @@ -495,7 +495,6 @@ static void handle_bootstrap_impl(THD *thd) We don't need to obtain LOCK_thread_count here because in bootstrap mode we have only one thread. */ - thd->query_id=next_query_id(); thd->set_time(); mysql_parse(thd, thd->query(), length, & found_semicolon); close_thread_tables(thd); // Free tables @@ -1008,7 +1007,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, statistic_increment(thd->status_var.questions, &LOCK_status); query_id= next_query_id() - 1; } - thd->query_id= query_id; + thd->set_query_id(query_id); } inc_thread_running(); @@ -1275,12 +1274,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->security_ctx->priv_user, (char *) thd->security_ctx->host_or_ip); - thd->set_query(beginning_of_next_stmt, length); + thd->set_query_and_id(beginning_of_next_stmt, length, next_query_id()); /* Count each statement from the client. */ statistic_increment(thd->status_var.questions, &LOCK_status); - thd->query_id= next_query_id(); thd->set_time(); /* Reset the query start time. */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */ mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt); From 62c39a339b0b5d57595e98dded3c82cc5fc394ac Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 26 Nov 2009 13:48:21 +0100 Subject: [PATCH 13/21] Fixed kill_alarm test and got it working --- configure.in | 1 + mysql-test/r/kill_alarm.result | 10 ++++++++++ mysql-test/t/kill_alarm.test | 13 +++++++++++++ 3 files changed, 24 insertions(+) create mode 100644 mysql-test/r/kill_alarm.result create mode 100644 mysql-test/t/kill_alarm.test diff --git a/configure.in b/configure.in index 783b4444a28..890fc333cee 100644 --- a/configure.in +++ b/configure.in @@ -923,6 +923,7 @@ AC_ARG_WITH(alarm, AC_MSG_CHECKING(whether to use alarms to implement socket timeout) if test "$use_alarm" = no ; then AC_DEFINE([NO_ALARM], [1], [No need to use alarm for socket timeout]) + AC_DEFINE([SIGNAL_WITH_VIO_CLOSE], [1], [Need to use vio close for kill connection]) fi AC_MSG_RESULT($use_alarm) diff --git a/mysql-test/r/kill_alarm.result b/mysql-test/r/kill_alarm.result new file mode 100644 index 00000000000..27636f55c97 --- /dev/null +++ b/mysql-test/r/kill_alarm.result @@ -0,0 +1,10 @@ +show processlist; +Id User Host db Command Time State Info +2 root localhost test Sleep 0 NULL +3 root localhost test Sleep 0 NULL +4 root localhost test Query 0 NULL show processlist +kill connection 3; +show processlist; +Id User Host db Command Time State Info +2 root localhost test Sleep 4 NULL +4 root localhost test Query 0 NULL show processlist diff --git a/mysql-test/t/kill_alarm.test b/mysql-test/t/kill_alarm.test new file mode 100644 index 00000000000..c08eb3dcf83 --- /dev/null +++ b/mysql-test/t/kill_alarm.test @@ -0,0 +1,13 @@ +-- source include/not_embedded.inc + +connect (con1, localhost, root,,); +connect (con2, localhost, root,,); + +connection con1; +let $ID=`select connection_id()`; + +connection con2; +show processlist; +eval kill connection $ID; +--sleep 4 +show processlist; From 8df0c15b36964eac2dfc259ad59fa692fbb63184 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 26 Nov 2009 13:58:59 +0100 Subject: [PATCH 14/21] Removed extra test case after review comment --- mysql-test/r/kill_alarm.result | 10 ---------- mysql-test/t/kill_alarm.test | 13 ------------- 2 files changed, 23 deletions(-) delete mode 100644 mysql-test/r/kill_alarm.result delete mode 100644 mysql-test/t/kill_alarm.test diff --git a/mysql-test/r/kill_alarm.result b/mysql-test/r/kill_alarm.result deleted file mode 100644 index 27636f55c97..00000000000 --- a/mysql-test/r/kill_alarm.result +++ /dev/null @@ -1,10 +0,0 @@ -show processlist; -Id User Host db Command Time State Info -2 root localhost test Sleep 0 NULL -3 root localhost test Sleep 0 NULL -4 root localhost test Query 0 NULL show processlist -kill connection 3; -show processlist; -Id User Host db Command Time State Info -2 root localhost test Sleep 4 NULL -4 root localhost test Query 0 NULL show processlist diff --git a/mysql-test/t/kill_alarm.test b/mysql-test/t/kill_alarm.test deleted file mode 100644 index c08eb3dcf83..00000000000 --- a/mysql-test/t/kill_alarm.test +++ /dev/null @@ -1,13 +0,0 @@ --- source include/not_embedded.inc - -connect (con1, localhost, root,,); -connect (con2, localhost, root,,); - -connection con1; -let $ID=`select connection_id()`; - -connection con2; -show processlist; -eval kill connection $ID; ---sleep 4 -show processlist; From 268be884572918ac227573a9fd9eb811d74c1a7d Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 8 Dec 2009 11:14:51 +0100 Subject: [PATCH 15/21] Fixed --fast flag on Linux to use -O3 --- BUILD/build_mccge.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index 3345ac3dcb5..8ca31b2d119 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -1303,7 +1303,11 @@ set_linux_configs() compiler_flags="$compiler_flags -m32" fi if test "x$fast_flag" != "xno" ; then - compiler_flags="$compiler_flags -O2" + if test "x$fast_flag" = "xyes" ; then + compiler_flags="$compiler_flags -O3" + else + compiler_flags="$compiler_flags -O2" + fi else compiler_flags="$compiler_flags -O0" fi From 32b9defd3c7ca206dc314d044607c05b2f2501f5 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 14 Dec 2009 15:51:42 +0100 Subject: [PATCH 16/21] Fixed an issue where STOP SLAVE generated a warning to error log which test case couldn't handle, fixed by checking for io slave killed before checking for network error --- sql/slave.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sql/slave.cc b/sql/slave.cc index 96aa9890c89..ce5bb785792 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1219,6 +1219,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) mi->clock_diff_with_master= (long) (time((time_t*) 0) - strtoul(master_row[0], 0, 10)); } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1271,7 +1273,9 @@ not always make sense; please check the manual before using it)."; } else if (mysql_errno(mysql)) { - if (is_network_error(mysql_errno(mysql))) + if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; + else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), "Get master SERVER_ID failed with error: %s", mysql_error(mysql)); @@ -1342,6 +1346,8 @@ be equal for the Statement-format replication to work"; goto err; } } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1403,6 +1409,8 @@ be equal for the Statement-format replication to work"; goto err; } } + else if (check_io_slave_killed(mi->io_thd, mi, NULL)) + goto slave_killed_err; else if (is_network_error(mysql_errno(mysql))) { mi->report(WARNING_LEVEL, mysql_errno(mysql), @@ -1466,6 +1474,11 @@ network_err: if (master_res) mysql_free_result(master_res); DBUG_RETURN(2); + +slave_killed_err: + if (master_res) + mysql_free_result(master_res); + DBUG_RETURN(2); } /* @@ -2884,7 +2897,7 @@ connected: if (ret == 1) /* Fatal error */ goto err; - + if (ret == 2) { if (check_io_slave_killed(mi->io_thd, mi, "Slave I/O thread killed" From e74991d4a62a0064a4538e2edd8636a2d3855480 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Dec 2009 15:40:08 +0100 Subject: [PATCH 17/21] Fixed atomic instruction headers for Windows and x86-gcc --- include/atomic/generic-msvc.h | 32 ++++++++++++++++++++++++++++---- include/atomic/x86-gcc.h | 6 ++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h index f1e1b0e88c9..e317e7dc4cc 100644 --- a/include/atomic/generic-msvc.h +++ b/include/atomic/generic-msvc.h @@ -37,18 +37,29 @@ C_MODE_START /*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/ LONG _InterlockedExchange (LONG volatile *Target,LONG Value); -LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp); +LONGLONG _InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); +LONG _InterlockedCompareExchange (LONG volatile *Target, + LONG Value, LONG Comp); +LONGLONG _InterlockedCompareExchange64 (LONGLONG volatile *Target, + LONGLONG Value, LONGLONG Comp); LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value); +LONGLONG _InterlockedExchangeAdd64 (LONGLONG volatile *Addend, LONGLONG Value); C_MODE_END #pragma intrinsic(_InterlockedExchangeAdd) #pragma intrinsic(_InterlockedCompareExchange) #pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedExchange64) #endif #define InterlockedExchange _InterlockedExchange #define InterlockedExchangeAdd _InterlockedExchangeAdd #define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedExchange64 _InterlockedExchange64 +#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 /* No need to do something special for InterlockedCompareExchangePointer as it is a #define to InterlockedCompareExchange. The same applies to @@ -57,10 +68,20 @@ C_MODE_END #endif /*_M_IX86*/ #define MY_ATOMIC_MODE "msvc-intrinsics" -#define IL_EXCHG_ADD32(X,Y) InterlockedExchangeAdd((volatile LONG *)(X),(Y)) -#define IL_COMP_EXCHG32(X,Y,Z) InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z)) +#define IL_EXCHG_ADD32(X,Y) \ + InterlockedExchangeAdd((volatile LONG *)(X),(Y)) +#define IL_EXCHG_ADD64(X,Y) \ + InterlockedExchangeAdd64((volatile LONGLONG *)(X),(LONGLONG)(Y)) +#define IL_COMP_EXCHG32(X,Y,Z) \ + InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z)) +#define IL_COMP_EXCHG64(X,Y,Z) \ + InterlockedCompareExchange64((volatile LONGLONG *)(X), \ + (LONGLONG)(Y),(LONGLONG)(Z)) #define IL_COMP_EXCHGptr InterlockedCompareExchangePointer -#define IL_EXCHG32(X,Y) InterlockedExchange((volatile LONG *)(X),(Y)) +#define IL_EXCHG32(X,Y) \ + InterlockedExchange((volatile LONG *)(X),(Y)) +#define IL_EXCHG64(X,Y) \ + InterlockedExchange64((volatile LONGLONG *)(X),(LONGLONG)(Y)) #define IL_EXCHGptr InterlockedExchangePointer #define make_atomic_add_body(S) \ v= IL_EXCHG_ADD ## S (a, v) @@ -108,9 +129,12 @@ static __inline int my_yield_processor() #else /* cleanup */ #undef IL_EXCHG_ADD32 +#undef IL_EXCHG_ADD64 #undef IL_COMP_EXCHG32 +#undef IL_COMP_EXCHG64 #undef IL_COMP_EXCHGptr #undef IL_EXCHG32 +#undef IL_EXCHG64 #undef IL_EXCHGptr #endif diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h index e5e88fa58ff..f19a4a33f3c 100644 --- a/include/atomic/x86-gcc.h +++ b/include/atomic/x86-gcc.h @@ -22,6 +22,12 @@ architectures support double-word (128-bit) cas. */ +/* + No special support of 8 and 16 bit operations are implemented here + currently. +*/ +#undef MY_ATOMIC_HAS_8_AND_16 + #ifdef __x86_64__ # ifdef MY_ATOMIC_NO_XADD # define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix "-no-xadd" From 0d28ae37e5cc4a8a3d5e869345c471dc2ea92e96 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Dec 2009 17:07:43 +0100 Subject: [PATCH 18/21] Fixed 64-bit atomics on Win x86 and removed support for 8 and 16-bit atomic operations --- include/atomic/generic-msvc.h | 13 +------------ include/my_atomic.h | 7 +++---- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h index e317e7dc4cc..77319aaa93c 100644 --- a/include/atomic/generic-msvc.h +++ b/include/atomic/generic-msvc.h @@ -37,29 +37,18 @@ C_MODE_START /*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/ LONG _InterlockedExchange (LONG volatile *Target,LONG Value); -LONGLONG _InterlockedExchange64 (LONGLONG volatile *Target,LONGLONG Value); -LONG _InterlockedCompareExchange (LONG volatile *Target, - LONG Value, LONG Comp); -LONGLONG _InterlockedCompareExchange64 (LONGLONG volatile *Target, - LONGLONG Value, LONGLONG Comp); +LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp); LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value); -LONGLONG _InterlockedExchangeAdd64 (LONGLONG volatile *Addend, LONGLONG Value); C_MODE_END #pragma intrinsic(_InterlockedExchangeAdd) #pragma intrinsic(_InterlockedCompareExchange) #pragma intrinsic(_InterlockedExchange) -#pragma intrinsic(_InterlockedExchangeAdd64) -#pragma intrinsic(_InterlockedCompareExchange64) -#pragma intrinsic(_InterlockedExchange64) #endif #define InterlockedExchange _InterlockedExchange #define InterlockedExchangeAdd _InterlockedExchangeAdd #define InterlockedCompareExchange _InterlockedCompareExchange -#define InterlockedExchange64 _InterlockedExchange64 -#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64 -#define InterlockedCompareExchange64 _InterlockedCompareExchange64 /* No need to do something special for InterlockedCompareExchangePointer as it is a #define to InterlockedCompareExchange. The same applies to diff --git a/include/my_atomic.h b/include/my_atomic.h index 4170e45fe8c..23c3dc749ab 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -56,11 +56,10 @@ #define intptr void * /** - On most platforms we implement 8-bit, 16-bit, 32-bit and "pointer" - operations. Thus the symbol below is defined by default; platforms - where we leave out 8-bit or 16-bit operations should undefine it. + Currently we don't support 8-bit and 16-bit operations. + It can be added later if needed. */ -#define MY_ATOMIC_HAS_8_16 1 +#undef MY_ATOMIC_HAS_8_16 #ifndef MY_ATOMIC_MODE_RWLOCKS /* From 6b0bb0506880d04d6a1d6cd5c6c03f2aebe4ca24 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Dec 2009 18:12:49 +0100 Subject: [PATCH 19/21] Include windows.h in atomics framework for windows --- include/atomic/generic-msvc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h index 77319aaa93c..4a50dc4a667 100644 --- a/include/atomic/generic-msvc.h +++ b/include/atomic/generic-msvc.h @@ -23,6 +23,7 @@ */ #undef MY_ATOMIC_HAS_8_16 +#include /* x86 compilers (both VS2003 or VS2005) never use instrinsics, but generate function calls to kernel32 instead, even in the optimized build. From 0fb1c286d762d94564edaa924de9769c599bc231 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Dec 2009 22:15:48 +0100 Subject: [PATCH 20/21] Fixed complex gcc assembler issues with 64-bit operations on 32-bit platforms using PIC codes, commented x86-gcc.h a lot more --- include/atomic/x86-gcc.h | 75 ++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/include/atomic/x86-gcc.h b/include/atomic/x86-gcc.h index f19a4a33f3c..32839e0a67d 100644 --- a/include/atomic/x86-gcc.h +++ b/include/atomic/x86-gcc.h @@ -59,39 +59,68 @@ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \ : "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set)) -#define make_atomic_cas_bodyptr make_atomic_cas_body32 - -#ifndef __x86_64__ +#ifdef __x86_64__ #define make_atomic_add_body64 make_atomic_add_body32 #define make_atomic_cas_body64 make_atomic_cas_body32 -#else -#define make_atomic_add_body64 \ - int64 tmp=*a; \ - while (!my_atomic_cas64(a, &tmp, tmp+v)); \ - v=tmp; -#define make_atomic_cas_body64 \ - int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \ - asm volatile (LOCK_prefix "; cmpxchg8b %0; setz %2;" \ - : "+m" (*a), "+A" (*cmp), "=q" (ret) \ - :"b" (ebx), "c" (ecx)) -#endif #define make_atomic_fas_body(S) \ asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a)) -#ifdef MY_ATOMIC_MODE_DUMMY -#define make_atomic_load_body(S) ret=*a -#define make_atomic_store_body(S) *a=v -#else /* Actually 32-bit reads/writes are always atomic on x86 But we add LOCK_prefix here anyway to force memory barriers */ -#define make_atomic_load_body(S) \ - ret=0; \ - asm volatile (LOCK_prefix "; cmpxchg %2, %0" \ - : "+m" (*a), "+a" (ret): "r" (ret)) -#define make_atomic_store_body(S) \ +#define make_atomic_load_body(S) \ + ret=0; \ + asm volatile (LOCK_prefix "; cmpxchg %2, %0" \ + : "+m" (*a), "+a" (ret): "r" (ret)) +#define make_atomic_store_body(S) \ asm volatile ("; xchg %0, %1;" : "+m" (*a), "+r" (v)) + +#else +/* + Use default implementations of 64-bit operations since we solved + the 64-bit problem on 32-bit platforms for CAS, no need to solve it + once more for ADD, LOAD, STORE and FAS as well. + Since we already added add32 support, we need to define add64 + here, but we haven't defined fas, load and store at all, so + we can fallback on default implementations. +*/ +#define make_atomic_add_body64 \ + int64 tmp=*a; \ + while (!my_atomic_cas64(a, &tmp, tmp+v)); \ + v=tmp; + +/* + On some platforms (e.g. Mac OS X and Solaris) the ebx register + is held as a pointer to the global offset table. Thus we're not + allowed to use the b-register on those platforms when compiling + PIC code, to avoid this we push ebx and pop ebx and add a movl + instruction to avoid having ebx in the interface of the assembler + instruction. + + cmpxchg8b works on both 32-bit platforms and 64-bit platforms but + the code here is only used on 32-bit platforms, on 64-bit + platforms the much simpler make_atomic_cas_body32 will work + fine. +*/ +#define make_atomic_cas_body64 \ + int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \ + asm volatile ("push %%ebx; movl %3, %%ebx;" \ + LOCK_prefix "; cmpxchg8b %0; setz %2; pop %%ebx"\ + : "+m" (*a), "+A" (*cmp), "=q" (ret) \ + :"m" (ebx), "c" (ecx)) +#endif + +/* + The implementation of make_atomic_cas_body32 is adaptable to + the OS word size, so on 64-bit platforms it will automatically + adapt to 64-bits and so it will work also on 64-bit platforms +*/ +#define make_atomic_cas_bodyptr make_atomic_cas_body32 + +#ifdef MY_ATOMIC_MODE_DUMMY +#define make_atomic_load_body(S) ret=*a +#define make_atomic_store_body(S) *a=v #endif #endif /* ATOMIC_X86_GCC_INCLUDED */ From a893a64e2342eb4d179db46c5f85d4c86c45a4ed Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 16 Dec 2009 00:33:15 +0100 Subject: [PATCH 21/21] Fix for Windows atomics --- include/atomic/generic-msvc.h | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/include/atomic/generic-msvc.h b/include/atomic/generic-msvc.h index 4a50dc4a667..a84cde6b2c3 100644 --- a/include/atomic/generic-msvc.h +++ b/include/atomic/generic-msvc.h @@ -37,19 +37,17 @@ #else C_MODE_START /*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/ -LONG _InterlockedExchange (LONG volatile *Target,LONG Value); LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp); -LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value); +LONGLONG _InterlockedCompareExchange64 (LONGLONG volatile *Target, + LONGLONG Value, LONGLONG Comp); C_MODE_END -#pragma intrinsic(_InterlockedExchangeAdd) #pragma intrinsic(_InterlockedCompareExchange) -#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedCompareExchange64) #endif -#define InterlockedExchange _InterlockedExchange -#define InterlockedExchangeAdd _InterlockedExchangeAdd #define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedCompareExchange64 _InterlockedCompareExchange64 /* No need to do something special for InterlockedCompareExchangePointer as it is a #define to InterlockedCompareExchange. The same applies to @@ -58,33 +56,39 @@ C_MODE_END #endif /*_M_IX86*/ #define MY_ATOMIC_MODE "msvc-intrinsics" -#define IL_EXCHG_ADD32(X,Y) \ - InterlockedExchangeAdd((volatile LONG *)(X),(Y)) -#define IL_EXCHG_ADD64(X,Y) \ - InterlockedExchangeAdd64((volatile LONGLONG *)(X),(LONGLONG)(Y)) +/* Implement using CAS on WIN32 */ #define IL_COMP_EXCHG32(X,Y,Z) \ InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z)) #define IL_COMP_EXCHG64(X,Y,Z) \ InterlockedCompareExchange64((volatile LONGLONG *)(X), \ (LONGLONG)(Y),(LONGLONG)(Z)) #define IL_COMP_EXCHGptr InterlockedCompareExchangePointer + +#define make_atomic_cas_body(S) \ + int ## S initial_cmp= *cmp; \ + int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \ + if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a; + +#ifndef _M_IX86 +/* Use full set of optimised functions on WIN64 */ +#define IL_EXCHG_ADD32(X,Y) \ + InterlockedExchangeAdd((volatile LONG *)(X),(Y)) +#define IL_EXCHG_ADD64(X,Y) \ + InterlockedExchangeAdd64((volatile LONGLONG *)(X),(LONGLONG)(Y)) #define IL_EXCHG32(X,Y) \ InterlockedExchange((volatile LONG *)(X),(Y)) #define IL_EXCHG64(X,Y) \ InterlockedExchange64((volatile LONGLONG *)(X),(LONGLONG)(Y)) #define IL_EXCHGptr InterlockedExchangePointer + #define make_atomic_add_body(S) \ v= IL_EXCHG_ADD ## S (a, v) -#define make_atomic_cas_body(S) \ - int ## S initial_cmp= *cmp; \ - int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \ - if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a; #define make_atomic_swap_body(S) \ v= IL_EXCHG ## S (a, v) #define make_atomic_load_body(S) \ ret= 0; /* avoid compiler warning */ \ ret= IL_COMP_EXCHG ## S (a, ret, ret); - +#endif /* my_yield_processor (equivalent of x86 PAUSE instruction) should be used to improve performance on hyperthreaded CPUs. Intel recommends to use it in