mariadb/include/atomic/x86-gcc.h

146 lines
5.7 KiB
C
Raw Normal View History

#ifndef ATOMIC_X86_GCC_INCLUDED
#define ATOMIC_X86_GCC_INCLUDED
2011-06-30 17:46:53 +02:00
/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
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
Many files: Changed header to GPL version 2 only client/mysqlslap.c: Changed header to GPL version 2 only include/atomic/nolock.h: Changed header to GPL version 2 only include/atomic/rwlock.h: Changed header to GPL version 2 only include/atomic/x86-gcc.h: Changed header to GPL version 2 only include/atomic/x86-msvc.h: Changed header to GPL version 2 only include/my_atomic.h: Changed header to GPL version 2 only include/my_trie.h: Changed header to GPL version 2 only include/my_vle.h: Changed header to GPL version 2 only include/mysql/plugin.h: Changed header to GPL version 2 only mysys/my_atomic.c: Changed header to GPL version 2 only mysys/my_getncpus.c: Changed header to GPL version 2 only mysys/my_memmem.c: Changed header to GPL version 2 only mysys/my_vle.c: Changed header to GPL version 2 only mysys/trie.c: Changed header to GPL version 2 only plugin/Makefile.am: Changed header to GPL version 2 only server-tools/instance-manager/IMService.h: Changed header to GPL version 2 only server-tools/instance-manager/WindowsService.h: Changed header to GPL version 2 only server-tools/instance-manager/exit_codes.h: Changed header to GPL version 2 only server-tools/instance-manager/user_management_commands.h: Changed header to GPL version 2 only sql/authors.h: Changed header to GPL version 2 only sql/contributors.h: Changed header to GPL version 2 only sql/event_data_objects.cc: Changed header to GPL version 2 only sql/event_data_objects.h: Changed header to GPL version 2 only sql/event_db_repository.cc: Changed header to GPL version 2 only sql/event_db_repository.h: Changed header to GPL version 2 only sql/event_queue.cc: Changed header to GPL version 2 only sql/event_queue.h: Changed header to GPL version 2 only sql/event_scheduler.cc: Changed header to GPL version 2 only sql/event_scheduler.h: Changed header to GPL version 2 only sql/events.cc: Changed header to GPL version 2 only sql/events.h: Changed header to GPL version 2 only sql/ha_ndbcluster_binlog.cc: Changed header to GPL version 2 only sql/ha_ndbcluster_binlog.h: Changed header to GPL version 2 only sql/ha_ndbcluster_tables.h: Changed header to GPL version 2 only sql/ha_partition.cc: Changed header to GPL version 2 only sql/ha_partition.h: Changed header to GPL version 2 only sql/item_xmlfunc.cc: Changed header to GPL version 2 only sql/item_xmlfunc.h: Changed header to GPL version 2 only sql/log.h: Changed header to GPL version 2 only sql/partition_element.h: Changed header to GPL version 2 only sql/partition_info.cc: Changed header to GPL version 2 only sql/partition_info.h: Changed header to GPL version 2 only sql/rpl_filter.cc: Changed header to GPL version 2 only sql/rpl_filter.h: Changed header to GPL version 2 only sql/rpl_injector.cc: Changed header to GPL version 2 only sql/rpl_injector.h: Changed header to GPL version 2 only sql/rpl_mi.cc: Changed header to GPL version 2 only sql/rpl_mi.h: Changed header to GPL version 2 only sql/rpl_rli.cc: Changed header to GPL version 2 only sql/rpl_rli.h: Changed header to GPL version 2 only sql/rpl_tblmap.cc: Changed header to GPL version 2 only sql/rpl_tblmap.h: Changed header to GPL version 2 only sql/rpl_utility.cc: Changed header to GPL version 2 only sql/rpl_utility.h: Changed header to GPL version 2 only sql/sql_binlog.cc: Changed header to GPL version 2 only sql/sql_partition.cc: Changed header to GPL version 2 only sql/sql_partition.h: Changed header to GPL version 2 only sql/sql_plugin.cc: Changed header to GPL version 2 only sql/sql_plugin.h: Changed header to GPL version 2 only sql/sql_servers.cc: Changed header to GPL version 2 only sql/sql_servers.h: Changed header to GPL version 2 only sql/sql_tablespace.cc: Changed header to GPL version 2 only sql/sql_yacc.yy.bak: Changed header to GPL version 2 only storage/Makefile.am: Changed header to GPL version 2 only storage/archive/Makefile.am: Changed header to GPL version 2 only storage/blackhole/Makefile.am: Changed header to GPL version 2 only storage/csv/Makefile.am: Changed header to GPL version 2 only storage/example/Makefile.am: Changed header to GPL version 2 only storage/federated/Makefile.am: Changed header to GPL version 2 only storage/innobase/handler/Makefile.am: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/AllocNodeId.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateFilegroup.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateFilegroupImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/CreateObj.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DictObjOp.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DihFragCount.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropFilegroup.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropFilegroupImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/DropObj.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/Extent.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/LgmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/PgmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RestoreContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RestoreImpl.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/RouteOrd.hpp: Changed header to GPL version 2 only storage/ndb/include/kernel/signaldata/TsmanContinueB.hpp: Changed header to GPL version 2 only storage/ndb/include/ndbapi/NdbIndexStat.hpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/mgmapi_logevent/mgmapi_logevent.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/mgmapi_logevent_dual/mgmapi_logevent_dual.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_async/ndbapi_async.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_async1/ndbapi_async1.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_event/ndbapi_event.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_retries/ndbapi_retries.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple/ndbapi_simple.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple_dual/ndbapi_simple_dual.cpp: Changed header to GPL version 2 only storage/ndb/ndbapi-examples/ndbapi_simple_index/ndbapi_simple_index.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbdih/printSysfile.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/DbtupDiskAlloc.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/DbtupVarAlloc.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/Undo_buffer.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/tuppage.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtup/tuppage.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/dbtux/DbtuxStat.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/diskpage.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/lgman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/lgman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/pgman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/pgman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/print_file.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/record_types.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/restore.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/restore.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/tsman.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/blocks/tsman.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DLCFifoList.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DLCHashTable.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DynArr256.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/DynArr256.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/KeyTable2Ref.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/LinearPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/NdbdSuperPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/NdbdSuperPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Pool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Pool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/RWPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/RWPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/Rope.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/SLFifoList.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/WOPool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/WOPool.hpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/bench_pool.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/ndbd_malloc_impl.cpp: Changed header to GPL version 2 only storage/ndb/src/kernel/vm/ndbd_malloc_impl.hpp: Changed header to GPL version 2 only storage/ndb/src/mgmsrv/ParamInfo.cpp: Changed header to GPL version 2 only storage/ndb/src/ndbapi/NdbIndexStat.cpp: Changed header to GPL version 2 only storage/ndb/test/ndbapi/testIndexStat.cpp: Changed header to GPL version 2 only storage/ndb/test/tools/listen.cpp: Changed header to GPL version 2 only storage/ndb/tools/restore/ndb_nodegroup_map.h: Changed header to GPL version 2 only strings/my_strchr.c: Changed header to GPL version 2 only unittest/mysys/base64-t.c: Changed header to GPL version 2 only unittest/mysys/bitmap-t.c: Changed header to GPL version 2 only unittest/mysys/my_atomic-t.c: Changed header to GPL version 2 only unittest/mytap/tap.c: Changed header to GPL version 2 only unittest/mytap/tap.h: Changed header to GPL version 2 only win/Makefile.am: Changed header to GPL version 2 only
2006-12-27 02:23:51 +01:00
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
2011-06-30 17:46:53 +02:00
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
XXX 64-bit atomic operations can be implemented using
cmpxchg8b, if necessary. Though I've heard that not all 64-bit
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"
# else
# define MY_ATOMIC_MODE "gcc-amd64" LOCK_prefix
# endif
#else
# 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
unittest: rename *.t* to *-t* to be automake-friendly simplify Makefiles test_atomic.c: move to unittest, add GPL comment, fix warnings, convert to tap framework. configure: remove custom tests for available types, use AC_CHECK_TYPE instead x86-gcc.h: fix gcc -ansi errors while maintaining readability ignore: added *-t unittest/mysys/base64-t.c: Rename: unittest/mysys/base64.t.c -> unittest/mysys/base64-t.c unittest/mysys/bitmap-t.c: Rename: unittest/mysys/bitmap.t.c -> unittest/mysys/bitmap-t.c unittest/mytap/t/basic-t.c: Rename: unittest/mytap/t/basic.t.c -> unittest/mytap/t/basic-t.c unittest/examples/no_plan-t.c: Rename: unittest/examples/no_plan.t.c -> unittest/examples/no_plan-t.c unittest/examples/simple-t.c: Rename: unittest/examples/simple.t.c -> unittest/examples/simple-t.c unittest/examples/skip-t.c: Rename: unittest/examples/skip.t.c -> unittest/examples/skip-t.c unittest/examples/skip_all-t.c: Rename: unittest/examples/skip_all.t.c -> unittest/examples/skip_all-t.c unittest/examples/todo-t.c: Rename: unittest/examples/todo.t.c -> unittest/examples/todo-t.c BitKeeper/etc/ignore: added *-t config/ac-macros/misc.m4: remove custom AC_TRY_RUN tests for available types, use AC_CHECK_TYPE instead configure.in: remove custom tests for available types, use AC_CHECK_TYPE instead include/atomic/x86-gcc.h: fix gcc -ansi errors while maintaining readability include/my_global.h: remove custom tests for available types, use AC_CHECK_TYPE instead include/my_sys.h: add missing declaration mysys/Makefile.am: move test_atomic to unittest unittest/Makefile.am: simplifications, correct permissions in chmod unittest/README.txt: rename *.t* to *-t* to be automake-friendly unittest/examples/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/my_atomic-t.c: move mysys/test_atomic.c to unittest, add GPL comment, fix warnings, convert to tap framework. unittest/mytap/t/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/unit.pl: rename *.t* to *-t* to be automake-friendly
2006-06-01 12:25:47 +02:00
/* fix -ansi errors while maintaining readability */
#ifndef asm
unittest: rename *.t* to *-t* to be automake-friendly simplify Makefiles test_atomic.c: move to unittest, add GPL comment, fix warnings, convert to tap framework. configure: remove custom tests for available types, use AC_CHECK_TYPE instead x86-gcc.h: fix gcc -ansi errors while maintaining readability ignore: added *-t unittest/mysys/base64-t.c: Rename: unittest/mysys/base64.t.c -> unittest/mysys/base64-t.c unittest/mysys/bitmap-t.c: Rename: unittest/mysys/bitmap.t.c -> unittest/mysys/bitmap-t.c unittest/mytap/t/basic-t.c: Rename: unittest/mytap/t/basic.t.c -> unittest/mytap/t/basic-t.c unittest/examples/no_plan-t.c: Rename: unittest/examples/no_plan.t.c -> unittest/examples/no_plan-t.c unittest/examples/simple-t.c: Rename: unittest/examples/simple.t.c -> unittest/examples/simple-t.c unittest/examples/skip-t.c: Rename: unittest/examples/skip.t.c -> unittest/examples/skip-t.c unittest/examples/skip_all-t.c: Rename: unittest/examples/skip_all.t.c -> unittest/examples/skip_all-t.c unittest/examples/todo-t.c: Rename: unittest/examples/todo.t.c -> unittest/examples/todo-t.c BitKeeper/etc/ignore: added *-t config/ac-macros/misc.m4: remove custom AC_TRY_RUN tests for available types, use AC_CHECK_TYPE instead configure.in: remove custom tests for available types, use AC_CHECK_TYPE instead include/atomic/x86-gcc.h: fix gcc -ansi errors while maintaining readability include/my_global.h: remove custom tests for available types, use AC_CHECK_TYPE instead include/my_sys.h: add missing declaration mysys/Makefile.am: move test_atomic to unittest unittest/Makefile.am: simplifications, correct permissions in chmod unittest/README.txt: rename *.t* to *-t* to be automake-friendly unittest/examples/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/my_atomic-t.c: move mysys/test_atomic.c to unittest, add GPL comment, fix warnings, convert to tap framework. unittest/mytap/t/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/unit.pl: rename *.t* to *-t* to be automake-friendly
2006-06-01 12:25:47 +02:00
#define asm __asm__
#endif
unittest: rename *.t* to *-t* to be automake-friendly simplify Makefiles test_atomic.c: move to unittest, add GPL comment, fix warnings, convert to tap framework. configure: remove custom tests for available types, use AC_CHECK_TYPE instead x86-gcc.h: fix gcc -ansi errors while maintaining readability ignore: added *-t unittest/mysys/base64-t.c: Rename: unittest/mysys/base64.t.c -> unittest/mysys/base64-t.c unittest/mysys/bitmap-t.c: Rename: unittest/mysys/bitmap.t.c -> unittest/mysys/bitmap-t.c unittest/mytap/t/basic-t.c: Rename: unittest/mytap/t/basic.t.c -> unittest/mytap/t/basic-t.c unittest/examples/no_plan-t.c: Rename: unittest/examples/no_plan.t.c -> unittest/examples/no_plan-t.c unittest/examples/simple-t.c: Rename: unittest/examples/simple.t.c -> unittest/examples/simple-t.c unittest/examples/skip-t.c: Rename: unittest/examples/skip.t.c -> unittest/examples/skip-t.c unittest/examples/skip_all-t.c: Rename: unittest/examples/skip_all.t.c -> unittest/examples/skip_all-t.c unittest/examples/todo-t.c: Rename: unittest/examples/todo.t.c -> unittest/examples/todo-t.c BitKeeper/etc/ignore: added *-t config/ac-macros/misc.m4: remove custom AC_TRY_RUN tests for available types, use AC_CHECK_TYPE instead configure.in: remove custom tests for available types, use AC_CHECK_TYPE instead include/atomic/x86-gcc.h: fix gcc -ansi errors while maintaining readability include/my_global.h: remove custom tests for available types, use AC_CHECK_TYPE instead include/my_sys.h: add missing declaration mysys/Makefile.am: move test_atomic to unittest unittest/Makefile.am: simplifications, correct permissions in chmod unittest/README.txt: rename *.t* to *-t* to be automake-friendly unittest/examples/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/mysys/my_atomic-t.c: move mysys/test_atomic.c to unittest, add GPL comment, fix warnings, convert to tap framework. unittest/mytap/t/Makefile.am: rename *.t* to *-t* to be automake-friendly simplify Makefile unittest/unit.pl: rename *.t* to *-t* to be automake-friendly
2006-06-01 12:25:47 +02:00
#ifndef MY_ATOMIC_NO_XADD
#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_add_body32 \
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
asm volatile (LOCK_prefix "; xadd %0, %1;" \
: "+r" (v), "=m" (*a) \
: "m" (*a) \
: "memory")
#define make_atomic_cas_body32 \
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
__typeof__(*cmp) sav; \
asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
: "=m" (*a), "=a" (sav), "=q" (ret) \
: "r" (set), "m" (*a), "a" (*cmp) \
: "memory"); \
if (!ret) \
*cmp= sav
#ifdef __x86_64__
#define make_atomic_add_body64 make_atomic_add_body32
#define make_atomic_cas_body64 make_atomic_cas_body32
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
#define make_atomic_fas_body(S) \
asm volatile ("xchg %0, %1;" \
: "+r" (v), "=m" (*a) \
: "m" (*a) \
: "memory")
/*
Actually 32/64-bit reads/writes are always atomic on x86_64,
nonetheless issue memory barriers as appropriate.
*/
#define make_atomic_load_body(S) \
/* Serialize prior load and store operations. */ \
asm volatile ("mfence" ::: "memory"); \
ret= *a; \
/* Prevent compiler from reordering instructions. */ \
asm volatile ("" ::: "memory")
#define make_atomic_store_body(S) \
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
asm volatile ("; xchg %0, %1;" \
: "=m" (*a), "+r" (v) \
: "m" (*a) \
: "memory")
#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
Bug#52419: x86 assembly based atomic CAS causes test failures The problem was that the x86 assembly based atomic CAS (compare and swap) implementation could copy the wrong value to the ebx register, where the cmpxchg8b expects to see part of the "comparand" value. Since the original value in the ebx register is saved in the stack (that is, the push instruction causes the stack pointer to change), a wrong offset could be used if the compiler decides to put the source of the comparand value in the stack. The solution is to copy the comparand value directly from memory. Since the comparand value is 64-bits wide, it is copied in two steps over to the ebx and ecx registers. include/atomic/x86-gcc.h: For reference, an excerpt from a faulty binary follows. It is a disassembly of my_atomic-t, compiled at -O3 with ICC 11.0. Most of the code deals with preparations for a atomic cmpxchg8b operation. This instruction compares the value in edx:eax with the destination operand. If the values are equal, the value in ecx:ebx is stored in the destination, otherwise the value in the destination operand is copied into edx:eax. In this case, my_atomic_add64 is implemented as a compare and exchange. The addition is done over temporary storage and loaded into the destination if the original term value is still valid. volatile int64 a64; int64 b=0x1000200030004000LL; a64=0; mov 0xfffffda8(%ebx),%eax xor %ebp,%ebp mov %ebp,(%eax) mov %ebp,0x4(%eax) my_atomic_add64(&a64, b); mov 0xfffffda8(%ebx),%ebp # Load address of a64 mov 0x0(%ebp),%edx # Copy value mov 0x4(%ebp),%ecx mov %edx,0xc(%esp) # Assign to tmp var in the stack mov %ecx,0x10(%esp) add $0x30004000,%edx # Sum values adc $0x10002000,%ecx mov %edx,0x8(%esp) # Save part of result for later mov 0x0(%ebp),%esi # Copy value of a64 again mov 0x4(%ebp),%edi mov 0xc(%esp),%eax # Load the value of a64 used mov 0x10(%esp),%edx # for comparison mov %esi,(%esp) mov %edi,0x4(%esp) push %ebx # Push %ebx into stack. Changes esp. mov 0x8(%esp),%ebx # Wrong restore of the result. lock cmpxchg8b 0x0(%ebp) sete %cl pop %ebx
2010-09-17 22:34:15 +02:00
PIC code, to avoid this we push ebx and pop ebx. The new value
is copied directly from memory to avoid problems with a implicit
manipulation of the stack pointer by the push.
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.
*/
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
#define make_atomic_cas_body64 \
Bug#52419: x86 assembly based atomic CAS causes test failures The problem was that the x86 assembly based atomic CAS (compare and swap) implementation could copy the wrong value to the ebx register, where the cmpxchg8b expects to see part of the "comparand" value. Since the original value in the ebx register is saved in the stack (that is, the push instruction causes the stack pointer to change), a wrong offset could be used if the compiler decides to put the source of the comparand value in the stack. The solution is to copy the comparand value directly from memory. Since the comparand value is 64-bits wide, it is copied in two steps over to the ebx and ecx registers. include/atomic/x86-gcc.h: For reference, an excerpt from a faulty binary follows. It is a disassembly of my_atomic-t, compiled at -O3 with ICC 11.0. Most of the code deals with preparations for a atomic cmpxchg8b operation. This instruction compares the value in edx:eax with the destination operand. If the values are equal, the value in ecx:ebx is stored in the destination, otherwise the value in the destination operand is copied into edx:eax. In this case, my_atomic_add64 is implemented as a compare and exchange. The addition is done over temporary storage and loaded into the destination if the original term value is still valid. volatile int64 a64; int64 b=0x1000200030004000LL; a64=0; mov 0xfffffda8(%ebx),%eax xor %ebp,%ebp mov %ebp,(%eax) mov %ebp,0x4(%eax) my_atomic_add64(&a64, b); mov 0xfffffda8(%ebx),%ebp # Load address of a64 mov 0x0(%ebp),%edx # Copy value mov 0x4(%ebp),%ecx mov %edx,0xc(%esp) # Assign to tmp var in the stack mov %ecx,0x10(%esp) add $0x30004000,%edx # Sum values adc $0x10002000,%ecx mov %edx,0x8(%esp) # Save part of result for later mov 0x0(%ebp),%esi # Copy value of a64 again mov 0x4(%ebp),%edi mov 0xc(%esp),%eax # Load the value of a64 used mov 0x10(%esp),%edx # for comparison mov %esi,(%esp) mov %edi,0x4(%esp) push %ebx # Push %ebx into stack. Changes esp. mov 0x8(%esp),%ebx # Wrong restore of the result. lock cmpxchg8b 0x0(%ebp) sete %cl pop %ebx
2010-09-17 22:34:15 +02:00
asm volatile ("push %%ebx;" \
"movl (%%ecx), %%ebx;" \
"movl 4(%%ecx), %%ecx;" \
LOCK_prefix "; cmpxchg8b (%%esi);" \
Bug#52419: x86 assembly based atomic CAS causes test failures The problem was that the x86 assembly based atomic CAS (compare and swap) implementation could copy the wrong value to the ebx register, where the cmpxchg8b expects to see part of the "comparand" value. Since the original value in the ebx register is saved in the stack (that is, the push instruction causes the stack pointer to change), a wrong offset could be used if the compiler decides to put the source of the comparand value in the stack. The solution is to copy the comparand value directly from memory. Since the comparand value is 64-bits wide, it is copied in two steps over to the ebx and ecx registers. include/atomic/x86-gcc.h: For reference, an excerpt from a faulty binary follows. It is a disassembly of my_atomic-t, compiled at -O3 with ICC 11.0. Most of the code deals with preparations for a atomic cmpxchg8b operation. This instruction compares the value in edx:eax with the destination operand. If the values are equal, the value in ecx:ebx is stored in the destination, otherwise the value in the destination operand is copied into edx:eax. In this case, my_atomic_add64 is implemented as a compare and exchange. The addition is done over temporary storage and loaded into the destination if the original term value is still valid. volatile int64 a64; int64 b=0x1000200030004000LL; a64=0; mov 0xfffffda8(%ebx),%eax xor %ebp,%ebp mov %ebp,(%eax) mov %ebp,0x4(%eax) my_atomic_add64(&a64, b); mov 0xfffffda8(%ebx),%ebp # Load address of a64 mov 0x0(%ebp),%edx # Copy value mov 0x4(%ebp),%ecx mov %edx,0xc(%esp) # Assign to tmp var in the stack mov %ecx,0x10(%esp) add $0x30004000,%edx # Sum values adc $0x10002000,%ecx mov %edx,0x8(%esp) # Save part of result for later mov 0x0(%ebp),%esi # Copy value of a64 again mov 0x4(%ebp),%edi mov 0xc(%esp),%eax # Load the value of a64 used mov 0x10(%esp),%edx # for comparison mov %esi,(%esp) mov %edi,0x4(%esp) push %ebx # Push %ebx into stack. Changes esp. mov 0x8(%esp),%ebx # Wrong restore of the result. lock cmpxchg8b 0x0(%ebp) sete %cl pop %ebx
2010-09-17 22:34:15 +02:00
"setz %2; pop %%ebx" \
: "+S" (a), "+A" (*cmp), "=c" (ret) \
: "c" (&set) \
Bug#22320: my_atomic-t unit test fails Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
2010-07-23 14:37:10 +02:00
: "memory", "esp")
#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 */