Commit 99b5d9e2 authored by inaam's avatar inaam

branches/zip

Enable atomics on solaris (using the libc functions as defined in
atomic.h) if GCC atomic builtins are not present.

There still remains some work to be done (by Vasil?). This patch
makes changes to plug.in to check pthread_t size and presence of
atomic functions when running on solaris. The same has to become
a part of the generated Makefile.in when we bake our source.

Reviewed by: Heikki rb://106
parent e5cd059f
......@@ -285,21 +285,68 @@ os_fast_mutex_free(
/*===============*/
os_fast_mutex_t* fast_mutex); /* in: mutex to free */
/**************************************************************
Atomic compare-and-swap and increment for InnoDB. */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
/**************************************************************
Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins.
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
#define os_compare_and_swap(ptr, old_val, new_val) \
# define os_compare_and_swap(ptr, old_val, new_val) \
__sync_bool_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
/**************************************************************
Atomic increment for InnoDB. Currently requires GCC atomic builtins.
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
#define os_atomic_increment(ptr, amount) \
# define os_atomic_increment(ptr, amount) \
__sync_add_and_fetch(ptr, amount)
# define os_atomic_increment_lint(ptr, amount) \
os_atomic_increment(ptr, amount)
# define os_atomic_increment_ulint(ptr, amount) \
os_atomic_increment(ptr, amount)
/**************************************************************
Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \
__sync_lock_test_and_set(ptr, new_val)
/* If not compiling with GCC or GCC doesn't support the atomic
intrinsics and running on Solaris >= 10 use Solaris atomics */
#elif defined(HAVE_SOLARIS_ATOMICS)
#include <atomic.h>
/**************************************************************
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
(atomic_cas_ulong(ptr, old_val, new_val) == old_val)
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
((lint)atomic_cas_ulong((ulong_t*) ptr, old_val, new_val) == old_val)
# ifdef INNODB_RW_LOCKS_USE_ATOMICS
# if SIZEOF_PTHREAD_T == 4
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
((pthread_t)atomic_cas_32(ptr, old_val, new_val) == old_val)
# elif SIZEOF_PTHREAD_T == 8
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
((pthread_t)atomic_cas_64(ptr, old_val, new_val) == old_val)
# else
# error "SIZEOF_PTHREAD_T != 4 or 8"
# endif /* SIZEOF_PTHREAD_T CHECK */
# endif /* INNODB_RW_LOCKS_USE_ATOMICS */
/**************************************************************
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
# define os_atomic_increment_lint(ptr, amount) \
atomic_add_long_nv((ulong_t*) ptr, amount)
# define os_atomic_increment_ulint(ptr, amount) \
atomic_add_long_nv(ptr, amount)
/**************************************************************
Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_byte(ptr, new_val) \
atomic_swap_uchar(ptr, new_val)
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
#ifndef UNIV_NONINL
......
......@@ -89,7 +89,7 @@ rw_lock_set_waiter_flag(
rw_lock_t* lock) /* in: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_compare_and_swap(&lock->waiters, 0, 1);
os_compare_and_swap_ulint(&lock->waiters, 0, 1);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 1;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
......@@ -106,7 +106,7 @@ rw_lock_reset_waiter_flag(
rw_lock_t* lock) /* in: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
os_compare_and_swap(&lock->waiters, 1, 0);
os_compare_and_swap_ulint(&lock->waiters, 1, 0);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 0;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
......@@ -201,7 +201,7 @@ rw_lock_lock_word_decr(
lint local_lock_word = lock->lock_word;
while (local_lock_word > 0) {
if(os_compare_and_swap(&(lock->lock_word),
if(os_compare_and_swap_lint(&lock->lock_word,
local_lock_word,
local_lock_word - amount)) {
return(TRUE);
......@@ -236,10 +236,9 @@ rw_lock_lock_word_incr(
rw_lock_t* lock, /* in: rw-lock */
ulint amount) /* in: amount of increment */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
return(os_atomic_increment(&(lock->lock_word), amount));
return(os_atomic_increment_lint(&lock->lock_word, amount));
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
......@@ -287,8 +286,8 @@ rw_lock_set_writer_id_and_recursion_flag(
UNIV_MEM_VALID(&lock->writer_thread, sizeof lock->writer_thread);
local_thread = lock->writer_thread;
success = os_compare_and_swap(&lock->writer_thread,
local_thread, curr_thread);
success = os_compare_and_swap_thread_id(
&lock->writer_thread, local_thread, curr_thread);
ut_a(success);
lock->recursive = recursive;
......@@ -448,7 +447,7 @@ rw_lock_x_lock_func_nowait(
ibool success;
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
success = os_compare_and_swap(&(lock->lock_word), X_LOCK_DECR, 0);
success = os_compare_and_swap_lint(&lock->lock_word, X_LOCK_DECR, 0);
#else
success = FALSE;
......
......@@ -486,9 +486,10 @@ struct mutex_struct {
os_event_t event; /* Used by sync0arr.c for the wait queue */
byte lock_word; /* This byte is the target of the atomic
test-and-set instruction in Win32 and
x86 32/64 with GCC 4.1.0 or later version */
when atomic operations are enabled on other
platforms. */
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#elif defined(HAVE_ATOMIC_BUILTINS)
#else
os_fast_mutex_t
os_fast_mutex; /* In other systems we use this OS mutex
......
......@@ -111,8 +111,8 @@ mutex_test_and_set(
/* mutex_fence(); */
return(res);
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __sync_lock_test_and_set(&(mutex->lock_word), 1);
#elif defined(HAVE_ATOMIC_BUILTINS)
return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
#else
ibool ret;
......@@ -149,11 +149,11 @@ mutex_reset_lock_word(
__asm MOV EDX, 0
__asm MOV ECX, lw
__asm XCHG DL, BYTE PTR [ECX]
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#elif defined(HAVE_ATOMIC_BUILTINS)
/* In theory __sync_lock_release should be used to release the lock.
Unfortunately, it does not work properly alone. The workaround is
that more conservative __sync_lock_test_and_set is used instead. */
__sync_lock_test_and_set(&(mutex->lock_word), 0);
os_atomic_test_and_set_byte(&mutex->lock_word, 0);
#else
mutex->lock_word = 0;
......
......@@ -113,10 +113,15 @@ of the 32-bit x86 assembler in mutex operations. */
# define UNIV_CAN_USE_X86_ASSEMBLER
# endif
# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS)
/* If atomics are defined we use them in InnoDB mutex implementation */
# define HAVE_ATOMIC_BUILTINS
# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) */
/* For InnoDB rw_locks to work with atomics we need the thread_id
to be no more than machine word wide. The following enables using
atomics for InnoDB rw_locks where these conditions are met. */
#ifdef HAVE_GCC_ATOMIC_BUILTINS
#ifdef HAVE_ATOMIC_BUILTINS
/* if HAVE_ATOMIC_PTHREAD_T is defined at this point that means that
the code from plug.in has defined it and we do not need to include
ut0auxconf.h which would either define HAVE_ATOMIC_PTHREAD_T or will
......@@ -129,7 +134,7 @@ from Makefile.in->ut0auxconf.h */
# ifdef HAVE_ATOMIC_PTHREAD_T
# define INNODB_RW_LOCKS_USE_ATOMICS
# endif /* HAVE_ATOMIC_PTHREAD_T */
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
#endif /* HAVE_ATOMIC_BUILTINS */
/* We only try to do explicit inlining of functions with gcc and
Microsoft Visual C++ */
......
......@@ -38,6 +38,16 @@ MYSQL_PLUGIN_ACTIONS(innobase, [
irix*|osf*|sysv5uw7*|openbsd*)
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
*solaris*|*SunOS*)
# Begin Solaris atomic function checks
AC_CHECK_FUNCS(atomic_cas_ulong atomic_cas_32 \
atomic_cas_64 atomic_add_long,
AC_DEFINE(
[HAVE_SOLARIS_ATOMICS],
[1],
[Define to 1 if Solaris supports \
atomic functions.]))
### End Solaris atomic function checks
CFLAGS="$CFLAGS -DUNIV_SOLARIS";;
esac
INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN"
......@@ -75,6 +85,39 @@ MYSQL_PLUGIN_ACTIONS(innobase, [
AC_MSG_RESULT(no)
]
)
# Try using solaris atomics on SunOS if GCC atomics are not available
AC_CHECK_DECLS(
[HAVE_ATOMIC_PTHREAD_T],
[
AC_MSG_NOTICE(no need to check pthread_t size)
],
[
AC_CHECK_DECLS(
[HAVE_SOLARIS_ATOMICS],
[
AC_MSG_CHECKING(checking if pthread_t size is integral)
AC_TRY_RUN(
[
#include <pthread.h>
int main()
{
pthread_t x = 0;
return(0);
}
],
[
AC_DEFINE([HAVE_ATOMIC_PTHREAD_T], [1],
[pthread_t can be used by solaris atomics])
AC_MSG_RESULT(yes)
# size of pthread_t is needed for typed solaris atomics
AC_CHECK_SIZEOF([pthread_t], [], [#include <pthread.h>])
],
[
AC_MSG_RESULT(no)
])
])
])
])
# vim: set ft=config:
......@@ -1805,7 +1805,7 @@ srv_export_innodb_status(void)
export_vars.innodb_buffer_pool_pages_misc = buf_pool->curr_size
- UT_LIST_GET_LEN(buf_pool->LRU)
- UT_LIST_GET_LEN(buf_pool->free);
#ifdef HAVE_GCC_ATOMIC_BUILTINS
#ifdef HAVE_ATOMIC_BUILTINS
export_vars.innodb_have_atomic_builtins = 1;
#else
export_vars.innodb_have_atomic_builtins = 0;
......
......@@ -1078,13 +1078,21 @@ innobase_start_or_create_for_mysql(void)
}
#ifdef HAVE_GCC_ATOMIC_BUILTINS
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
# ifdef INNODB_RW_LOCKS_USE_ATOMICS
fprintf(stderr,
"InnoDB: Mutexes and rw_locks use GCC atomic builtins.\n");
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
# else /* INNODB_RW_LOCKS_USE_ATOMICS */
fprintf(stderr,
"InnoDB: Mutexes use GCC atomic builtins, rw_locks do not.\n");
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
# endif /* INNODB_RW_LOCKS_USE_ATOMICS */
#elif defined(HAVE_SOLARIS_ATOMICS)
# ifdef INNODB_RW_LOCKS_USE_ATOMICS
fprintf(stderr,
"InnoDB: Mutexes and rw_locks use Solaris atomic functions.\n");
# else
fprintf(stderr,
"InnoDB: Mutexes use Solaris atomic functions.\n");
# endif /* INNODB_RW_LOCKS_USE_ATOMICS */
#else /* HAVE_GCC_ATOMIC_BUILTINS */
fprintf(stderr,
"InnoDB: Neither mutexes nor rw_locks use GCC atomic builtins.\n");
......
......@@ -856,8 +856,8 @@ sync_array_object_signalled(
/*========================*/
sync_array_t* arr) /* in: wait array */
{
#ifdef HAVE_GCC_ATOMIC_BUILTINS
(void) os_atomic_increment(&arr->sg_count, 1);
#ifdef HAVE_ATOMIC_BUILTINS
(void) os_atomic_increment_ulint(&arr->sg_count, 1);
#else
sync_array_enter(arr);
......
......@@ -237,7 +237,7 @@ mutex_create_func(
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
mutex_reset_lock_word(mutex);
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#elif defined(HAVE_ATOMIC_BUILTINS)
mutex_reset_lock_word(mutex);
#else
os_fast_mutex_init(&(mutex->os_fast_mutex));
......@@ -328,7 +328,7 @@ mutex_free(
os_event_free(mutex->event);
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
#elif defined(HAVE_ATOMIC_BUILTINS)
#else
os_fast_mutex_free(&(mutex->os_fast_mutex));
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment