Skip to content

Commit 1e46d6a

Browse files
author
Marc Alff
committed
WL#2595 kernel-independent atomic operations
Backport from 6.0.14 to 5.6.0 Original code from Sergei Golubchik
1 parent 9d3ddc4 commit 1e46d6a

File tree

14 files changed

+675
-282
lines changed

14 files changed

+675
-282
lines changed

configure.in

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,64 +1750,74 @@ then
17501750
fi
17511751

17521752
AC_ARG_WITH([atomic-ops],
1753-
AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
1754-
[Implement atomic operations using pthread rwlocks or atomic CPU
1755-
instructions for multi-processor (default) or uniprocessor
1756-
configuration]), , [with_atomic_ops=smp])
1753+
AS_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
1754+
[Implement atomic operations using pthread rwlocks or atomic CPU
1755+
instructions for multi-processor or uniprocessor
1756+
configuration. By default gcc built-in sync functions are used,
1757+
if available and 'smp' configuration otherwise.]))
17571758
case "$with_atomic_ops" in
17581759
"up") AC_DEFINE([MY_ATOMIC_MODE_DUMMY], [1],
17591760
[Assume single-CPU mode, no concurrency]) ;;
17601761
"rwlocks") AC_DEFINE([MY_ATOMIC_MODE_RWLOCKS], [1],
17611762
[Use pthread rwlocks for atomic ops]) ;;
17621763
"smp") ;;
1764+
"")
1765+
;;
17631766
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
17641767
esac
17651768

17661769
AC_CACHE_CHECK([whether the compiler provides atomic builtins],
1767-
[mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
1768-
int main()
1769-
{
1770-
int foo= -10; int bar= 10;
1771-
if (!__sync_fetch_and_add(&foo, bar) || foo)
1772-
return -1;
1773-
bar= __sync_lock_test_and_set(&foo, bar);
1774-
if (bar || foo != 10)
1775-
return -1;
1776-
bar= __sync_val_compare_and_swap(&bar, foo, 15);
1777-
if (bar)
1778-
return -1;
1779-
return 0;
1780-
}
1781-
], [mysql_cv_gcc_atomic_builtins=yes],
1770+
[mysql_cv_gcc_atomic_builtins],
1771+
[AC_RUN_IFELSE(
1772+
[AC_LANG_PROGRAM(
1773+
[
1774+
],
1775+
[[
1776+
int foo= -10; int bar= 10;
1777+
if (!__sync_fetch_and_add(&foo, bar) || foo)
1778+
return -1;
1779+
bar= __sync_lock_test_and_set(&foo, bar);
1780+
if (bar || foo != 10)
1781+
return -1;
1782+
bar= __sync_val_compare_and_swap(&bar, foo, 15);
1783+
if (bar)
1784+
return -1;
1785+
return 0;
1786+
]]
1787+
)],
1788+
[mysql_cv_gcc_atomic_builtins=yes],
17821789
[mysql_cv_gcc_atomic_builtins=no],
1783-
[mysql_cv_gcc_atomic_builtins=no])])
1784-
1790+
[mysql_cv_gcc_atomic_builtins=no]
1791+
)])
17851792
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
17861793
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
17871794
[Define to 1 if compiler provides atomic builtins.])
17881795
fi
17891796

17901797
AC_CACHE_CHECK([whether the OS provides atomic_* functions like Solaris],
1791-
[mysql_cv_solaris_atomic], [AC_TRY_RUN([
1792-
#include <atomic.h>
1793-
int
1794-
main()
1795-
{
1796-
int foo = -10; int bar = 10;
1797-
if (atomic_add_int_nv((uint_t *)&foo, bar) || foo)
1798-
return -1;
1799-
bar = atomic_swap_uint((uint_t *)&foo, (uint_t)bar);
1800-
if (bar || foo != 10)
1801-
return -1;
1802-
bar = atomic_cas_uint((uint_t *)&bar, (uint_t)foo, 15);
1803-
if (bar)
1804-
return -1;
1805-
return 0;
1806-
}
1807-
], [mysql_cv_solaris_atomic=yes],
1798+
[mysql_cv_solaris_atomic],
1799+
[AC_RUN_IFELSE(
1800+
[AC_LANG_PROGRAM(
1801+
[
1802+
#include <atomic.h>
1803+
]
1804+
[[
1805+
int foo = -10; int bar = 10;
1806+
if (atomic_add_int_nv((uint_t *)&foo, bar) || foo)
1807+
return -1;
1808+
bar = atomic_swap_uint((uint_t *)&foo, (uint_t)bar);
1809+
if (bar || foo != 10)
1810+
return -1;
1811+
bar = atomic_cas_uint((uint_t *)&bar, (uint_t)foo, 15);
1812+
if (bar)
1813+
return -1;
1814+
return 0;
1815+
]]
1816+
)],
1817+
[mysql_cv_solaris_atomic=yes],
18081818
[mysql_cv_solaris_atomic=no],
1809-
[mysql_cv_solaris_atomic=no])])
1810-
1819+
[mysql_cv_solaris_atomic=no]
1820+
)])
18111821
if test "x$mysql_cv_solaris_atomic" = xyes; then
18121822
AC_DEFINE(HAVE_SOLARIS_ATOMIC, 1,
18131823
[Define to 1 if OS provides atomic_* functions like Solaris.])

