├── .gitignore ├── CMakeLists.txt ├── README.md ├── build ├── borland │ ├── README │ └── build.bat ├── digitalmars │ └── build.bat ├── intel │ └── build.sh ├── tcc │ └── build.bat ├── vc10 │ ├── c89atomic.sln │ └── c89atomic_basic │ │ ├── c89atomic_basic.vcxproj │ │ └── c89atomic_basic.vcxproj.filters ├── vc6 │ ├── c89atomic.dsw │ └── c89atomic_basic │ │ └── c89atomic_basic.dsp ├── vc8 │ ├── c89atomic.sln │ └── c89atomic_basic │ │ └── c89atomic_basic.vcproj └── watcom │ └── build.bat ├── c89atomic.c ├── c89atomic.h ├── tests └── c89atomic_basic.c └── x64 └── c89atomic.x64.win64.nasm /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | /#docs 3 | /build/cmake 4 | 5 | /build/borland/* 6 | !/build/borland/build.bat 7 | !/build/borland/README 8 | 9 | /build/digitalmars/* 10 | !/build/digitalmars/build.bat 11 | 12 | /build/intel/* 13 | !/build/intel/build.sh 14 | 15 | /build/nasm/* 16 | #!/build/nasm/build.bat 17 | 18 | /build/tcc/* 19 | !/build/tcc/build.bat 20 | 21 | /build/vc6/* 22 | !/build/vc6/c89atomic.dsw 23 | !/build/vc6/c89atomic_basic/c89atomic_basic.dsp 24 | 25 | /build/vc8/* 26 | !/build/vc8/c89atomic.sln 27 | !/build/vc8/c89atomic_basic/c89atomic_basic.vcproj 28 | 29 | /build/vc10/* 30 | !/build/vc10/c89atomic.sln 31 | !/build/vc10/c89atomic_basic/c89atomic_basic.vcproj 32 | 33 | /build/watcom/* 34 | !/build/watcom/build.bat 35 | 36 | 37 | /tests/bin 38 | *.exe 39 | a.out 40 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(c89atomic VERSION 1.0) 3 | 4 | # Options 5 | option(C89ATOMIC_BUILD_EXAMPLES "Build c89atomic examples" OFF) 6 | option(C89ATOMIC_BUILD_TESTS "Build c89atomic tests" OFF) 7 | option(C89ATOMIC_BUILD_TOOLS "Build c89atomic tools" OFF) 8 | option(C89ATOMIC_FORCE_CXX "Force compilation as C++" OFF) 9 | option(C89ATOMIC_FORCE_C89 "Force compilation as C89" OFF) 10 | 11 | # Construct compiler options. 12 | set(COMPILE_OPTIONS) 13 | 14 | if(C89ATOMIC_FORCE_CXX AND C89ATOMIC_FORCE_C89) 15 | message(FATAL_ERROR "C89ATOMIC_FORCE_CXX and C89ATOMIC_FORCE_C89 cannot be enabled at the same time.") 16 | endif() 17 | 18 | if(C89ATOMIC_FORCE_CXX) 19 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 20 | message(STATUS "Compiling as C++ (GNU/Clang)") 21 | list(APPEND COMPILE_OPTIONS -x c++) 22 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 23 | message(STATUS "Compiling as C++ (MSVC)") 24 | list(APPEND COMPILE_OPTIONS /TP) 25 | else() 26 | message(WARNING "C89ATOMIC_FORCE_CXX is enabled but the compiler does not support it. Ignoring.") 27 | endif() 28 | endif() 29 | 30 | if(C89ATOMIC_FORCE_C89) 31 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 32 | message(STATUS "Compiling as C89") 33 | list(APPEND COMPILE_OPTIONS -std=c89) 34 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 35 | message(WARNING "MSVC does not support forcing C89. C89ATOMIC_FORCE_C89 ignored.") 36 | else() 37 | message(WARNING "C89ATOMIC_FORCE_C89 is enabled but the compiler does not support it. Ignoring.") 38 | endif() 39 | endif() 40 | 41 | # Warnings 42 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") 43 | list(APPEND COMPILE_OPTIONS -Wall -Wextra -pedantic) 44 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 45 | #list(APPEND COMPILE_OPTIONS /W4) 46 | endif() 47 | 48 | 49 | # Construct compiler defines 50 | set(COMPILE_DEFINES) 51 | 52 | 53 | # Link libraries 54 | set(COMMON_LIBRARIES) 55 | set(COMMON_INCLUDE_DIRS) 56 | 57 | 58 | # Common interface 59 | add_library(c89atomic_common INTERFACE) 60 | target_compile_options (c89atomic_common INTERFACE ${COMPILE_OPTIONS}) 61 | target_link_libraries (c89atomic_common INTERFACE ${COMMON_LIBRARIES}) 62 | target_include_directories(c89atomic_common INTERFACE ${COMMON_INCLUDE_DIRS}) 63 | target_compile_definitions(c89atomic_common INTERFACE ${COMPILE_DEFINES}) 64 | 65 | 66 | # Main library 67 | add_library(c89atomic STATIC 68 | c89atomic.c 69 | c89atomic.h 70 | ) 71 | 72 | target_include_directories(c89atomic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 73 | target_link_libraries (c89atomic PRIVATE c89atomic_common) 74 | 75 | 76 | # Tests 77 | if(C89ATOMIC_BUILD_TESTS) 78 | enable_testing() 79 | 80 | add_executable(c89atomic_basic tests/c89atomic_basic.c) 81 | target_link_libraries(c89atomic_basic PRIVATE c89atomic) 82 | add_test(NAME c89atomic_basic COMMAND c89atomic_basic) 83 | 84 | # sandbox. Don't add a test for this. 85 | #add_executable(c89atomic_sandbox tests/c89atomic_sandbox.c) 86 | #target_link_libraries(c89atomic_sandbox PRIVATE c89atomic) 87 | endif() 88 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

C89 compatible atomics.

2 | 3 |

4 | discord 5 |

