Below is the list of changes that have just been committed into a local
5.1 repository of . When does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-06-05 22:34:04+02:00, guilhem@mysqlwin32. +23 -0
Making libmytap compile under Windows.
Making all unit tests (mysys, examples) compile and pass under Windows.
Using Interlocked* intrinsics to implement my_atomic functions under
Windows.
Speed stats when running my_atomic-t in Release build:
Interlocked* is 150-200 times faster than rwlocks,
and 17-60% slower than hand-written assembler on Linux (same machine).
It has not been said where this would be pushed:
- does not have to be 5.1 as only online backup uses my_atomic
- but having unit tests working on Windows is interesting even in 5.1
as 5.1 uses my_bitmap and base64 modules which are covered in these
unit tests. When this patch is approved I can ask authorities.
And when it is pushed, unit tests can be enabled in pushbuild's
Win32 hosts, and also Win64 hosts (I don't have Win64).
CMakeLists.txt@stripped, 2007-06-05 22:33:53+02:00, guilhem@mysqlwin32. +10 -0
Pass /Oi to Visual Studio so that it considers inlining intrinsics
(used in my_atomic).
We now build unit tests under Windows.
include/atomic/nolock.h@stripped, 2007-06-05 22:33:54+02:00, guilhem@mysqlwin32. +12 -12
- update of my_atomic from a newer development branch
- and addition of support for all CPUs if using MS VC; also, empty
struct is not supported by MS VC, changing to char.
include/atomic/rwlock.h@stripped, 2007-06-05 22:33:55+02:00, guilhem@mysqlwin32. +14 -9
update to my_atomic from a newer development branch
include/atomic/x86-gcc.h@stripped, 2007-06-05 22:33:55+02:00, guilhem@mysqlwin32. +21 -10
update to my_atomic from a newer development branch
include/atomic/x86-msvc.h@stripped, 2007-06-05 22:33:55+02:00, guilhem@mysqlwin32. +40 -72
using compiler intrinsics on Windows (32 and 64) to implement my_atomic
atomic functions. It replaces assembler which wasn't functional.
include/my_atomic.h@stripped, 2007-06-05 22:33:54+02:00, guilhem@mysqlwin32. +161 -60
- update of my_atomic from a newer development branch
- and addition of comments, CAS-based definitions of
my_atomic_fas/store/load if not natively implemented by the platform,
shuffling order of make_atomic_*_body() calls (as for example "store"
may depend on "fas"), and removing 8-bit and 16-bit types, as we
don't use them and Windows intrinsics don't allow to use them (only
32-bit and pointer).
include/my_global.h@stripped, 2007-06-05 22:33:54+02:00, guilhem@mysqlwin32. +2 -0
- update of my_atomic from a newer development branch
mysys/CMakeLists.txt@stripped, 2007-06-05 22:33:56+02:00, guilhem@mysqlwin32. +2 -1
my_atomic.c and my_getncpus.c were missing from mysys on Windows
mysys/my_atomic.c@stripped, 2007-06-05 22:33:56+02:00, guilhem@mysqlwin32. +1 -1
to have my_getncpus() it needs my_sys.h
mysys/my_getncpus.c@stripped, 2007-06-05 22:33:56+02:00, guilhem@mysqlwin32. +12 -10
implementation of my_getncpus() under Windows (thanks Miguel and Shane,
who gave solutions a few seconds after I asked!)
mysys/my_winthread.c@stripped, 2007-06-05 22:33:56+02:00, guilhem@mysqlwin32. +16 -6
two bugfixes: on Windows, our implementation of pthread_create() didn't
allow a NULL thread attribute, and also, when creating a thread,
my_thread_init() was called, but at thread's end, my_thread_end()
was not called (causing "my_thread_global_end: X threads didn't
exit" to be printed).
unittest/examples/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +40
-0
We now build examples unit tests on Windows
unittest/examples/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +0
-0
unittest/examples/core-t.c@stripped, 2007-06-05 22:33:57+02:00, guilhem@mysqlwin32. +1 -1
my_config.h is for Unix
unittest/examples/no_plan-t.c@stripped, 2007-06-05 22:33:57+02:00, guilhem@mysqlwin32. +1 -1
my_config.h is for Unix
unittest/examples/skip_all-t.c@stripped, 2007-06-05 22:33:58+02:00, guilhem@mysqlwin32. +1 -1
my_config.h is for Unix
unittest/examples/todo-t.c@stripped, 2007-06-05 22:33:58+02:00, guilhem@mysqlwin32. +1 -1
my_config.h is for Unix
unittest/mysys/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +31 -0
We now build mysys unit tests on Windows
unittest/mysys/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +0 -0
unittest/mysys/bitmap-t.c@stripped, 2007-06-05 22:33:58+02:00, guilhem@mysqlwin32. +1 -0
MY_BITMAP structure contains a mutex so needs my_sys.h
unittest/mysys/my_atomic-t.c@stripped, 2007-06-05 22:33:59+02:00, guilhem@mysqlwin32. +193
-56
- update to my_atomic from a newer development branch
- one variable changes from uint32 to int32 (avoid compiler warning)
- pthread_join() hanged on Windows, replaced with a global counter,
with main thread waiting for the counter to be 0.
unittest/mytap/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +23 -0
we now build libmytap on Windows
unittest/mytap/CMakeLists.txt@stripped, 2007-06-05 22:34:00+02:00, guilhem@mysqlwin32. +0 -0
unittest/mytap/tap.c@stripped, 2007-06-05 22:33:59+02:00, guilhem@mysqlwin32. +10 -3
my_config.h is for Unix.
Visual Studio 2003 does not know vsprintf, so we use _vsnprintf. I don't
put that in config-win.h because generally we should use my_vsnprintf(),
not vsnprintf(); on the other hand, I didn't want to replace
vsnprintf() by my_vsnprintf() in tap.c as it would have required to
link all unit tests with mysys.
SIGBUS not known on Windows.
unittest/mytap/tap.h@stripped, 2007-06-05 22:33:59+02:00, guilhem@mysqlwin32. +3 -3
Fix for compiler warnings (there were differences in prototypes
between tap.c and tap.h).
unittest/unit.pl@stripped, 2007-06-05 22:33:57+02:00, guilhem@mysqlwin32. +2 -2
On Windows, our executables end in ".exe".
That change was enough to have
cd unittest; perl unit.pl run mysys
work fine if using Cygwin's perl. But with Activestate's, it appeared
that the test program was internally invoked as
perl -e 'exec @ARGV' mysys/the_test_program
and ' is not a string delimitor on Windows so the 'exec @ARGV' was
interpreted as two arguments instead of one. Using " solves this.
So now the command works with both Cygwin and Activestate.
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: guilhem
# Host: mysqlwin32.
# Root: C:/mysql-5.1-rpl-atomic-ops
--- 1.13/mysys/my_winthread.c 2006-12-23 20:04:08 +01:00
+++ 1.14/mysys/my_winthread.c 2007-06-05 22:33:56 +02:00
@@ -54,12 +54,15 @@
{
pthread_handler func=((struct pthread_map *) param)->func;
void *func_param=((struct pthread_map *) param)->param;
+ void *result;
my_thread_init(); /* Will always succeed in windows */
pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beginthread to return */
win_pthread_self=((struct pthread_map *) param)->pthreadself;
pthread_mutex_unlock(&THR_LOCK_thread);
free((char*) param); /* Free param from create */
- pthread_exit((void*) (*func)(func_param));
+ result= (void*) (*func)(func_param);
+ my_thread_end();
+ pthread_exit(result);
return 0; /* Safety */
}
@@ -69,21 +72,28 @@
{
HANDLE hThread;
struct pthread_map *map;
+ DWORD StackSize= 0;
+ int priority= 0;
DBUG_ENTER("pthread_create");
if (!(map=malloc(sizeof(*map))))
DBUG_RETURN(-1);
map->func=func;
map->param=param;
+ if (attr != NULL)
+ {
+ StackSize= attr->dwStackSize;
+ priority= attr->priority;
+ }
+ if (StackSize == 0)
+ StackSize= 65535;
pthread_mutex_lock(&THR_LOCK_thread);
#ifdef __BORLANDC__
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
- 65535, (void*) map);
+ StackSize, (void*) map);
#else
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
- attr->dwStackSize ? attr->dwStackSize :
- 65535, (void*) map);
+ StackSize, (void*) map);
#endif
DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
*thread_id=map->pthreadself=hThread;
@@ -96,7 +106,7 @@
("Can't create thread to handle request (error %d)",error));
DBUG_RETURN(error ? error : -1);
}
- VOID(SetThreadPriority(hThread, attr->priority)) ;
+ VOID(SetThreadPriority(hThread, priority)) ;
DBUG_RETURN(0);
}
--- New file ---
+++ unittest/examples/CMakeLists.txt 07/06/05 22:34:00
# Copyright (C) 2006 MySQL AB
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include
${CMAKE_SOURCE_DIR}/unittest/mytap)
ADD_EXECUTABLE(simple-t simple-t.c)
TARGET_LINK_LIBRARIES(simple-t mytap)
ADD_EXECUTABLE(skip-t skip-t.c)
TARGET_LINK_LIBRARIES(skip-t mytap)
ADD_EXECUTABLE(todo-t todo-t.c)
TARGET_LINK_LIBRARIES(todo-t mytap)
ADD_EXECUTABLE(skip_all-t skip_all-t.c)
TARGET_LINK_LIBRARIES(skip_all-t mytap)
ADD_EXECUTABLE(no_plan-t no_plan-t.c)
TARGET_LINK_LIBRARIES(no_plan-t mytap)
ADD_EXECUTABLE(core-t core-t.c)
TARGET_LINK_LIBRARIES(core-t mytap)
--- New file ---
+++ unittest/mysys/CMakeLists.txt 07/06/05 22:34:00
# Copyright (C) 2006 MySQL AB
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include
${CMAKE_SOURCE_DIR}/unittest/mytap)
ADD_EXECUTABLE(bitmap-t bitmap-t.c)
TARGET_LINK_LIBRARIES(bitmap-t mytap mysys dbug strings)
ADD_EXECUTABLE(base64-t base64-t.c)
TARGET_LINK_LIBRARIES(base64-t mytap mysys dbug strings)
ADD_EXECUTABLE(my_atomic-t my_atomic-t.c)
TARGET_LINK_LIBRARIES(my_atomic-t mytap mysys dbug strings wsock32)
--- New file ---
+++ unittest/mytap/CMakeLists.txt 07/06/05 22:34:00
# Copyright (C) 2006 MySQL AB
#
# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
${CMAKE_SOURCE_DIR}/sql
${CMAKE_SOURCE_DIR}/regex
${CMAKE_SOURCE_DIR}/extra/yassl/include)
ADD_LIBRARY(mytap tap.c)
--- 1.10/unittest/mytap/tap.c 2006-12-23 20:33:31 +01:00
+++ 1.11/unittest/mytap/tap.c 2007-06-05 22:33:59 +02:00
@@ -19,7 +19,7 @@
#include "tap.h"
-#include "my_config.h"
+#include "my_global.h"
#include <stdlib.h>
#include <stdarg.h>
@@ -27,6 +27,11 @@
#include <string.h>
#include <signal.h>
+/* Visual Studio 2003 does not know vsnprintf but knows _vsnprintf */
+#if defined(_MSC_VER) && ( _MSC_VER == 1310 )
+#define vsnprintf _vsnprintf
+#endif
+
/**
@defgroup MyTAP_Internal MyTAP Internals
@@ -150,8 +155,10 @@
{ SIGILL, handle_core_signal },
{ SIGABRT, handle_core_signal },
{ SIGFPE, handle_core_signal },
- { SIGSEGV, handle_core_signal },
- { SIGBUS, handle_core_signal }
+ { SIGSEGV, handle_core_signal }
+#ifdef SIGBUS
+ , { SIGBUS, handle_core_signal }
+#endif
#ifdef SIGXCPU
, { SIGXCPU, handle_core_signal }
#endif
--- 1.9/unittest/mytap/tap.h 2006-12-23 20:33:31 +01:00
+++ 1.10/unittest/mytap/tap.h 2007-06-05 22:33:59 +02:00
@@ -84,7 +84,7 @@
@param count The planned number of tests to run.
*/
-void plan(int count);
+void plan(int const count);
/**
@@ -103,7 +103,7 @@
which case nothing is printed.
*/
-void ok(int pass, char const *fmt, ...)
+void ok(int const pass, char const *fmt, ...)
__attribute__((format(printf,2,3)));
@@ -135,7 +135,7 @@
@param reason A reason for skipping the tests
*/
-void skip(int how_many, char const *reason, ...)
+void skip(int how_many, char const *const reason, ...)
__attribute__((format(printf,2,3)));
--- 1.5/unittest/examples/no_plan-t.c 2006-12-31 02:28:54 +01:00
+++ 1.6/unittest/examples/no_plan-t.c 2007-06-05 22:33:57 +02:00
@@ -13,7 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "my_config.h"
+#include <my_global.h>
#include <stdlib.h>
#include <tap.h>
--- 1.5/unittest/examples/skip_all-t.c 2006-12-31 02:28:54 +01:00
+++ 1.6/unittest/examples/skip_all-t.c 2007-06-05 22:33:58 +02:00
@@ -13,7 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "my_config.h"
+#include <my_global.h>
#include <stdlib.h>
#include <tap.h>
--- 1.4/unittest/examples/todo-t.c 2006-12-31 02:28:54 +01:00
+++ 1.5/unittest/examples/todo-t.c 2007-06-05 22:33:58 +02:00
@@ -13,7 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "my_config.h"
+#include <my_global.h>
#include <stdlib.h>
#include <tap.h>
--- 1.5/unittest/mysys/bitmap-t.c 2006-12-23 20:33:31 +01:00
+++ 1.6/unittest/mysys/bitmap-t.c 2007-06-05 22:33:58 +02:00
@@ -21,6 +21,7 @@
#include <tap.h>
#include <my_global.h>
+#include <my_sys.h>
#include <my_bitmap.h>
#include <string.h>
--- 1.7/unittest/unit.pl 2006-12-31 02:28:54 +01:00
+++ 1.8/unittest/unit.pl 2007-06-05 22:33:57 +02:00
@@ -56,7 +56,7 @@
my @files;
find sub {
$File::Find::prune = 1 if /^SCCS$/;
- push(@files, $File::Find::name) if -x _ && /-t\z/;
+ push(@files, $File::Find::name) if -x _ && (/-t\z/ || /-t\.exe\z/);
}, @dirs;
return @files;
}
@@ -92,7 +92,7 @@
if (@files > 0) {
# Removing the first './' from the file names
foreach (@files) { s!^\./!! }
- $ENV{'HARNESS_PERL_SWITCHES'} .= q" -e 'exec @ARGV'";
+ $ENV{'HARNESS_PERL_SWITCHES'} .= ' -e "exec @ARGV"';
runtests @files;
}
}
--- 1.2/unittest/examples/core-t.c 2006-12-31 02:28:54 +01:00
+++ 1.3/unittest/examples/core-t.c 2007-06-05 22:33:57 +02:00
@@ -13,7 +13,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-#include "my_config.h"
+#include <my_global.h>
#include <stdlib.h>
#include <tap.h>
--- 1.163/include/my_global.h 2007-03-22 01:04:26 +01:00
+++ 1.164/include/my_global.h 2007-06-05 22:33:54 +02:00
@@ -224,6 +224,8 @@
#endif
#undef inline_test_2
#undef inline_test_1
+/* helper macro for "instantiating" inline functions */
+#define STATIC_INLINE static inline
/*
The following macros are used to control inlining a bit more than
--- 1.27/CMakeLists.txt 2007-04-10 12:51:42 +02:00
+++ 1.28/CMakeLists.txt 2007-06-05 22:33:53 +02:00
@@ -129,6 +129,13 @@
${CMAKE_CXX_FLAGS_INIT})
STRING(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS_DEBUG_INIT
${CMAKE_CXX_FLAGS_DEBUG_INIT})
+
+ # enable intrisic functions for my_atomic
+ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Oi")
+ SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Oi")
+ SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Oi")
+ SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Oi")
+
ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 7" OR
CMAKE_GENERATOR MATCHES "Visual Studio 8")
@@ -169,6 +176,9 @@
ADD_SUBDIRECTORY(server-tools/instance-manager)
ADD_SUBDIRECTORY(libmysql)
ADD_SUBDIRECTORY(tests)
+ADD_SUBDIRECTORY(unittest/mytap)
+ADD_SUBDIRECTORY(unittest/examples)
+ADD_SUBDIRECTORY(unittest/mysys)
# disable libmysqld until it's fixed, so we can use Cmake 2.2 and 2.4
#ADD_SUBDIRECTORY(libmysqld)
--- 1.12/mysys/CMakeLists.txt 2007-03-12 14:55:33 +01:00
+++ 1.13/mysys/CMakeLists.txt 2007-06-05 22:33:56 +02:00
@@ -41,4 +41,5 @@
my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c my_wincond.c
my_windac.c my_winthread.c my_write.c ptr_cmp.c queues.c
rijndael.c safemalloc.c sha1.c string.c thr_alarm.c thr_lock.c thr_mutex.c
- thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c)
+ thr_rwlock.c tree.c typelib.c my_vle.c base64.c my_memmem.c my_getpagesize.c
+ my_atomic.c my_getncpus.c)
--- 1.4/include/atomic/nolock.h 2006-12-23 20:33:28 +01:00
+++ 1.5/include/atomic/nolock.h 2007-06-05 22:33:54 +02:00
@@ -13,24 +13,24 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#if defined(__i386__) || defined(_M_IX86)
+#if defined(__i386__) || defined(_MSC_VER) || defined(__x86_64__)
-#ifdef MY_ATOMIC_MODE_DUMMY
-# define LOCK ""
-#else
-# define LOCK "lock"
-#endif
+# ifdef MY_ATOMIC_MODE_DUMMY
+# define LOCK_prefix ""
+# else
+# define LOCK_prefix "lock"
+# endif
-#ifdef __GNUC__
-#include "x86-gcc.h"
-#elif defined(_MSC_VER)
-#include "x86-msvc.h"
-#endif
+# ifdef __GNUC__
+# include "x86-gcc.h"
+# elif defined(_MSC_VER)
+# include "x86-msvc.h"
+# endif
#endif
#ifdef make_atomic_cas_body
-typedef struct { } my_atomic_rwlock_t;
+typedef char my_atomic_rwlock_t __attribute__ ((unused));
#define my_atomic_rwlock_destroy(name)
#define my_atomic_rwlock_init(name)
#define my_atomic_rwlock_rdlock(name)
--- 1.3/include/atomic/rwlock.h 2006-12-23 20:33:28 +01:00
+++ 1.4/include/atomic/rwlock.h 2007-06-05 22:33:55 +02:00
@@ -13,7 +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 */
-typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
+typedef struct {pthread_mutex_t rw;} my_atomic_rwlock_t;
#ifdef MY_ATOMIC_MODE_DUMMY
/*
@@ -31,17 +31,22 @@
#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"
#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;
--- 1.5/include/atomic/x86-gcc.h 2006-12-23 20:33:28 +01:00
+++ 1.6/include/atomic/x86-gcc.h 2007-06-05 22:33:55 +02:00
@@ -19,10 +19,18 @@
architectures support double-word (128-bit) cas.
*/
-#ifdef MY_ATOMIC_NO_XADD
-#define MY_ATOMIC_MODE "gcc-x86" LOCK "-no-xadd"
+#ifdef __x86_64__
+# ifdef MY_ATOMIC_NO_XADD
+# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix "-no-xadd"
+# else
+# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix
+# endif
#else
-#define MY_ATOMIC_MODE "gcc-x86" LOCK
+# ifdef MY_ATOMIC_NO_XADD
+# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix "-no-xadd"
+# else
+# define MY_ATOMIC_MODE "gcc-x86" LOCK_prefix
+# endif
#endif
/* fix -ansi errors while maintaining readability */
@@ -32,12 +40,12 @@
#ifndef MY_ATOMIC_NO_XADD
#define make_atomic_add_body(S) \
- asm volatile (LOCK "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
+ asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
#endif
-#define make_atomic_swap_body(S) \
- asm volatile ("; xchg %0, %1;" : "+r" (v) , "+m" (*a))
+#define make_atomic_fas_body(S) \
+ asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a))
#define make_atomic_cas_body(S) \
- asm volatile (LOCK "; cmpxchg %3, %0; setz %2;" \
+ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \
: "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set))
#ifdef MY_ATOMIC_MODE_DUMMY
@@ -46,13 +54,16 @@
#else
/*
Actually 32-bit reads/writes are always atomic on x86
- But we add LOCK here anyway to force memory barriers
+ But we add LOCK_prefix here anyway to force memory barriers
*/
#define make_atomic_load_body(S) \
ret=0; \
- asm volatile (LOCK "; cmpxchg %2, %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))
+ asm volatile ("; xchg %0, %1;" : "+m" (*a), "+r" (v))
#endif
+
+/* TODO test on intel whether the below helps. on AMD it makes no difference */
+//#define LF_BACKOFF ({asm volatile ("rep; nop"); 1; })
--- 1.4/include/atomic/x86-msvc.h 2006-12-23 20:33:28 +01:00
+++ 1.5/include/atomic/x86-msvc.h 2007-06-05 22:33:55 +02:00
@@ -13,84 +13,52 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- XXX 64-bit atomic operations can be implemented using
- cmpxchg8b, if necessary
-*/
-
-// Would it be better to use intrinsics ?
-// (InterlockedCompareExchange, InterlockedCompareExchange16
-// InterlockedExchangeAdd, InterlockedExchange)
-
#ifndef _atomic_h_cleanup_
#define _atomic_h_cleanup_ "atomic/x86-msvc.h"
-#define MY_ATOMIC_MODE "msvc-x86" LOCK
-
-#define make_atomic_add_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm LOCK xadd *a, reg_ ## S \
- _asm movzx v, reg_ ## S \
- }
-#define make_atomic_cas_body(S) \
- _asm { \
- _asm mov areg_ ## S, *cmp \
- _asm mov reg2_ ## S, set \
- _asm LOCK cmpxchg *a, reg2_ ## S \
- _asm mov *cmp, areg_ ## S \
- _asm setz al \
- _asm movzx ret, al \
- }
-#define make_atomic_swap_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm xchg *a, reg_ ## S \
- _asm mov v, reg_ ## S \
- }
-
-#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 here anyway to force memory barriers
+ TODO this file is expected to work fine on x86-64, rename it to msvc.h
+ before pushing.
*/
-#define make_atomic_load_body(S) \
- _asm { \
- _asm mov areg_ ## S, 0 \
- _asm mov reg2_ ## S, areg_ ## S \
- _asm LOCK cmpxchg *a, reg2_ ## S \
- _asm mov ret, areg_ ## S \
- }
-#define make_atomic_store_body(S) \
- _asm { \
- _asm mov reg_ ## S, v \
- _asm xchg *a, reg_ ## S \
- }
-#endif
-
-#define reg_8 al
-#define reg_16 ax
-#define reg_32 eax
-#define areg_8 al
-#define areg_16 ax
-#define areg_32 eax
-#define reg2_8 bl
-#define reg2_16 bx
-#define reg2_32 ebx
+/*
+ We don't implement anything specific for MY_ATOMIC_MODE_DUMMY, always use
+ intrinsics.
+*/
+#define MY_ATOMIC_MODE "msvc-intrinsics"
+/*
+ By compiling with /Oi, we suggest the compiler to use inline versions of
+ Interlocked* functions.
+ QQ Reggie: what would it bring to additionally have #pragma intrinsic(),
+ and use _Interlocked instead of Interlocked? Reading MSDN, it is not
+ clear.
+*/
+#define IL_EXCHG_ADD32 InterlockedExchangeAdd
+#define IL_COMP_EXCHG32 InterlockedCompareExchange
+#define IL_COMP_EXCHGptr InterlockedCompareExchangePointer
+#define IL_EXCHG32 InterlockedExchange
+#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)
+/*
+ TODO: when my_atomic_load is tested in my_atomic-t.c, benchmark other possible
+ implementations (using InterlockedOr[64](a, 0)).
+*/
+#define make_atomic_load_body(S) \
+ ret= 0; /* avoid compiler warning */ \
+ ret= IL_COMP_EXCHG ## S (a, ret, ret);
#else /* cleanup */
-#undef reg_8
-#undef reg_16
-#undef reg_32
-#undef areg_8
-#undef areg_16
-#undef areg_32
-#undef reg2_8
-#undef reg2_16
-#undef reg2_32
-#endif
+#undef IL_EXCHG_ADD32
+#undef IL_COMP_EXCHG32
+#undef IL_COMP_EXCHGptr
+#undef IL_EXCHG32
+#undef IL_EXCHGptr
+#endif
--- 1.6/include/my_atomic.h 2007-01-28 21:12:55 +01:00
+++ 1.7/include/my_atomic.h 2007-06-05 22:33:54 +02:00
@@ -13,6 +13,40 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+ This header defines five atomic operations:
+
+ my_atomic_add#(&var, what)
+ add 'what' to *var, and return the old value of *var
+
+ my_atomic_fas#(&var, what)
+ 'Fetch And Store'
+ store 'what' in *var, and return the old value of *var
+
+ my_atomic_cas#(&var, &old, new)
+ 'Compare And Swap'
+ if *var is equal to *old, then store 'new' in *var, and return TRUE
+ otherwise store *var in *old, and return FALSE
+
+ my_atomic_load#(&var)
+ return *var
+
+ my_atomic_store#(&var, what)
+ store 'what' in *var
+
+ '#' is substituted by a size suffix - 8, 16, 32, 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
+ enclosed in my_atomic_rwlock_rdlock(lock)/my_atomic_rwlock_rdunlock(lock)
+ or my_atomic_rwlock_wrlock(lock)/my_atomic_rwlock_wrunlock(lock).
+ Hint: if a code block makes intensive use of atomic ops, it make sense
+ to take/release rwlock once for the whole block, not for every statement.
+
+ On architectures where these operations are really atomic, rwlocks will
+ be optimized away.
+*/
+
#ifndef my_atomic_rwlock_init
#define intptr void *
@@ -22,116 +56,183 @@
#endif
#ifndef make_atomic_cas_body
+/* nolock.h was not able to generate even a CAS function, fall back */
#include "atomic/rwlock.h"
-#endif
-
+#else
+/* define missing functions by using the already generated ones */
#ifndef make_atomic_add_body
-#define make_atomic_add_body(S) \
+#define make_atomic_add_body(S) \
int ## S tmp=*a; \
while (!my_atomic_cas ## S(a, &tmp, tmp+v)); \
v=tmp;
#endif
+#ifndef make_atomic_fas_body
+#define make_atomic_fas_body(S) \
+ int ## S tmp=*a; \
+ while (!my_atomic_cas ## S(a, &tmp, v)); \
+ v=tmp;
+#endif
+#ifndef make_atomic_load_body
+#define make_atomic_load_body(S) \
+ ret= 0; /* avoid compiler warning */ \
+ (void)(my_atomic_cas ## S(a, &ret, ret));
+#endif
+#ifndef make_atomic_store_body
+#define make_atomic_store_body(S) \
+ (void)(my_atomic_fas ## S (a, v));
+#endif
+#endif
+
+#ifdef __GNUC__
+/*
+ we want to be able to use my_atomic_xxx functions with
+ both signed and unsigned integers. But gcc will issue a warning
+ "passing arg N of `my_atomic_XXX' as [un]signed due to prototype"
+ if the signedness of the argument doesn't match the prototype, or
+ "pointer targets in passing argument N of my_atomic_XXX differ in signedness"
+ if int* is used where uint* is expected (or vice versa).
+ Let's shut these warnings up
+*/
+#define make_transparent_unions(S) \
+ typedef union { \
+ int ## S i; \
+ uint ## S u; \
+ } U_ ## S __attribute__ ((transparent_union)); \
+ typedef union { \
+ int ## S volatile *i; \
+ uint ## S volatile *u; \
+ } Uv_ ## S __attribute__ ((transparent_union));
+#define uintptr intptr
+make_transparent_unions(8)
+make_transparent_unions(16)
+make_transparent_unions(32)
+make_transparent_unions(ptr)
+#undef uintptr
+#undef make_transparent_unions
+#define a U_a.i
+#define cmp U_cmp.i
+#define v U_v.i
+#define set U_set.i
+#else
+#define U_32 int32
+#define U_ptr intptr
+#define Uv_32 int32
+#define Uv_ptr intptr
+#define U_a volatile *a
+#define U_cmp *cmp
+#define U_v v
+#define U_set set
+#endif /* __GCC__ transparent_union magic */
#ifdef HAVE_INLINE
-#define make_atomic_add(S) \
-static inline int ## S my_atomic_add ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_add_body(S); \
- return v; \
+#define make_atomic_cas(S) \
+STATIC_INLINE int my_atomic_cas ## S(Uv_ ## S U_a, \
+ Uv_ ## S U_cmp, U_ ## S U_set) \
+{ \
+ int8 ret; \
+ make_atomic_cas_body(S); \
+ return ret; \
}
-#define make_atomic_swap(S) \
-static inline int ## S my_atomic_swap ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_swap_body(S); \
- return v; \
+#define make_atomic_add(S) \
+STATIC_INLINE int ## S my_atomic_add ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_add_body(S); \
+ return v; \
}
-#define make_atomic_cas(S) \
-static inline int my_atomic_cas ## S(int ## S volatile *a, \
- int ## S *cmp, int ## S set) \
-{ \
- int8 ret; \
- make_atomic_cas_body(S); \
- return ret; \
+#define make_atomic_fas(S) \
+STATIC_INLINE int ## S my_atomic_fas ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_fas_body(S); \
+ return v; \
}
-#define make_atomic_load(S) \
-static inline int ## S my_atomic_load ## S(int ## S volatile *a) \
-{ \
- int ## S ret; \
- make_atomic_load_body(S); \
- return ret; \
+#define make_atomic_load(S) \
+STATIC_INLINE int ## S my_atomic_load ## S(Uv_ ## S U_a) \
+{ \
+ int ## S ret; \
+ make_atomic_load_body(S); \
+ return ret; \
}
-#define make_atomic_store(S) \
-static inline void my_atomic_store ## S( \
- int ## S volatile *a, int ## S v) \
-{ \
- make_atomic_store_body(S); \
+#define make_atomic_store(S) \
+STATIC_INLINE void my_atomic_store ## S( \
+ Uv_ ## S U_a, U_ ## S U_v) \
+{ \
+ make_atomic_store_body(S); \
}
#else /* no inline functions */
-#define make_atomic_add(S) \
-extern int ## S my_atomic_add ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_add(S) \
+extern int ## S my_atomic_add ## S(Uv_ ## S, U_ ## S);
-#define make_atomic_swap(S) \
-extern int ## S my_atomic_swap ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_fas(S) \
+extern int ## S my_atomic_fas ## S(Uv_ ## S, U_ ## S);
-#define make_atomic_cas(S) \
-extern int my_atomic_cas ## S(int ## S volatile *a, int ## S *cmp, int ## S set);
+#define make_atomic_cas(S) \
+extern int my_atomic_cas ## S(Uv_ ## S, Uv_ ## S, U_ ## S);
-#define make_atomic_load(S) \
-extern int ## S my_atomic_load ## S(int ## S volatile *a);
+#define make_atomic_load(S) \
+extern int ## S my_atomic_load ## S(Uv_ ## S);
-#define make_atomic_store(S) \
-extern void my_atomic_store ## S(int ## S volatile *a, int ## S v);
+#define make_atomic_store(S) \
+extern void my_atomic_store ## S(Uv_ ## S, U_ ## S);
#endif
-make_atomic_cas( 8)
-make_atomic_cas(16)
make_atomic_cas(32)
make_atomic_cas(ptr)
-make_atomic_add( 8)
-make_atomic_add(16)
make_atomic_add(32)
-make_atomic_load( 8)
-make_atomic_load(16)
make_atomic_load(32)
make_atomic_load(ptr)
-make_atomic_store( 8)
-make_atomic_store(16)
+make_atomic_fas(32)
+make_atomic_fas(ptr)
+
make_atomic_store(32)
make_atomic_store(ptr)
-make_atomic_swap( 8)
-make_atomic_swap(16)
-make_atomic_swap(32)
-make_atomic_swap(ptr)
+#ifdef _atomic_h_cleanup_
+#include _atomic_h_cleanup_
+#undef _atomic_h_cleanup_
+#endif
+#undef U_32
+#undef U_ptr
+#undef a
+#undef cmp
+#undef v
+#undef set
+#undef U_a
+#undef U_cmp
+#undef U_v
+#undef U_set
#undef make_atomic_add
#undef make_atomic_cas
#undef make_atomic_load
#undef make_atomic_store
-#undef make_atomic_swap
+#undef make_atomic_fas
#undef make_atomic_add_body
#undef make_atomic_cas_body
#undef make_atomic_load_body
#undef make_atomic_store_body
-#undef make_atomic_swap_body
+#undef make_atomic_fas_body
#undef intptr
-#ifdef _atomic_h_cleanup_
-#include _atomic_h_cleanup_
-#undef _atomic_h_cleanup_
+/*
+ the macro below defines (as an expression) the code that
+ will be run in spin-loops. Intel manuals recummend to have PAUSE there.
+ It is expected to be defined in include/atomic/ *.h files
+*/
+#ifndef LF_BACKOFF
+#define LF_BACKOFF (1)
#endif
#define MY_ATOMIC_OK 0
--- 1.3/mysys/my_atomic.c 2006-12-23 20:33:28 +01:00
+++ 1.4/mysys/my_atomic.c 2007-06-05 22:33:56 +02:00
@@ -14,7 +14,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
-#include <my_pthread.h>
+#include <my_sys.h>
#ifndef HAVE_INLINE
/*
--- 1.2/mysys/my_getncpus.c 2006-12-23 20:33:28 +01:00
+++ 1.3/mysys/my_getncpus.c 2007-06-05 22:33:56 +02:00
@@ -16,24 +16,26 @@
/* get the number of (online) CPUs */
#include "mysys_priv.h"
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
+#endif
static int ncpus=0;
-#ifdef _SC_NPROCESSORS_ONLN
int my_getncpus()
{
if (!ncpus)
+ {
+#ifdef _SC_NPROCESSORS_ONLN
ncpus= sysconf(_SC_NPROCESSORS_ONLN);
- return ncpus;
-}
-
+#elif defined(__WIN__)
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ ncpus= sysinfo.dwNumberOfProcessors;
#else
/* unknown */
-int my_getncpus()
-{
- return 2;
-}
-
+ ncpus= 2;
#endif
-
+ }
+ return ncpus;
+}
--- 1.10/unittest/mysys/my_atomic-t.c 2007-03-16 19:43:57 +01:00
+++ 1.11/unittest/mysys/my_atomic-t.c 2007-06-05 22:33:59 +02:00
@@ -13,27 +13,39 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#include <my_global.h>
#include <tap.h>
+
+#include <my_global.h>
#include <my_sys.h>
#include <my_atomic.h>
+/*
+ lock-free algorithms are not needed in 5.x trees now, they will be
+ incorporated when needed
+*/
+#ifdef DISABLED
+#include <lf.h>
+#endif
-int32 a32,b32,c32;
+volatile uint32 a32,b32;
+volatile int32 c32, N;
my_atomic_rwlock_t rwl;
-
+#ifdef DISABLED
+LF_ALLOCATOR lf_allocator;
+LF_HASH lf_hash;
+#endif
pthread_attr_t thr_attr;
pthread_mutex_t mutex;
pthread_cond_t cond;
-int N;
+uint running_threads;
/* add and sub a random number in a loop. Must get 0 at the end */
pthread_handler_t test_atomic_add_handler(void *arg)
{
- int m=*(int *)arg;
+ int m= (*(int *)arg)/2;
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_rwlock_wrunlock(&rwl);
@@ -43,8 +55,7 @@
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;
}
@@ -57,30 +68,24 @@
5. subtract result from a32
must get 0 in a32 at the end
*/
-pthread_handler_t test_atomic_swap_handler(void *arg)
+pthread_handler_t test_atomic_fas_handler(void *arg)
{
- int m=*(int *)arg;
- int32 x;
+ int m= *(int *)arg;
+ int32 x= my_atomic_add32(&b32, 1);
- my_atomic_rwlock_wrlock(&rwl);
- x=my_atomic_add32(&b32, 1);
- my_atomic_rwlock_wrunlock(&rwl);
-
- my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&a32, 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);
}
@@ -89,79 +94,199 @@
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
+ my_atomic_cas32 - notice that the slowdown is proportional to the
+ number of CPUs
*/
pthread_handler_t test_atomic_cas_handler(void *arg)
{
- int m=*(int *)arg, ok;
- int32 x,y;
- for (x=((int)((long)(&m))); m ; m--)
+ int m= (*(int *)arg)/2, ok= 0;
+ int32 x, y;
+ for (x= ((int)(intptr)(&m)); m ; m--)
{
my_atomic_rwlock_wrlock(&rwl);
- y=my_atomic_load32(&a32);
+ y= my_atomic_load32(&a32);
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(&a32, &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(&a32, &y, y-x);
my_atomic_rwlock_wrunlock(&rwl);
- } while (!ok);
+ } while (!ok) ;
+ }
+ pthread_mutex_lock(&mutex);
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+
+#ifdef DISABLED
+/*
+ pin allocator - alloc and release an element in a loop
+*/
+pthread_handler_t test_lf_pinbox(void *arg)
+{
+ int m= *(int *)arg;
+ int32 x= 0;
+ LF_PINS *pins;
+
+ pins= lf_pinbox_get_pins(&lf_allocator.pinbox);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ lf_pinbox_put_pins(pins);
+ pins= lf_pinbox_get_pins(&lf_allocator.pinbox);
}
+ lf_pinbox_put_pins(pins);
pthread_mutex_lock(&mutex);
- N--;
- if (!N) pthread_cond_signal(&cond);
+ if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
+typedef union {
+ int32 data;
+ void *not_used;
+} TLA;
+
+pthread_handler_t test_lf_alloc(void *arg)
+{
+ int m= (*(int *)arg)/2;
+ int32 x,y= 0;
+ LF_PINS *pins;
+
+ pins= lf_alloc_get_pins(&lf_allocator);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ TLA *node1, *node2;
+ x= (x*m+0x87654321) & INT_MAX32;
+ node1= (TLA *)lf_alloc_new(pins);
+ node1->data= x;
+ y+= node1->data;
+ node1->data= 0;
+ node2= (TLA *)lf_alloc_new(pins);
+ node2->data= x;
+ y-= node2->data;
+ node2->data= 0;
+ lf_alloc_free(pins, node1);
+ lf_alloc_free(pins, node2);
+ }
+ lf_alloc_put_pins(pins);
+ my_atomic_rwlock_wrlock(&rwl);
+ my_atomic_add32(&a32, y);
+
+ if (my_atomic_add32(&N, -1) == 1)
+ {
+ diag("%d mallocs, %d pins in stack",
+ lf_allocator.mallocs, lf_allocator.pinbox.pins_in_stack);
+#ifdef MY_LF_EXTRA_DEBUG
+ a32|= lf_allocator.mallocs - lf_alloc_in_pool(&lf_allocator);
+#endif
+ }
+ my_atomic_rwlock_wrunlock(&rwl);
+ pthread_mutex_lock(&mutex);
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+
+#define N_TLH 1000
+pthread_handler_t test_lf_hash(void *arg)
+{
+ int m= (*(int *)arg)/(2*N_TLH);
+ int32 x,y,z,sum= 0, ins= 0;
+ LF_PINS *pins;
+
+ pins= lf_hash_get_pins(&lf_hash);
+
+ for (x= ((int)(intptr)(&m)); m ; m--)
+ {
+ int i;
+ y= x;
+ for (i= 0; i < N_TLH; i++)
+ {
+ x= (x*(m+i)+0x87654321) & INT_MAX32;
+ z= (x<0) ? -x : x;
+ if (lf_hash_insert(&lf_hash, pins, &z))
+ {
+ sum+= z;
+ ins++;
+ }
+ }
+ for (i= 0; i < N_TLH; i++)
+ {
+ y= (y*(m+i)+0x87654321) & INT_MAX32;
+ z= (y<0) ? -y : y;
+ if (lf_hash_delete(&lf_hash, pins, (uchar *)&z, sizeof(z)))
+ sum-= z;
+ }
+ }
+ lf_hash_put_pins(pins);
+ my_atomic_rwlock_wrlock(&rwl);
+ my_atomic_add32(&a32, sum);
+ my_atomic_add32(&b32, ins);
+
+ if (my_atomic_add32(&N, -1) == 1)
+ {
+ diag("%d mallocs, %d pins in stack, %d hash size, %d inserts",
+ lf_hash.alloc.mallocs, lf_hash.alloc.pinbox.pins_in_stack,
+ lf_hash.size, b32);
+ a32|= lf_hash.count;
+ }
+ my_atomic_rwlock_wrunlock(&rwl);
+ pthread_mutex_lock(&mutex);
+ if (!--running_threads) pthread_cond_signal(&cond);
+ pthread_mutex_unlock(&mutex);
+ return 0;
+}
+#endif
+
void test_atomic(const char *test, pthread_handler handler, int n, int m)
{
pthread_t t;
- ulonglong now=my_getsystime();
+ ulonglong now= my_getsystime();
a32= 0;
b32= 0;
c32= 0;
diag("Testing %s with %d threads, %d iterations... ", test, n, m);
- for (N=n ; n ; n--)
+ for (running_threads= n ; n ; n--)
{
if (pthread_create(&t, &thr_attr, handler, &m) != 0)
{
diag("Could not create thread");
- a32= 1;
- goto err;
+ abort();
}
}
-
pthread_mutex_lock(&mutex);
- while (N)
+ while (running_threads)
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);
+ now= my_getsystime()-now;
+ ok(a32 == 0, "tested %s in %g secs (%d)", test, ((double)now)/1e7, a32);
}
+
int main()
{
int err;
- diag("N CPUs: %d", my_getncpus());
+ my_init();
+
+ diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE);
err= my_atomic_initialize();
plan(4);
@@ -172,26 +297,38 @@
pthread_mutex_init(&mutex, 0);
pthread_cond_init(&cond, 0);
my_atomic_rwlock_init(&rwl);
+#ifdef DISABLED
+ lf_alloc_init(&lf_allocator, sizeof(TLA), offsetof(TLA, not_used));
+ lf_hash_init(&lf_hash, sizeof(int), LF_HASH_UNIQUE, 0, sizeof(int), 0,
+ &my_charset_bin);
+#endif
-#ifdef HPUX11
-#define CYCLES 1000
+#ifdef MY_ATOMIC_MODE_RWLOCKS
+#define CYCLES 3000
#else
-#define CYCLES 10000
+#define CYCLES 300000
#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);
+ test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS,CYCLES);
+ test_atomic("my_atomic_fas32", test_atomic_fas_handler, THREADS,CYCLES);
+ test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS,CYCLES);
+#ifdef DISABLED
+ test_atomic("lf_pinbox", test_lf_pinbox, THREADS,CYCLES);
+ test_atomic("lf_alloc", test_lf_alloc, THREADS,CYCLES);
+ test_atomic("lf_hash", test_lf_hash, THREADS,CYCLES/10);
+
+ lf_hash_destroy(&lf_hash);
+ lf_alloc_destroy(&lf_allocator);
+#endif
+
+ /* workaround until we know why this includes dbug but not safemalloc */
+ if(err) { my_thread_global_init(); my_free(my_malloc(0, MYF(0)), MYF(0)); }
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&thr_attr);
my_atomic_rwlock_destroy(&rwl);
+ my_end(0);
return exit_status();
}
| Thread |
|---|
| • bk commit into 5.1 tree (guilhem:1.2579) | guilhem | 5 Jun |