include/Makefile.am

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \
3939
thr_lock.h t_ctype.h violite.h my_md5.h base64.h \
4040
my_handler.h my_time.h service_versions.h \
4141
my_vle.h my_user.h my_atomic.h atomic/nolock.h \
42-
atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \
43-
atomic/solaris.h \
44-
atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h
42+
atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \
43+
atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h \
44+
atomic/solaris.h
4545

4646
EXTRA_DIST = mysql.h.pp mysql/plugin.h.pp probes_mysql.d.base
4747

include/atomic/gcc_builtins.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#define make_atomic_add_body(S) \
2020
v= __sync_fetch_and_add(a, v);
21-
#define make_atomic_swap_body(S) \
21+
#define make_atomic_fas_body(S) \
2222
v= __sync_lock_test_and_set(a, v);
2323
#define make_atomic_cas_body(S) \
2424
int ## S sav; \
@@ -28,7 +28,10 @@
2828
#ifdef MY_ATOMIC_MODE_DUMMY
2929
#define make_atomic_load_body(S) ret= *a
3030
#define make_atomic_store_body(S) *a= v
31+
#define MY_ATOMIC_MODE "gcc-builtins-up"
32+
3133
#else
34+
#define MY_ATOMIC_MODE "gcc-builtins-smp"
3235
#define make_atomic_load_body(S) \
3336
ret= __sync_fetch_and_or(a, 0);
3437
#define make_atomic_store_body(S) \

include/atomic/generic-msvc.h

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; version 2 of the License.
6+
7+
This program is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License
13+
along with this program; if not, write to the Free Software
14+
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
15+
16+
#ifndef _atomic_h_cleanup_
17+
#define _atomic_h_cleanup_ "atomic/generic-msvc.h"
18+
19+
/*
20+
We don't implement anything specific for MY_ATOMIC_MODE_DUMMY, always use
21+
intrinsics.
22+
8 and 16-bit atomics are not implemented, but it can be done if necessary.
23+
*/
24+
#undef MY_ATOMIC_HAS_8_16
25+
26+
/*
27+
x86 compilers (both VS2003 or VS2005) never use instrinsics, but generate
28+
function calls to kernel32 instead, even in the optimized build.
29+
We force intrinsics as described in MSDN documentation for
30+
_InterlockedCompareExchange.
31+
*/
32+
#ifdef _M_IX86
33+
34+
#if (_MSC_VER >= 1500)
35+
#include <intrin.h>
36+
#else
37+
C_MODE_START
38+
/*Visual Studio 2003 and earlier do not have prototypes for atomic intrinsics*/
39+
LONG _InterlockedExchange (LONG volatile *Target,LONG Value);
40+
LONG _InterlockedCompareExchange (LONG volatile *Target, LONG Value, LONG Comp);
41+
LONG _InterlockedExchangeAdd (LONG volatile *Addend, LONG Value);
42+
C_MODE_END
43+
44+
#pragma intrinsic(_InterlockedExchangeAdd)
45+
#pragma intrinsic(_InterlockedCompareExchange)
46+
#pragma intrinsic(_InterlockedExchange)
47+
#endif
48+
49+
#define InterlockedExchange _InterlockedExchange
50+
#define InterlockedExchangeAdd _InterlockedExchangeAdd
51+
#define InterlockedCompareExchange _InterlockedCompareExchange
52+
/*
53+
No need to do something special for InterlockedCompareExchangePointer
54+
as it is a #define to InterlockedCompareExchange. The same applies to
55+
InterlockedExchangePointer.
56+
*/
57+
#endif /*_M_IX86*/
58+
59+
#define MY_ATOMIC_MODE "msvc-intrinsics"
60+
#define IL_EXCHG_ADD32(X,Y) InterlockedExchangeAdd((volatile LONG *)(X),(Y))
61+
#define IL_COMP_EXCHG32(X,Y,Z) InterlockedCompareExchange((volatile LONG *)(X),(Y),(Z))
62+
#define IL_COMP_EXCHGptr InterlockedCompareExchangePointer
63+
#define IL_EXCHG32(X,Y) InterlockedExchange((volatile LONG *)(X),(Y))
64+
#define IL_EXCHGptr InterlockedExchangePointer
65+
#define make_atomic_add_body(S) \
66+
v= IL_EXCHG_ADD ## S (a, v)
67+
#define make_atomic_cas_body(S) \
68+
int ## S initial_cmp= *cmp; \
69+
int ## S initial_a= IL_COMP_EXCHG ## S (a, set, initial_cmp); \
70+
if (!(ret= (initial_a == initial_cmp))) *cmp= initial_a;
71+
#define make_atomic_swap_body(S) \
72+
v= IL_EXCHG ## S (a, v)
73+
#define make_atomic_load_body(S) \
74+
ret= 0; /* avoid compiler warning */ \
75+
ret= IL_COMP_EXCHG ## S (a, ret, ret);
76+
77+
/*
78+
my_yield_processor (equivalent of x86 PAUSE instruction) should be used
79+
to improve performance on hyperthreaded CPUs. Intel recommends to use it in
80+
spin loops also on non-HT machines to reduce power consumption (see e.g
81+
http://softwarecommunity.intel.com/articles/eng/2004.htm)
82+
83+
Running benchmarks for spinlocks implemented with InterlockedCompareExchange
84+
and YieldProcessor shows that much better performance is achieved by calling
85+
YieldProcessor in a loop - that is, yielding longer. On Intel boxes setting
86+
loop count in the range 200-300 brought best results.
87+
*/
88+
#ifndef YIELD_LOOPS
89+
#define YIELD_LOOPS 200
90+
#endif
91+
92+
static __inline int my_yield_processor()
93+
{
94+
int i;
95+
for(i=0; i<YIELD_LOOPS; i++)
96+
{
97+
#if (_MSC_VER <= 1310)
98+
/* On older compilers YieldProcessor is not available, use inline assembly*/
99+
__asm { rep nop }
100+
#else
101+
YieldProcessor();
102+
#endif
103+
}
104+
return 1;
105+
}
106+
107+
#define LF_BACKOFF my_yield_processor()
108+
#else /* cleanup */
109+
110+
#undef IL_EXCHG_ADD32
111+
#undef IL_COMP_EXCHG32
112+
#undef IL_COMP_EXCHGptr
113+
#undef IL_EXCHG32
114+
#undef IL_EXCHGptr
115+
116+
#endif