6 | 7 | This library aims to implement an equivalent to the C11 atomics library. It's intended to be used as a way to 8 | enable the use of atomics in a mostly consistent manner to modern C, while still enabling compatibility with 9 | older compilers. This is *not* a drop-in replacement for C11 atomics, but is very similar. Only limited testing 10 | has been done so use at your own risk. I'm happy to accept feedback and pull requests with bug fixes. 11 | 12 | The following compilers are supported: 13 | 14 | - Visual Studio from VC6 (Earlier versions may work, but are untested.) 15 | - GCC starting from 2.7 (Earlier versions lack support for extended inline assembly.) 16 | - Clang 17 | - Intel oneAPI (Tested with 2025.0.4. Intel C++ Compiler Classic has not been tested.) 18 | - TinyCC/TCC (Tested with 0.9.27) 19 | - OpenWatcom (Tested with 2.0) 20 | - Digital Mars 21 | - Borland C++ (Tested with 5.02) 22 | 23 | New compilers will use intrinsics. GCC-likes, such as GCC and Clang, will use `__atomic_*` intrinsics through a 24 | pre-processor define and should have no overhead. This uses `__GNUC__` to detect GCC-likes. 25 | 26 | Old compilers, or compilers lacking support for intrinsics, will use inlined assembly. There are two inlined 27 | assembly paths: GCC-style (GAS syntax) and MSVC-style. For an old compiler to be supported, it must support one 28 | of these two paths. Note that only 32- and 64-bit x86 is supported for inlined assembly. I have not thouroughly 29 | tested the inlined assembly paths. It passes basics tests, but things like memory ordering may have some issues. 30 | Advice welcome on how to improve this. 31 | 32 | 33 | Usage 34 | ----- 35 | In most cases you can use this as a header-only library. Just add `c89atomic.h` to your source tree and 36 | include it: 37 | 38 | ```c 39 | #include "c89atomic.h" 40 | ``` 41 | 42 | Everything is implemented with defines and inline functions. In some cases there may not be native hardware 43 | support for a given atomic operation in which case the library will emulate it with a global spinlock. If 44 | you get errors about `c89atomic_global_lock` being undefined, you need to integrate c89atomic.c into your 45 | build. This will not usually be required on modern compilers. 46 | 47 | 48 | Differences With C11 49 | -------------------- 50 | For practicality, this is not a drop-in replacement for C11's `stdatomic.h`. Below are the main differences 51 | between c89atomic and stdatomic. 52 | 53 | * All operations require an explicit size which is specified by the name of the function, and only 8-, 54 | 16-, 32- and 64-bit operations are supported. Objects of arbitrary sizes are not supported. 55 | * All APIs are namespaced with `c89`. 56 | * `c89atomic_*` data types are undecorated (there is no `_Atomic` decoration). 57 | 58 | 59 | Types and Functions 60 | ------------------- 61 | The following types and functions are implemented: 62 | ``` 63 | +-----------------------------------------+-----------------------------------------------+ 64 | | C11 Atomics | C89 Atomics | 65 | +-----------------------------------------+-----------------------------------------------+ 66 | | #include | #include "c89atomic.h" | 67 | +-----------------------------------------+-----------------------------------------------+ 68 | | memory_order | c89atomic_memory_order | 69 | | memory_order_relaxed | c89atomic_memory_order_relaxed | 70 | | memory_order_consume | c89atomic_memory_order_consume | 71 | | memory_order_acquire | c89atomic_memory_order_acquire | 72 | | memory_order_release | c89atomic_memory_order_release | 73 | | memory_order_acq_rel | c89atomic_memory_order_acq_rel | 74 | | memory_order_seq_cst | c89atomic_memory_order_seq_cst | 75 | +-----------------------------------------+-----------------------------------------------+ 76 | | atomic_flag | c89atomic_flag | 77 | | atomic_bool | c89atomic_bool | 78 | | atomic_int8 | c89atomic_int8 | 79 | | atomic_uint8 | c89atomic_uint8 | 80 | | atomic_int16 | c89atomic_int16 | 81 | | atomic_uint16 | c89atomic_uint16 | 82 | | atomic_int32 | c89atomic_int32 | 83 | | atomic_uint32 | c89atomic_uint32 | 84 | | atomic_int64 | c89atomic_int64 | 85 | | atomic_uint64 | c89atomic_uint64 | 86 | +-----------------------------------------+-----------------------------------------------+ 87 | | atomic_flag_test_and_set | c89atomic_flag_test_and_set | 88 | | atomic_flag_test_and_set_explicit | c89atomic_flag_test_and_set_explicit | 89 | +-----------------------------------------+-----------------------------------------------+ 90 | | atomic_flag_clear | c89atomic_flag_clear | 91 | | atomic_flag_clear_explicit | c89atomic_flag_clear_explicit | 92 | +-----------------------------------------+-----------------------------------------------+ 93 | | atomic_store | c89atomic_store_8 | 94 | | atomic_store_explicit | c89atomic_store_16 | 95 | | | c89atomic_store_32 | 96 | | | c89atomic_store_64 | 97 | | | c89atomic_store_explicit_8 | 98 | | | c89atomic_store_explicit_16 | 99 | | | c89atomic_store_explicit_32 | 100 | | | c89atomic_store_explicit_64 | 101 | +-----------------------------------------+-----------------------------------------------+ 102 | | atomic_load | c89atomic_load_8 | 103 | | atomic_load_explicit | c89atomic_load_16 | 104 | | | c89atomic_load_32 | 105 | | | c89atomic_load_64 | 106 | | | c89atomic_load_explicit_8 | 107 | | | c89atomic_load_explicit_16 | 108 | | | c89atomic_load_explicit_32 | 109 | | | c89atomic_load_explicit_64 | 110 | +-----------------------------------------+-----------------------------------------------+ 111 | | atomic_exchange | c89atomic_exchange_8 | 112 | | atomic_exchange_explicit | c89atomic_exchange_16 | 113 | | | c89atomic_exchange_32 | 114 | | | c89atomic_exchange_64 | 115 | | | c89atomic_exchange_explicit_8 | 116 | | | c89atomic_exchange_explicit_16 | 117 | | | c89atomic_exchange_explicit_32 | 118 | | | c89atomic_exchange_explicit_64 | 119 | +-----------------------------------------+-----------------------------------------------+ 120 | | atomic_compare_exchange_weak | c89atomic_compare_exchange_weak_8 | 121 | | atomic_compare_exchange_weak_explicit | c89atomic_compare_exchange_weak_16 | 122 | | atomic_compare_exchange_strong | c89atomic_compare_exchange_weak_32 | 123 | | atomic_compare_exchange_strong_explicit | c89atomic_compare_exchange_weak_64 | 124 | | | c89atomic_compare_exchange_weak_explicit_8 | 125 | | | c89atomic_compare_exchange_weak_explicit_16 | 126 | | | c89atomic_compare_exchange_weak_explicit_32 | 127 | | | c89atomic_compare_exchange_weak_explicit_64 | 128 | | | c89atomic_compare_exchange_strong_8 | 129 | | | c89atomic_compare_exchange_strong_16 | 130 | | | c89atomic_compare_exchange_strong_32 | 131 | | | c89atomic_compare_exchange_strong_64 | 132 | | | c89atomic_compare_exchange_strong_explicit_8 | 133 | | | c89atomic_compare_exchange_strong_explicit_16 | 134 | | | c89atomic_compare_exchange_strong_explicit_32 | 135 | | | c89atomic_compare_exchange_strong_explicit_64 | 136 | +-----------------------------------------+-----------------------------------------------+ 137 | | atomic_fetch_add | c89atomic_fetch_add_8 | 138 | | atomic_fetch_add_explicit | c89atomic_fetch_add_16 | 139 | | | c89atomic_fetch_add_32 | 140 | | | c89atomic_fetch_add_64 | 141 | | | c89atomic_fetch_add_explicit_8 | 142 | | | c89atomic_fetch_add_explicit_16 | 143 | | | c89atomic_fetch_add_explicit_32 | 144 | | | c89atomic_fetch_add_explicit_64 | 145 | +-----------------------------------------+-----------------------------------------------+ 146 | | atomic_fetch_sub | c89atomic_fetch_sub_8 | 147 | | atomic_fetch_sub_explicit | c89atomic_fetch_sub_16 | 148 | | | c89atomic_fetch_sub_32 | 149 | | | c89atomic_fetch_sub_64 | 150 | | | c89atomic_fetch_sub_explicit_8 | 151 | | | c89atomic_fetch_sub_explicit_16 | 152 | | | c89atomic_fetch_sub_explicit_32 | 153 | | | c89atomic_fetch_sub_explicit_64 | 154 | +-----------------------------------------+-----------------------------------------------+ 155 | | atomic_fetch_or | c89atomic_fetch_or_8 | 156 | | atomic_fetch_or_explicit | c89atomic_fetch_or_16 | 157 | | | c89atomic_fetch_or_32 | 158 | | | c89atomic_fetch_or_64 | 159 | | | c89atomic_fetch_or_explicit_8 | 160 | | | c89atomic_fetch_or_explicit_16 | 161 | | | c89atomic_fetch_or_explicit_32 | 162 | | | c89atomic_fetch_or_explicit_64 | 163 | +-----------------------------------------+-----------------------------------------------+ 164 | | atomic_fetch_xor | c89atomic_fetch_xor_8 | 165 | | atomic_fetch_xor_explicit | c89atomic_fetch_xor_16 | 166 | | | c89atomic_fetch_xor_32 | 167 | | | c89atomic_fetch_xor_64 | 168 | | | c89atomic_fetch_xor_explicit_8 | 169 | | | c89atomic_fetch_xor_explicit_16 | 170 | | | c89atomic_fetch_xor_explicit_32 | 171 | | | c89atomic_fetch_xor_explicit_64 | 172 | +-----------------------------------------+-----------------------------------------------+ 173 | | atomic_fetch_and | c89atomic_fetch_and_8 | 174 | | atomic_fetch_and_explicit | c89atomic_fetch_and_16 | 175 | | | c89atomic_fetch_and_32 | 176 | | | c89atomic_fetch_and_64 | 177 | | | c89atomic_fetch_and_explicit_8 | 178 | | | c89atomic_fetch_and_explicit_16 | 179 | | | c89atomic_fetch_and_explicit_32 | 180 | | | c89atomic_fetch_and_explicit_64 | 181 | +-----------------------------------------+-----------------------------------------------+ 182 | | atomic_thread_fence() | c89atomic_thread_fence | 183 | | atomic_signal_fence() | c89atomic_signal_fence | 184 | +-----------------------------------------+-----------------------------------------------+ 185 | | atomic_is_lock_free | c89atomic_is_lock_free_8 | 186 | | | c89atomic_is_lock_free_16 | 187 | | | c89atomic_is_lock_free_32 | 188 | | | c89atomic_is_lock_free_64 | 189 | +-----------------------------------------+-----------------------------------------------+ 190 | | (Not Defined) | c89atomic_compare_and_swap_8 | 191 | | | c89atomic_compare_and_swap_16 | 192 | | | c89atomic_compare_and_swap_32 | 193 | | | c89atomic_compare_and_swap_64 | 194 | | | c89atomic_compare_and_swap_ptr | 195 | +-----------------------------------------+-----------------------------------------------+ 196 | ``` -------------------------------------------------------------------------------- /build/borland/README: -------------------------------------------------------------------------------- 1 | I was able to get this compiling with Borland C++ 5.02, but only through the command line. When 2 | compiling from the IDE I get an "Out of hash space" error. 3 | 4 | You will need to install Turbo Assembler 5.0 (TASM). To do this, just download the ZIP archive 5 | from here: 6 | 7 | https://github.com/qb40/tasm/releases/tag/1.0.0 8 | 9 | Then just unzip that somewhere and add the "BIN" folder to your path environment variable. 10 | 11 | Borland C++ doesn't handle relative include paths like other compilers. It tries loading files 12 | relative to the current working directory rather than relative to the current file. To work around 13 | this you need to use the "-I" compiler switch. See build.bat in this directory for an example. 14 | 15 | The build.bat file can be used to make it easy to compile the test program and to also act as a 16 | reference. To use it, change into this directory and run it. 17 | 18 | PSA: If you're curious about playing with Borland C++ 5.02, be aware that for me the installer 19 | decided to just clear out my PATH environment variable. That's fun. Take a copy of your PATH if you 20 | decide to run the installer. 21 | -------------------------------------------------------------------------------- /build/borland/build.bat: -------------------------------------------------------------------------------- 1 | :: This script assumes you are compiling from this directory. The "-I" part needs to come 2 | :: before the source file. 3 | :: 4 | :: Borland is very annoying because it doesn't handle relative include paths properly. From 5 | :: what I can tell, it looks like it only considers the current directory and paths explicitly 6 | :: added to the command line via the "-I" switch. 7 | :: 8 | :: This script has been built with the assumption that it'll be run from this directory. If 9 | :: you want to compile from another directory you'll need to adjust the "-I" parts. 10 | :: 11 | :: The `-I"../../"` switch is to add the root directory to the include search paths. This is 12 | :: required for doing `#include "c89atomic.h"`. 13 | :: 14 | :: The `-I"../"` switch is to allow tests/c89atomic_basic.c to do `#include "../c89atomic.c"`. 15 | 16 | bcc32 -I"../../" -I"../" ../../tests/c89atomic_basic.c -------------------------------------------------------------------------------- /build/digitalmars/build.bat: -------------------------------------------------------------------------------- 1 | dmc ../../tests/c89atomic_basic.c -------------------------------------------------------------------------------- /build/intel/build.sh: -------------------------------------------------------------------------------- 1 | source /opt/intel/oneapi/setvars.sh > /dev/null 2 | icx ../../tests/c89atomic_basic.c -------------------------------------------------------------------------------- /build/tcc/build.bat: -------------------------------------------------------------------------------- 1 | tcc ../../tests/c89atomic_basic.c -Wall -------------------------------------------------------------------------------- /build/vc10/c89atomic.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual C++ Express 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "c89atomic_basic", "c89atomic_basic\c89atomic_basic.vcxproj", "{E240D631-1D94-4B78-B3C3-BD9B9CDF138A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {E240D631-1D94-4B78-B3C3-BD9B9CDF138A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {E240D631-1D94-4B78-B3C3-BD9B9CDF138A}.Debug|Win32.Build.0 = Debug|Win32 14 | {E240D631-1D94-4B78-B3C3-BD9B9CDF138A}.Release|Win32.ActiveCfg = Release|Win32 15 | {E240D631-1D94-4B78-B3C3-BD9B9CDF138A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /build/vc10/c89atomic_basic/c89atomic_basic.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {E240D631-1D94-4B78-B3C3-BD9B9CDF138A} 15 | c89atomic_basic 16 | 17 | 18 | 19 | Application 20 | true 21 | MultiByte 22 | 23 | 24 | Application 25 | false 26 | true 27 | MultiByte 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Level3 43 | Disabled 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | Level3 52 | MaxSpeed 53 | true 54 | true 55 | 56 | 57 | true 58 | true 59 | true 60 | 61 | 62 | 63 | 64 | true 65 | true 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /build/vc10/c89atomic_basic/c89atomic_basic.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | -------------------------------------------------------------------------------- /build/vc6/c89atomic.dsw: -------------------------------------------------------------------------------- 1 | Microsoft Developer Studio Workspace File, Format Version 6.00 2 | # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! 3 | 4 | ############################################################################### 5 | 6 | Project: "c89atomic_basic"=.\c89atomic_basic\c89atomic_basic.dsp - Package Owner=<4> 7 | 8 | Package=<5> 9 | {{{ 10 | }}} 11 | 12 | Package=<4> 13 | {{{ 14 | }}} 15 | 16 | ############################################################################### 17 | 18 | Global: 19 | 20 | Package=<5> 21 | {{{ 22 | }}} 23 | 24 | Package=<3> 25 | {{{ 26 | }}} 27 | 28 | ############################################################################### 29 | 30 | -------------------------------------------------------------------------------- /build/vc6/c89atomic_basic/c89atomic_basic.dsp: -------------------------------------------------------------------------------- 1 | # Microsoft Developer Studio Project File - Name="c89atomic_basic" - Package Owner=<4> 2 | # Microsoft Developer Studio Generated Build File, Format Version 6.00 3 | # ** DO NOT EDIT ** 4 | 5 | # TARGTYPE "Win32 (x86) Console Application" 0x0103 6 | 7 | CFG=c89atomic_basic - Win32 Debug 8 | !MESSAGE This is not a valid makefile. To build this project using NMAKE, 9 | !MESSAGE use the Export Makefile command and run 10 | !MESSAGE 11 | !MESSAGE NMAKE /f "c89atomic_basic.mak". 12 | !MESSAGE 13 | !MESSAGE You can specify a configuration when running NMAKE 14 | !MESSAGE by defining the macro CFG on the command line. For example: 15 | !MESSAGE 16 | !MESSAGE NMAKE /f "c89atomic_basic.mak" CFG="c89atomic_basic - Win32 Debug" 17 | !MESSAGE 18 | !MESSAGE Possible choices for configuration are: 19 | !MESSAGE 20 | !MESSAGE "c89atomic_basic - Win32 Release" (based on "Win32 (x86) Console Application") 21 | !MESSAGE "c89atomic_basic - Win32 Debug" (based on "Win32 (x86) Console Application") 22 | !MESSAGE 23 | 24 | # Begin Project 25 | # PROP AllowPerConfigDependencies 0 26 | # PROP Scc_ProjName "" 27 | # PROP Scc_LocalPath "" 28 | CPP=cl.exe 29 | RSC=rc.exe 30 | 31 | !IF "$(CFG)" == "c89atomic_basic - Win32 Release" 32 | 33 | # PROP BASE Use_MFC 0 34 | # PROP BASE Use_Debug_Libraries 0 35 | # PROP BASE Output_Dir "Release" 36 | # PROP BASE Intermediate_Dir "Release" 37 | # PROP BASE Target_Dir "" 38 | # PROP Use_MFC 0 39 | # PROP Use_Debug_Libraries 0 40 | # PROP Output_Dir "Release" 41 | # PROP Intermediate_Dir "Release" 42 | # PROP Target_Dir "" 43 | # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c 44 | # ADD CPP /nologo /W4 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /c 45 | # ADD BASE RSC /l 0x409 /d "NDEBUG" 46 | # ADD RSC /l 0x409 /d "NDEBUG" 47 | BSC32=bscmake.exe 48 | # ADD BASE BSC32 /nologo 49 | # ADD BSC32 /nologo 50 | LINK32=link.exe 51 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 52 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 53 | 54 | !ELSEIF "$(CFG)" == "c89atomic_basic - Win32 Debug" 55 | 56 | # PROP BASE Use_MFC 0 57 | # PROP BASE Use_Debug_Libraries 1 58 | # PROP BASE Output_Dir "Debug" 59 | # PROP BASE Intermediate_Dir "Debug" 60 | # PROP BASE Target_Dir "" 61 | # PROP Use_MFC 0 62 | # PROP Use_Debug_Libraries 1 63 | # PROP Output_Dir "Debug" 64 | # PROP Intermediate_Dir "Debug" 65 | # PROP Target_Dir "" 66 | # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 67 | # ADD CPP /nologo /W4 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c 68 | # ADD BASE RSC /l 0x409 /d "_DEBUG" 69 | # ADD RSC /l 0x409 /d "_DEBUG" 70 | BSC32=bscmake.exe 71 | # ADD BASE BSC32 /nologo 72 | # ADD BSC32 /nologo 73 | LINK32=link.exe 74 | # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 75 | # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept 76 | 77 | !ENDIF 78 | 79 | # Begin Target 80 | 81 | # Name "c89atomic_basic - Win32 Release" 82 | # Name "c89atomic_basic - Win32 Debug" 83 | # Begin Group "Source Files" 84 | 85 | # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" 86 | # Begin Source File 87 | 88 | SOURCE=..\..\..\c89atomic.c 89 | # PROP Exclude_From_Build 1 90 | # End Source File 91 | # Begin Source File 92 | 93 | SOURCE=..\..\..\tests\c89atomic_basic.c 94 | # End Source File 95 | # End Group 96 | # Begin Group "Header Files" 97 | 98 | # PROP Default_Filter "h;hpp;hxx;hm;inl" 99 | # Begin Source File 100 | 101 | SOURCE=..\..\..\c89atomic.h 102 | # End Source File 103 | # End Group 104 | # Begin Group "Resource Files" 105 | 106 | # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" 107 | # End Group 108 | # End Target 109 | # End Project 110 | -------------------------------------------------------------------------------- /build/vc8/c89atomic.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual C++ Express 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "c89atomic_basic", "c89atomic_basic\c89atomic_basic.vcproj", "{A42F56D7-320B-4BAD-9788-58FB2C8FB244}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {A42F56D7-320B-4BAD-9788-58FB2C8FB244}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {A42F56D7-320B-4BAD-9788-58FB2C8FB244}.Debug|Win32.Build.0 = Debug|Win32 14 | {A42F56D7-320B-4BAD-9788-58FB2C8FB244}.Release|Win32.ActiveCfg = Release|Win32 15 | {A42F56D7-320B-4BAD-9788-58FB2C8FB244}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /build/vc8/c89atomic_basic/c89atomic_basic.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 49 | 52 | 55 | 58 | 61 | 64 | 67 | 70 | 73 | 76 | 77 | 83 | 86 | 89 | 92 | 95 | 98 | 101 | 104 | 107 | 110 | 113 | 116 | 119 | 122 | 125 | 128 | 131 | 134 | 137 | 138 | 139 | 140 | 141 | 142 | 147 | 150 | 154 | 157 | 158 | 162 | 165 | 166 | 167 | 170 | 171 | 172 | 177 | 180 | 181 | 182 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /build/watcom/build.bat: -------------------------------------------------------------------------------- 1 | :: Adjust these paths to suit your own environment. 2 | set WATCOM_INSTALL_DIR=C:\WATCOM 3 | 4 | :: You need to setup the environment before executing the compiler. 5 | call "%WATCOM_INSTALL_DIR%\owsetenv.bat" 6 | 7 | :: Use wcl386 to compile for 32-bit. If you were wanting to do a 16-bit build, you would do "wcl", but 8 | :: since c89atomic does not support 16-bit architectures this is irrelevant for us. 9 | :: 10 | :: The "-zq" option is to enable quite builds. Not doing this will result in the compiler printing things 11 | :: like version and copyright information. 12 | wcl386 -zq ../../tests/c89atomic_basic.c -------------------------------------------------------------------------------- /c89atomic.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is only needed for the global lock, which is only needed for architectures that 3 | don't natively support a particular atomic operation. Most applications will not need this, 4 | but if you get errors about c89atomic_global_lock not being defined, you need to include 5 | this file in your project. 6 | */ 7 | #ifndef c89atomic_c 8 | #define c89atomic_c 9 | 10 | #include "c89atomic.h" 11 | 12 | /* BEG c89atomic_global_lock.c */ 13 | c89atomic_spinlock c89atomic_global_lock = 0; 14 | /* END c89atomic_global_lock.c */ 15 | 16 | #endif /* c89atomic_h*/ 17 | -------------------------------------------------------------------------------- /tests/c89atomic_basic.c: -------------------------------------------------------------------------------- 1 | /* 2 | Tests basic logic of all atomic functions. Does not test atomicity. 3 | */ 4 | #include 5 | #include 6 | 7 | //#define C89ATOMIC_MODERN_GCC 8 | //#define C89ATOMIC_LEGACY_GCC 9 | //#define C89ATOMIC_LEGACY_GCC_ASM 10 | //#define C89ATOMIC_MODERN_MSVC 11 | //#define C89ATOMIC_LEGACY_MSVC 12 | //#define C89ATOMIC_LEGACY_MSVC_ASM 13 | #include "../c89atomic.c" 14 | 15 | #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) 16 | #pragma GCC diagnostic push 17 | #pragma GCC diagnostic ignored "-Wlong-long" 18 | #if defined(__clang__) 19 | #pragma GCC diagnostic ignored "-Wc++11-long-long" 20 | #endif 21 | #endif 22 | 23 | #if defined(_MSC_VER) || defined(__BORLANDC__) 24 | #define C89ATOMIC_ULL(x) (c89atomic_uint64)(x##i64) 25 | #else 26 | #define C89ATOMIC_ULL(x) (c89atomic_uint64)(x##ULL) 27 | #endif 28 | 29 | #if defined(_WIN32) 30 | #include 31 | 32 | #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING 33 | #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 34 | #endif 35 | 36 | static void enable_colored_output(void) 37 | { 38 | HANDLE hOut; 39 | DWORD mode; 40 | 41 | hOut = GetStdHandle(STD_OUTPUT_HANDLE); 42 | if (hOut == INVALID_HANDLE_VALUE) { 43 | return; 44 | } 45 | 46 | if (!GetConsoleMode(hOut, &mode)) { 47 | return; 48 | } 49 | 50 | SetConsoleMode(hOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); 51 | } 52 | #else 53 | static void enable_colored_output(void) 54 | { 55 | /* Do nothing. */ 56 | } 57 | #endif 58 | 59 | 60 | #define PRINT_WIDTH 40 61 | 62 | /* Need to use a non-0 value for the old value to test byte ordering stuff properly. */ 63 | #define OLD_VAL 42 64 | 65 | static int g_ErrorCount = 0; 66 | 67 | const char* c89atomic_memory_order_to_string(c89atomic_memory_order order) 68 | { 69 | switch (order) 70 | { 71 | case c89atomic_memory_order_relaxed: return "c89atomic_memory_order_relaxed"; 72 | case c89atomic_memory_order_consume: return "c89atomic_memory_order_consume"; 73 | case c89atomic_memory_order_acquire: return "c89atomic_memory_order_acquire"; 74 | case c89atomic_memory_order_release: return "c89atomic_memory_order_release"; 75 | case c89atomic_memory_order_acq_rel: return "c89atomic_memory_order_acq_rel"; 76 | case c89atomic_memory_order_seq_cst: return "c89atomic_memory_order_seq_cst"; 77 | } 78 | 79 | return "[unknown memory order]"; 80 | } 81 | 82 | 83 | void c89atomic_test_passed(void) 84 | { 85 | printf("\033[32mPASSED\033[0m\n"); 86 | } 87 | 88 | void c89atomic_test_failed(void) 89 | { 90 | printf("\033[31mFAILED\033[0m\n"); 91 | g_ErrorCount += 1; 92 | } 93 | 94 | 95 | #define c89atomic_test__basic__flag_test_and_set_explicit(order) \ 96 | { \ 97 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 98 | { \ 99 | c89atomic_flag a = 0; \ 100 | c89atomic_flag b = 0; \ 101 | c89atomic_flag r = c89atomic_flag_test_and_set_explicit(&b, order); \ 102 | if (a == r && b == 1) { \ 103 | c89atomic_test_passed(); \ 104 | } else { \ 105 | c89atomic_test_failed(); \ 106 | } \ 107 | } \ 108 | } 109 | 110 | void c89atomic_test__basic__flag_test_and_set(void) 111 | { 112 | printf("c89atomic_flag_test_and_set():\n"); 113 | 114 | c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_relaxed); 115 | /*c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_consume);*/ 116 | c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_acquire); 117 | c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_release); 118 | c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_acq_rel); 119 | c89atomic_test__basic__flag_test_and_set_explicit(c89atomic_memory_order_seq_cst); 120 | 121 | printf("\n"); 122 | } 123 | 124 | #define c89atomic_test__basic__flag_clear_explicit(order) \ 125 | { \ 126 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 127 | { \ 128 | c89atomic_flag a = 1; \ 129 | c89atomic_flag_clear_explicit(&a, order); \ 130 | if (a == 0) { \ 131 | c89atomic_test_passed(); \ 132 | } else { \ 133 | c89atomic_test_failed(); \ 134 | } \ 135 | } \ 136 | } 137 | 138 | void c89atomic_test__basic__flag_clear(void) 139 | { 140 | printf("c89atomic_flag_clear():\n"); 141 | 142 | c89atomic_test__basic__flag_clear_explicit(c89atomic_memory_order_relaxed); 143 | c89atomic_test__basic__flag_clear_explicit(c89atomic_memory_order_release); 144 | c89atomic_test__basic__flag_clear_explicit(c89atomic_memory_order_seq_cst); 145 | 146 | printf("\n"); 147 | } 148 | 149 | #define c89atomic_test__basic__flag_load_explicit(order) \ 150 | { \ 151 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 152 | { \ 153 | c89atomic_flag a = 42; \ 154 | c89atomic_flag b = c89atomic_flag_load_explicit(&a, order); \ 155 | if (a == b) { \ 156 | c89atomic_test_passed(); \ 157 | } else { \ 158 | c89atomic_test_failed(); \ 159 | } \ 160 | } \ 161 | } 162 | 163 | void c89atomic_test__basic__flag_load(void) 164 | { 165 | printf("c89atomic_flag_load():\n"); 166 | 167 | c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_relaxed); 168 | c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_consume); 169 | c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_acquire); 170 | /*c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_release);*/ 171 | /*c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_acq_rel);*/ 172 | c89atomic_test__basic__flag_load_explicit(c89atomic_memory_order_seq_cst); 173 | 174 | printf("\n"); 175 | } 176 | 177 | 178 | #define c89atomic_test__basic_load_explicit(sizeInBits, src, order) \ 179 | { \ 180 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 181 | { \ 182 | c89atomic_uint##sizeInBits a = src; \ 183 | c89atomic_uint##sizeInBits b = c89atomic_load_explicit_##sizeInBits(&a, order); \ 184 | if (a == b) { \ 185 | c89atomic_test_passed(); \ 186 | } else { \ 187 | c89atomic_test_failed(); \ 188 | } \ 189 | } \ 190 | } 191 | 192 | #define c89atomic_test__basic_load_n(sizeInBits, src) \ 193 | { \ 194 | printf("c89atomic_load_%d():\n", sizeInBits); \ 195 | c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 196 | c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 197 | c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 198 | /*c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_release);*/ \ 199 | /*c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel);*/ \ 200 | c89atomic_test__basic_load_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 201 | } 202 | 203 | void c89atomic_test__basic__load(void) 204 | { 205 | c89atomic_test__basic_load_n(8, 123); 206 | c89atomic_test__basic_load_n(16, 1234); 207 | c89atomic_test__basic_load_n(32, 123456); 208 | c89atomic_test__basic_load_n(64, C89ATOMIC_ULL(123456789012)); 209 | printf("\n"); 210 | } 211 | 212 | 213 | #define c89atomic_test__basic_store_explicit(sizeInBits, src, order) \ 214 | { \ 215 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 216 | { \ 217 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 218 | c89atomic_uint##sizeInBits b = src; \ 219 | c89atomic_store_explicit_##sizeInBits(&a, b, order); \ 220 | if (b == a) { \ 221 | c89atomic_test_passed(); \ 222 | } else { \ 223 | c89atomic_test_failed(); \ 224 | } \ 225 | } \ 226 | } 227 | 228 | #define c89atomic_test__basic_store_n(sizeInBits, src) \ 229 | { \ 230 | printf("c89atomic_store_%d():\n", sizeInBits); \ 231 | c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 232 | /*c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_consume);*/ \ 233 | /*c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_acquire);*/ \ 234 | c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 235 | /*c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel);*/ \ 236 | c89atomic_test__basic_store_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 237 | } 238 | 239 | void c89atomic_test__basic__store(void) 240 | { 241 | c89atomic_test__basic_store_n(8, 123); 242 | c89atomic_test__basic_store_n(16, 1234); 243 | c89atomic_test__basic_store_n(32, 123456); 244 | c89atomic_test__basic_store_n(64, C89ATOMIC_ULL(123456789012)); 245 | printf("\n"); 246 | } 247 | 248 | 249 | #define c89atomic_test__basic_exchange_explicit(sizeInBits, src, order) \ 250 | { \ 251 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 252 | { \ 253 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 254 | c89atomic_uint##sizeInBits b = OLD_VAL; \ 255 | c89atomic_uint##sizeInBits c = src; \ 256 | c89atomic_uint##sizeInBits r = c89atomic_exchange_explicit_##sizeInBits(&b, c, order); \ 257 | if (r == a && b == c) { \ 258 | c89atomic_test_passed(); \ 259 | } else { \ 260 | c89atomic_test_failed(); \ 261 | } \ 262 | } \ 263 | } 264 | 265 | #define c89atomic_test__basic_exchange_n(sizeInBits, src) \ 266 | { \ 267 | printf("c89atomic_exchange_%d():\n", sizeInBits); \ 268 | c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 269 | /*c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_consume);*/ \ 270 | c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 271 | c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 272 | c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 273 | c89atomic_test__basic_exchange_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 274 | } 275 | 276 | void c89atomic_test__basic__exchange(void) 277 | { 278 | c89atomic_test__basic_exchange_n(8, 123); 279 | c89atomic_test__basic_exchange_n(16, 1234); 280 | c89atomic_test__basic_exchange_n(32, 123456); 281 | c89atomic_test__basic_exchange_n(64, C89ATOMIC_ULL(123456789012)); 282 | printf("\n"); 283 | } 284 | 285 | 286 | #define c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, orderSuccess, orderFailure) \ 287 | { \ 288 | printf(" %s, %s ", c89atomic_memory_order_to_string(orderSuccess), c89atomic_memory_order_to_string(orderFailure)); \ 289 | { \ 290 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 291 | c89atomic_uint##sizeInBits b = OLD_VAL; \ 292 | c89atomic_uint##sizeInBits c = src; \ 293 | c89atomic_bool r = c89atomic_compare_exchange_strong_explicit_##sizeInBits(&a, &b, c, orderSuccess, orderFailure); \ 294 | if (a == c && b == OLD_VAL && r == 1) { \ 295 | /* Negative case. Expecting a to remain unchanged, b to be set to OLD_VAL (previous value of a) and the result to be false. */ \ 296 | a = OLD_VAL; \ 297 | b = (c89atomic_uint##sizeInBits)(a + 1); \ 298 | r = c89atomic_compare_exchange_strong_explicit_##sizeInBits(&a, &b, c, orderSuccess, orderFailure); \ 299 | if (a == OLD_VAL && b == OLD_VAL && r == 0) { \ 300 | c89atomic_test_passed(); \ 301 | } else { \ 302 | c89atomic_test_failed(); \ 303 | } \ 304 | } else { \ 305 | c89atomic_test_failed(); \ 306 | } \ 307 | } \ 308 | } 309 | 310 | #define c89atomic_test__basic_compare_exchange_strong_n(sizeInBits, src) \ 311 | { \ 312 | printf("c89atomic_compare_exchange_%d():\n", sizeInBits); \ 313 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_relaxed, c89atomic_memory_order_relaxed); \ 314 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_consume, c89atomic_memory_order_consume); \ 315 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_acquire, c89atomic_memory_order_acquire); \ 316 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_release, c89atomic_memory_order_acquire); \ 317 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel, c89atomic_memory_order_acquire); \ 318 | c89atomic_test__basic_compare_exchange_strong_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst); \ 319 | } 320 | 321 | void c89atomic_test__basic__compare_exchange_strong(void) 322 | { 323 | c89atomic_test__basic_compare_exchange_strong_n(8, 123); 324 | c89atomic_test__basic_compare_exchange_strong_n(16, 1234); 325 | c89atomic_test__basic_compare_exchange_strong_n(32, 123456); 326 | c89atomic_test__basic_compare_exchange_strong_n(64, C89ATOMIC_ULL(123456789012)); 327 | printf("\n"); 328 | } 329 | 330 | 331 | #define c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, orderSuccess, orderFailure) \ 332 | { \ 333 | printf(" %s, %s ", c89atomic_memory_order_to_string(orderSuccess), c89atomic_memory_order_to_string(orderFailure)); \ 334 | { \ 335 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 336 | c89atomic_uint##sizeInBits b = OLD_VAL; \ 337 | c89atomic_uint##sizeInBits c = src; \ 338 | c89atomic_bool r = c89atomic_compare_exchange_weak_explicit_##sizeInBits(&a, &b, c, orderSuccess, orderFailure); \ 339 | if (a == c && b == OLD_VAL && r == 1) { \ 340 | /* Negative case. Expecting a to remain unchanged, b to be set to OLD_VAL (previous value of a) and the result to be false. */ \ 341 | a = OLD_VAL; \ 342 | b = (c89atomic_uint##sizeInBits)(a + 1); \ 343 | r = c89atomic_compare_exchange_weak_explicit_##sizeInBits(&a, &b, c, orderSuccess, orderFailure); \ 344 | if (a == OLD_VAL && b == OLD_VAL && r == 0) { \ 345 | c89atomic_test_passed(); \ 346 | } else { \ 347 | c89atomic_test_failed(); \ 348 | } \ 349 | } else { \ 350 | c89atomic_test_failed(); \ 351 | } \ 352 | } \ 353 | } 354 | 355 | #define c89atomic_test__basic_compare_exchange_weak_n(sizeInBits, src) \ 356 | { \ 357 | printf("c89atomic_compare_exchange_weak_%d():\n", sizeInBits); \ 358 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_relaxed, c89atomic_memory_order_relaxed); \ 359 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_consume, c89atomic_memory_order_consume); \ 360 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_acquire, c89atomic_memory_order_acquire); \ 361 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_release, c89atomic_memory_order_acquire); \ 362 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel, c89atomic_memory_order_acquire); \ 363 | c89atomic_test__basic_compare_exchange_weak_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst, c89atomic_memory_order_seq_cst); \ 364 | } 365 | 366 | void c89atomic_test__basic__compare_exchange_weak(void) 367 | { 368 | c89atomic_test__basic_compare_exchange_weak_n(8, 123); 369 | c89atomic_test__basic_compare_exchange_weak_n(16, 1234); 370 | c89atomic_test__basic_compare_exchange_weak_n(32, 123456); 371 | c89atomic_test__basic_compare_exchange_weak_n(64, C89ATOMIC_ULL(123456789012)); 372 | printf("\n"); 373 | } 374 | 375 | 376 | #define c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, order) \ 377 | { \ 378 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 379 | { \ 380 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 381 | c89atomic_uint##sizeInBits b = a; \ 382 | c89atomic_uint##sizeInBits c = src; \ 383 | c89atomic_uint##sizeInBits r = c89atomic_fetch_add_explicit_##sizeInBits(&a, c, order); \ 384 | if (r == b && a == (b + c)) { \ 385 | c89atomic_test_passed(); \ 386 | } else { \ 387 | c89atomic_test_failed(); \ 388 | } \ 389 | } \ 390 | } 391 | 392 | #define c89atomic_test__basic_fetch_add_n(sizeInBits, src) \ 393 | { \ 394 | printf("c89atomic_fetch_add_%d():\n", sizeInBits); \ 395 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 396 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 397 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 398 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 399 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 400 | c89atomic_test__basic_fetch_add_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 401 | } 402 | 403 | void c89atomic_test__basic__fetch_add(void) 404 | { 405 | c89atomic_test__basic_fetch_add_n(8, 123); 406 | c89atomic_test__basic_fetch_add_n(16, 1234); 407 | c89atomic_test__basic_fetch_add_n(32, 123456); 408 | c89atomic_test__basic_fetch_add_n(64, C89ATOMIC_ULL(123456789012)); 409 | printf("\n"); 410 | } 411 | 412 | 413 | #define c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, order) \ 414 | { \ 415 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 416 | { \ 417 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 418 | c89atomic_uint##sizeInBits b = a; \ 419 | c89atomic_uint##sizeInBits c = src; \ 420 | c89atomic_uint##sizeInBits r = c89atomic_fetch_sub_explicit_##sizeInBits(&a, c, order); \ 421 | if (r == b && a == (c89atomic_uint##sizeInBits)(b - c)) { \ 422 | c89atomic_test_passed(); \ 423 | } else { \ 424 | c89atomic_test_failed(); \ 425 | } \ 426 | } \ 427 | } 428 | 429 | #define c89atomic_test__basic_fetch_sub_n(sizeInBits, src) \ 430 | { \ 431 | printf("c89atomic_fetch_sub_%d():\n", sizeInBits); \ 432 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 433 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 434 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 435 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 436 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 437 | c89atomic_test__basic_fetch_sub_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 438 | } 439 | 440 | void c89atomic_test__basic__fetch_sub(void) 441 | { 442 | c89atomic_test__basic_fetch_sub_n(8, 123); 443 | c89atomic_test__basic_fetch_sub_n(16, 1234); 444 | c89atomic_test__basic_fetch_sub_n(32, 123456); 445 | c89atomic_test__basic_fetch_sub_n(64, C89ATOMIC_ULL(123456789012)); 446 | printf("\n"); 447 | } 448 | 449 | 450 | #define c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, order) \ 451 | { \ 452 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 453 | { \ 454 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 455 | c89atomic_uint##sizeInBits b = a; \ 456 | c89atomic_uint##sizeInBits c = src; \ 457 | c89atomic_uint##sizeInBits r = c89atomic_fetch_or_explicit_##sizeInBits(&a, c, order); \ 458 | if (r == b && a == (c89atomic_uint##sizeInBits)(b | c)) { \ 459 | c89atomic_test_passed(); \ 460 | } else { \ 461 | c89atomic_test_failed(); \ 462 | } \ 463 | } \ 464 | } 465 | 466 | #define c89atomic_test__basic_fetch_or_n(sizeInBits, src) \ 467 | { \ 468 | printf("c89atomic_fetch_or_%d():\n", sizeInBits); \ 469 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 470 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 471 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 472 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 473 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 474 | c89atomic_test__basic_fetch_or_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 475 | } 476 | 477 | void c89atomic_test__basic__fetch_or(void) 478 | { 479 | c89atomic_test__basic_fetch_or_n(8, 123); 480 | c89atomic_test__basic_fetch_or_n(16, 1234); 481 | c89atomic_test__basic_fetch_or_n(32, 123456); 482 | c89atomic_test__basic_fetch_or_n(64, C89ATOMIC_ULL(123456789012)); 483 | printf("\n"); 484 | } 485 | 486 | 487 | #define c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, order) \ 488 | { \ 489 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 490 | { \ 491 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 492 | c89atomic_uint##sizeInBits b = a; \ 493 | c89atomic_uint##sizeInBits c = src; \ 494 | c89atomic_uint##sizeInBits r = c89atomic_fetch_xor_explicit_##sizeInBits(&a, c, order); \ 495 | if (r == b && a == (c89atomic_uint##sizeInBits)(b ^ c)) { \ 496 | c89atomic_test_passed(); \ 497 | } else { \ 498 | c89atomic_test_failed(); \ 499 | } \ 500 | } \ 501 | } 502 | 503 | #define c89atomic_test__basic_fetch_xor_n(sizeInBits, src) \ 504 | { \ 505 | printf("c89atomic_fetch_xor_%d():\n", sizeInBits); \ 506 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 507 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 508 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 509 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 510 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 511 | c89atomic_test__basic_fetch_xor_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 512 | } 513 | 514 | void c89atomic_test__basic__fetch_xor(void) 515 | { 516 | c89atomic_test__basic_fetch_xor_n(8, 123); 517 | c89atomic_test__basic_fetch_xor_n(16, 1234); 518 | c89atomic_test__basic_fetch_xor_n(32, 123456); 519 | c89atomic_test__basic_fetch_xor_n(64, C89ATOMIC_ULL(123456789012)); 520 | printf("\n"); 521 | } 522 | 523 | 524 | #define c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, order) \ 525 | { \ 526 | printf(" %-*s", PRINT_WIDTH, c89atomic_memory_order_to_string(order)); \ 527 | { \ 528 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 529 | c89atomic_uint##sizeInBits b = a; \ 530 | c89atomic_uint##sizeInBits c = src; \ 531 | c89atomic_uint##sizeInBits r = c89atomic_fetch_and_explicit_##sizeInBits(&a, c, order); \ 532 | if (r == b && a == (c89atomic_uint##sizeInBits)(b & c)) { \ 533 | c89atomic_test_passed(); \ 534 | } else { \ 535 | c89atomic_test_failed(); \ 536 | } \ 537 | } \ 538 | } 539 | 540 | #define c89atomic_test__basic_fetch_and_n(sizeInBits, src) \ 541 | { \ 542 | printf("c89atomic_fetch_and_%d():\n", sizeInBits); \ 543 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_relaxed); \ 544 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_consume); \ 545 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_acquire); \ 546 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_release); \ 547 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_acq_rel); \ 548 | c89atomic_test__basic_fetch_and_explicit(sizeInBits, src, c89atomic_memory_order_seq_cst); \ 549 | } 550 | 551 | void c89atomic_test__basic__fetch_and(void) 552 | { 553 | c89atomic_test__basic_fetch_and_n(8, 123); 554 | c89atomic_test__basic_fetch_and_n(16, 1234); 555 | c89atomic_test__basic_fetch_and_n(32, 123456); 556 | c89atomic_test__basic_fetch_and_n(64, C89ATOMIC_ULL(123456789012)); 557 | printf("\n"); 558 | } 559 | 560 | 561 | #define c89atomic_test__basic_compare_and_swap_explicit(sizeInBits, src) \ 562 | { \ 563 | printf("c89atomic_compare_and_swap_%d() ", sizeInBits); printf("%*s", (int)(sizeInBits == 8), ""); \ 564 | { \ 565 | c89atomic_uint##sizeInBits a = OLD_VAL; \ 566 | c89atomic_uint##sizeInBits b = a; \ 567 | c89atomic_uint##sizeInBits c = src; \ 568 | c89atomic_uint##sizeInBits r = c89atomic_compare_and_swap_##sizeInBits(&a, b, c); \ 569 | if (a == c && r == b) { \ 570 | /* Negative case. Expecting a to remain unchanged and the result to not be equal to the expected value. */ \ 571 | a = OLD_VAL; \ 572 | b = (c89atomic_uint##sizeInBits)(a + 1); \ 573 | r = c89atomic_compare_and_swap_##sizeInBits(&a, b, c); \ 574 | if (a == OLD_VAL && r != b) { \ 575 | c89atomic_test_passed(); \ 576 | } else { \ 577 | c89atomic_test_failed(); \ 578 | } \ 579 | } else { \ 580 | c89atomic_test_failed(); \ 581 | } \ 582 | } \ 583 | } 584 | 585 | void c89atomic_test__basic__compare_and_swap(void) 586 | { 587 | c89atomic_test__basic_compare_and_swap_explicit(8, 123); 588 | c89atomic_test__basic_compare_and_swap_explicit(16, 1234); 589 | c89atomic_test__basic_compare_and_swap_explicit(32, 123456); 590 | c89atomic_test__basic_compare_and_swap_explicit(64, C89ATOMIC_ULL(123456789012)); 591 | printf("\n"); 592 | } 593 | 594 | 595 | #define C89ATOMIC_CHECK_SIZEOF(type, size) \ 596 | { \ 597 | printf("sizeof(%s)%*.s== %d ", #type, 17 - (int)strlen(#type), "", size); \ 598 | if (sizeof(type) != size) { \ 599 | c89atomic_test_failed(); \ 600 | } else { \ 601 | c89atomic_test_passed(); \ 602 | } \ 603 | } 604 | 605 | static void c89atomic_test__basic__sizeof(void) 606 | { 607 | C89ATOMIC_CHECK_SIZEOF(c89atomic_int8, 1); 608 | C89ATOMIC_CHECK_SIZEOF(c89atomic_uint8, 1); 609 | C89ATOMIC_CHECK_SIZEOF(c89atomic_int16, 2); 610 | C89ATOMIC_CHECK_SIZEOF(c89atomic_uint16, 2); 611 | C89ATOMIC_CHECK_SIZEOF(c89atomic_int32, 4); 612 | C89ATOMIC_CHECK_SIZEOF(c89atomic_uint32, 4); 613 | C89ATOMIC_CHECK_SIZEOF(c89atomic_int64, 8); 614 | C89ATOMIC_CHECK_SIZEOF(c89atomic_uint64, 8); 615 | printf("\n"); 616 | } 617 | 618 | 619 | int main(int argc, char** argv) 620 | { 621 | enable_colored_output(); 622 | 623 | /* The size of basic types must be valid. If not, the architecture/compiler/platform is not supported. */ 624 | c89atomic_test__basic__sizeof(); 625 | if (g_ErrorCount > 0) { 626 | printf("Tests cannot continue because the size of one or more basic types are not valid.\n"); 627 | return 1; 628 | } 629 | 630 | c89atomic_test__basic__flag_test_and_set(); 631 | c89atomic_test__basic__flag_clear(); 632 | c89atomic_test__basic__flag_load(); 633 | c89atomic_test__basic__load(); 634 | c89atomic_test__basic__store(); 635 | c89atomic_test__basic__exchange(); 636 | c89atomic_test__basic__compare_exchange_strong(); 637 | c89atomic_test__basic__compare_exchange_weak(); 638 | c89atomic_test__basic__fetch_add(); 639 | c89atomic_test__basic__fetch_sub(); 640 | c89atomic_test__basic__fetch_or(); 641 | c89atomic_test__basic__fetch_xor(); 642 | c89atomic_test__basic__fetch_and(); 643 | c89atomic_test__basic__compare_and_swap(); 644 | 645 | printf("c89atomic_is_lock_free_8 = %s\n", c89atomic_is_lock_free_8(NULL) ? "\033[32mTRUE\033[0m" : "\033[31mFALSE\033[0m"); 646 | printf("c89atomic_is_lock_free_16 = %s\n", c89atomic_is_lock_free_16(NULL) ? "\033[32mTRUE\033[0m" : "\033[31mFALSE\033[0m"); 647 | printf("c89atomic_is_lock_free_32 = %s\n", c89atomic_is_lock_free_32(NULL) ? "\033[32mTRUE\033[0m" : "\033[31mFALSE\033[0m"); 648 | printf("c89atomic_is_lock_free_64 = %s\n", c89atomic_is_lock_free_64(NULL) ? "\033[32mTRUE\033[0m" : "\033[31mFALSE\033[0m"); 649 | 650 | /* Putting these functions here for testing that they compile. */ 651 | c89atomic_thread_fence(c89atomic_memory_order_seq_cst); 652 | c89atomic_signal_fence(c89atomic_memory_order_seq_cst); 653 | 654 | /* Testing cases where the return value is not used. */ 655 | { 656 | void* dst = NULL; 657 | void* src = NULL; 658 | c89atomic_exchange_ptr(&dst, src); 659 | c89atomic_compare_exchange_strong_ptr(&dst, &dst, src); 660 | } 661 | 662 | { 663 | c89atomic_uint64 dst = 0; 664 | c89atomic_uint64 src = 1; 665 | c89atomic_exchange_64(&dst, src); 666 | } 667 | 668 | /* Testing that some basic integer versions are working without compilation errors. */ 669 | { 670 | int dst = 0; 671 | int src = 1; 672 | int res = c89atomic_exchange_i32(&dst, src); 673 | (void)res; 674 | } 675 | 676 | /* Basic floating point tests. */ 677 | { 678 | float dst = 1.0f; 679 | float src = 2.0f; 680 | float res = c89atomic_exchange_f32(&dst, src); 681 | (void)res; 682 | 683 | res = c89atomic_load_f32(&dst); 684 | (void)res; 685 | } 686 | 687 | { 688 | double dst = 1.0f; 689 | double src = 2.0f; 690 | double res = c89atomic_exchange_f64(&dst, src); 691 | (void)res; 692 | 693 | res = c89atomic_load_f64(&dst); 694 | (void)res; 695 | } 696 | 697 | (void)argc; 698 | (void)argv; 699 | 700 | printf("\n"); 701 | 702 | printf("Compiler: "); 703 | #if defined(__clang__) 704 | printf("Clang %d.%d\n", __clang_major__, __clang_minor__); 705 | #elif defined(__GNUC__) 706 | printf("GCC %d.%d\n", __GNUC__, __GNUC_MINOR__); 707 | #elif defined(_MSC_VER) 708 | printf("MSVC %d\n", _MSC_VER); 709 | #elif defined(__TINYC__) 710 | printf("TinyCC %d\n", __TINYC__); 711 | #elif defined(__WATCOMC__) 712 | printf("Watcom %d.%d\n", __WATCOMC__ / 100, (__WATCOMC__ - (__WATCOMC__ / 100)) / 10); 713 | #elif defined(__DMC__) 714 | printf("Digital Mars %d\n", __DMC__); 715 | #elif defined(__BORLANDC__) 716 | printf("Borland C++ %d\n", __BORLANDC__); 717 | #else 718 | printf("Unknown\n"); 719 | #endif 720 | 721 | printf("Architecture: "); 722 | #if defined(C89ATOMIC_X64) 723 | printf("x64\n"); 724 | #endif 725 | #if defined(C89ATOMIC_X86) 726 | printf("x86"); 727 | #if defined(__GNUC__) 728 | #if !defined(__i486__) 729 | printf(" (i386)\n"); 730 | #elif !defined(__i586__) 731 | printf(" (i486)\n"); 732 | #elif !defined(__i686__) 733 | printf(" (i586+)\n"); 734 | #else 735 | printf("\n"); 736 | #endif 737 | #elif defined(_M_IX86) 738 | #if _M_IX86 == 300 739 | printf(" (i386)\n"); 740 | #elif _M_IX86 == 400 741 | printf(" (i486)\n"); 742 | #elif _M_IX86 >= 500 743 | printf(" (i586+)\n"); 744 | #else 745 | printf("\n"); 746 | #endif 747 | #else 748 | printf("\n"); 749 | #endif 750 | #endif 751 | #if defined(C89ATOMIC_ARM64) 752 | printf("ARM64\n"); 753 | #endif 754 | #if defined(C89ATOMIC_ARM32) 755 | printf("ARM32\n"); 756 | #endif 757 | #if defined(C89ATOMIC_PPC64) 758 | printf("PowerPC64\n"); 759 | #endif 760 | #if defined(C89ATOMIC_PPC32) 761 | printf("PowerPC\n"); 762 | #endif 763 | 764 | printf("Code Path: "); 765 | #if defined(C89ATOMIC_MODERN_GCC) 766 | printf("GCC __atomic* intrinsics\n"); 767 | #elif defined(C89ATOMIC_LEGACY_GCC) 768 | printf("GCC __sync* intrinsics\n"); 769 | #elif defined(C89ATOMIC_LEGACY_GCC_ASM) 770 | printf("GCC inlined assembly\n"); 771 | #elif defined(C89ATOMIC_MODERN_MSVC) 772 | printf("MSVC _Interlocked* intrinsics\n"); 773 | #elif defined(C89ATOMIC_LEGACY_MSVC) 774 | printf("MSVC _Interlocked* intrinsics (no lock-free 8/16 bit)\n"); 775 | #elif defined(C89ATOMIC_LEGACY_MSVC_ASM) 776 | printf("MSVC inlined assembly\n"); 777 | #endif 778 | 779 | if (g_ErrorCount > 0) { 780 | printf("\033[31m%d test(s) failed.\033[0m\n", g_ErrorCount); 781 | return 1; 782 | } else { 783 | /*printf("\033[32mAll tests passed.\033[0m\n");*/ 784 | return 0; 785 | } 786 | } 787 | 788 | #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) 789 | #pragma GCC diagnostic pop /* -Wlong-long */ 790 | #endif 791 | -------------------------------------------------------------------------------- /x64/c89atomic.x64.win64.nasm: -------------------------------------------------------------------------------- 1 | ; u8 c89atomic_compare_and_swap_8 (u8* dst, u8 expected, u8 desired) 2 | ; u16 c89atomic_compare_and_swap_16(u16* dst, u16 expected, u16 desired) 3 | ; u32 c89atomic_compare_and_swap_32(u32* dst, u32 expected, u32 desired) 4 | ; u64 c89atomic_compare_and_swap_64(u64* dst, u64 expected, u64 desired) 5 | ; 6 | ; RCX = dst 7 | ; RDX = expected 8 | ; R8 = desired 9 | 10 | GLOBAL c89atomic_compare_and_swap_8 11 | GLOBAL c89atomic_compare_and_swap_16 12 | GLOBAL c89atomic_compare_and_swap_32 13 | GLOBAL c89atomic_compare_and_swap_64 14 | 15 | SECTION .text 16 | 17 | c89atomic_compare_and_swap_8: 18 | mov al, dl 19 | lock cmpxchg [rcx], r8b 20 | ret 21 | 22 | c89atomic_compare_and_swap_16: 23 | mov ax, dx 24 | lock cmpxchg [rcx], r8w 25 | ret 26 | 27 | c89atomic_compare_and_swap_32: 28 | mov eax, edx 29 | lock cmpxchg [rcx], r8d 30 | ret 31 | 32 | c89atomic_compare_and_swap_64: 33 | mov rax, rdx 34 | lock cmpxchg [rcx], r8 35 | ret 36 | --------------------------------------------------------------------------------