Commit e0b8c917 authored by calvin's avatar calvin

branches/zip: Use the Windows Interlocked functions for atomic memory

access

Mapping the atomic operations to Windows Interlocked functions:

os_compare_and_swap_* to InterlockedCompareExchange(64)
os_atomic_increment_* to InterlockedExchangeAdd(64)
os_atomic_test_and_set_byte to InterlockedExchange

In this patch, the legacy code under UNIV_CAN_USE_X86_ASSEMBLER is
removed all together, and add HAVE_WINDOWS_ATOMICS and
INNODB_RW_LOCKS_USE_ATOMICS to CMakeLists.txt

This is to address mantis issue#194.

rb://113

Approved by: Marko
parent 0bd50a09
......@@ -101,7 +101,9 @@ SET(INNODB_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
ut/ut0list.c ut/ut0wqueue.c)
IF(NOT SOURCE_SUBLIBS)
ADD_DEFINITIONS(-D_WIN32)
# INNODB_RW_LOCKS_USE_ATOMICS may be defined only if HAVE_WINDOWS_ATOMICS is defined.
# Windows Interlocked functions require Windows 2000 or newer operating system
ADD_DEFINITIONS(-D_WIN32 -DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS)
ADD_LIBRARY(innobase STATIC ${INNODB_SOURCES})
# Require mysqld_error.h, which is built as part of the GenError
ADD_DEPENDENCIES(innobase GenError)
......
......@@ -347,6 +347,39 @@ amount of increment. */
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)
/* On Windows, use Windows atomics / interlocked */
#elif defined(HAVE_WINDOWS_ATOMICS)
# ifdef _WIN64
# define win_cmp_and_xchg InterlockedCompareExchange64
# define win_xchg_and_add InterlockedExchangeAdd64
# else /* _WIN64 */
# define win_cmp_and_xchg InterlockedCompareExchange
# define win_xchg_and_add InterlockedExchangeAdd
# endif
/**************************************************************
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) \
(win_cmp_and_xchg(ptr, new_val, old_val) == old_val)
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
(win_cmp_and_xchg(ptr, new_val, old_val) == old_val)
# ifdef INNODB_RW_LOCKS_USE_ATOMICS
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
(InterlockedCompareExchange(ptr, new_val, old_val) == old_val)
# 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) \
(win_xchg_and_add(ptr, amount) + amount)
# define os_atomic_increment_ulint(ptr, amount) \
((ulint) (win_xchg_and_add(ptr, amount) + amount))
/**************************************************************
Returns the old value of *ptr, atomically sets *ptr to new_val.
InterlockedExchange() operates on LONG, and the LONG will be
clobbered */
# define os_atomic_test_and_set_byte(ptr, new_val) \
((byte) InterlockedExchange(ptr, new_val))
#endif /* HAVE_GCC_ATOMIC_BUILTINS */
#ifndef UNIV_NONINL
......
......@@ -42,6 +42,13 @@ Created 9/5/1995 Heikki Tuuri
extern my_bool timed_mutexes;
#ifdef HAVE_WINDOWS_ATOMICS
typedef LONG lock_word_t; /* On Windows, InterlockedExchange operates
on LONG variable */
#else
typedef byte lock_word_t;
#endif
/**********************************************************************
Initializes the synchronization data structures. */
UNIV_INTERN
......@@ -258,7 +265,7 @@ mutex_n_reserved(void);
NOT to be used outside this module except in debugging! Gets the value
of the lock word. */
UNIV_INLINE
byte
lock_word_t
mutex_get_lock_word(
/*================*/
const mutex_t* mutex); /* in: mutex */
......@@ -484,16 +491,14 @@ implementation of a mutual exclusion semaphore. */
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
when atomic operations are enabled on other
platforms. */
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_ATOMIC_BUILTINS)
#else
volatile lock_word_t lock_word; /* lock_word is the target
of the atomic test-and-set instruction when
atomic operations are enabled. */
#if !defined(HAVE_ATOMIC_BUILTINS)
os_fast_mutex_t
os_fast_mutex; /* In other systems we use this OS mutex
in place of lock_word */
os_fast_mutex; /* We use this OS mutex in place of lock_word
when atomic operations are not enabled */
#endif
ulint waiters; /* This ulint is set to 1 if there are (or
may be) threads waiting in the global wait
......
......@@ -79,39 +79,7 @@ mutex_test_and_set(
1 */
mutex_t* mutex) /* in: mutex */
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
byte res;
byte* lw; /* assembler code is used to ensure that
lock_word is loaded from memory */
ut_ad(mutex);
ut_ad(sizeof(byte) == 1);
lw = &(mutex->lock_word);
__asm MOV ECX, lw
__asm MOV EDX, 1
__asm XCHG DL, BYTE PTR [ECX]
__asm MOV res, DL
/* The fence below would prevent this thread from
reading the data structure protected by the mutex
before the test-and-set operation is committed, but
the fence is apparently not needed:
In a posting to comp.arch newsgroup (August 10, 1997)
Andy Glew said that in P6 a LOCKed instruction like
XCHG establishes a fence with respect to memory reads
and writes and thus an explicit fence is not
needed. In P5 he seemed to agree with a previous
newsgroup poster that LOCKed instructions serialize
all instruction execution, and, consequently, also
memory operations. This is confirmed in Intel Software
Dev. Manual, Vol. 3. */
/* mutex_fence(); */
return(res);
#elif defined(HAVE_ATOMIC_BUILTINS)
#if defined(HAVE_ATOMIC_BUILTINS)
return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
#else
ibool ret;
......@@ -139,17 +107,7 @@ mutex_reset_lock_word(
/*==================*/
mutex_t* mutex) /* in: mutex */
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
byte* lw; /* assembler code is used to ensure that
lock_word is loaded from memory */
ut_ad(mutex);
lw = &(mutex->lock_word);
__asm MOV EDX, 0
__asm MOV ECX, lw
__asm XCHG DL, BYTE PTR [ECX]
#elif defined(HAVE_ATOMIC_BUILTINS)
#if 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. */
......@@ -164,18 +122,14 @@ mutex_reset_lock_word(
/**********************************************************************
Gets the value of the lock word. */
UNIV_INLINE
byte
lock_word_t
mutex_get_lock_word(
/*================*/
const mutex_t* mutex) /* in: mutex */
{
const volatile byte* ptr; /* declared volatile to ensure that
lock_word is loaded from memory */
ut_ad(mutex);
ptr = &(mutex->lock_word);
return(*ptr);
return(mutex->lock_word);
}
/**********************************************************************
......
......@@ -70,9 +70,10 @@ the virtual method table (vtable) in GCC 3. */
# include <windows.h>
# if !defined(WIN64) && !defined(_WIN64)
# define UNIV_CAN_USE_X86_ASSEMBLER
# endif
# if defined(HAVE_WINDOWS_ATOMICS)
/* If atomics are defined we use them in InnoDB mutex implementation */
# define HAVE_ATOMIC_BUILTINS
# endif /* HAVE_WINDOWS_ATOMICS */
# ifdef _NT_
# define __NT__
......@@ -106,17 +107,12 @@ if we are compiling on Windows. */
# include <sched.h>
# endif
/* When compiling for Itanium IA64, undefine the flag below to prevent use
of the 32-bit x86 assembler in mutex operations. */
# if defined(__WIN__) && !defined(WIN64) && !defined(_WIN64)
# define UNIV_CAN_USE_X86_ASSEMBLER
# endif
# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS)
# if defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_SOLARIS_ATOMICS) \
|| defined(HAVE_WINDOWS_ATOMICS)
/* If atomics are defined we use them in InnoDB mutex implementation */
# define HAVE_ATOMIC_BUILTINS
# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS) */
# endif /* (HAVE_GCC_ATOMIC_BUILTINS) || (HAVE_SOLARIS_ATOMICS)
|| (HAVE_WINDOWS_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
......
......@@ -1093,6 +1093,14 @@ innobase_start_or_create_for_mysql(void)
fprintf(stderr,
"InnoDB: Mutexes use Solaris atomic functions.\n");
# endif /* INNODB_RW_LOCKS_USE_ATOMICS */
#elif HAVE_WINDOWS_ATOMICS
# ifdef INNODB_RW_LOCKS_USE_ATOMICS
fprintf(stderr,
"InnoDB: Mutexes and rw_locks use Windows interlocked functions.\n");
# else
fprintf(stderr,
"InnoDB: Mutexes use Windows interlocked 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");
......
......@@ -235,9 +235,7 @@ mutex_create_func(
const char* cfile_name, /* in: file name where created */
ulint cline) /* in: file line where created */
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
mutex_reset_lock_word(mutex);
#elif defined(HAVE_ATOMIC_BUILTINS)
#if defined(HAVE_ATOMIC_BUILTINS)
mutex_reset_lock_word(mutex);
#else
os_fast_mutex_init(&(mutex->os_fast_mutex));
......@@ -327,9 +325,7 @@ mutex_free(
os_event_free(mutex->event);
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
#elif defined(HAVE_ATOMIC_BUILTINS)
#else
#if !defined(HAVE_ATOMIC_BUILTINS)
os_fast_mutex_free(&(mutex->os_fast_mutex));
#endif
/* If we free the mutex protecting the mutex list (freeing is
......
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