include/atomic/nolock.h

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,36 @@
1616
along with this program; if not, write to the Free Software
1717
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1818

19-
#if defined(__i386__) || defined(_M_IX86) || defined(HAVE_GCC_ATOMIC_BUILTINS)
20-
21-
#ifdef MY_ATOMIC_MODE_DUMMY
22-
# define LOCK ""
23-
#else
24-
# define LOCK "lock"
25-
#endif
26-
27-
#ifdef HAVE_GCC_ATOMIC_BUILTINS
28-
#include "gcc_builtins.h"
29-
#elif __GNUC__
30-
#include "x86-gcc.h"
31-
#elif defined(_MSC_VER)
32-
#include "x86-msvc.h"
33-
#endif
34-
19+
#if defined(__i386__) || defined(_MSC_VER) || defined(__x86_64__) \
20+
|| defined(HAVE_GCC_ATOMIC_BUILTINS)
21+
22+
# ifdef MY_ATOMIC_MODE_DUMMY
23+
# define LOCK_prefix ""
24+
# else
25+
# define LOCK_prefix "lock"
26+
# endif
27+
28+
# ifdef HAVE_GCC_ATOMIC_BUILTINS
29+
# include "gcc_builtins.h"
30+
# elif __GNUC__
31+
# include "x86-gcc.h"
32+
# elif defined(_MSC_VER)
33+
# include "generic-msvc.h"
34+
# endif
3535
#elif defined(HAVE_SOLARIS_ATOMIC)
36-
3736
#include "solaris.h"
38-
39-
#endif /* __i386__ || _M_IX86 || HAVE_GCC_ATOMIC_BUILTINS */
37+
#endif
4038

4139
#if defined(make_atomic_cas_body) || defined(MY_ATOMICS_MADE)
4240
/*
4341
* We have atomics that require no locking
4442
*/
4543
#define MY_ATOMIC_NOLOCK
46-
47-
#ifdef __SUNPRO_C
4844
/*
49-
* Sun Studio 12 (and likely earlier) does not accept a typedef struct {}
50-
*/
51-
typedef char my_atomic_rwlock_t;
52-
#else
53-
typedef struct { } my_atomic_rwlock_t;
54-
#endif
55-
45+
Type not used so minimal size (emptry struct has different size between C
46+
and C++, zero-length array is gcc-specific).
47+
*/
48+
typedef char my_atomic_rwlock_t __attribute__ ((unused));
5649
#define my_atomic_rwlock_destroy(name)
5750
#define my_atomic_rwlock_init(name)
5851
#define my_atomic_rwlock_rdlock(name)

0 commit comments

Comments
 (0)