├── .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 |
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 |
--------------------------------------------------------------------------------