Name Date Size #Lines LOC

..--

atomicfu/H25-Apr-2025-4,6833,264

atomicfu-gradle-plugin/H25-Apr-2025-1,5311,208

atomicfu-maven-plugin/H25-Apr-2025-534366

atomicfu-native/H25-Apr-2025-86

atomicfu-transformer/H25-Apr-2025-3,3302,850

buildSrc/H25-Apr-2025-245159

gradle/H25-Apr-2025-255209

integration-testing/H25-Apr-2025-1,025749

license/H25-Apr-2025-97

.gitignoreH A D25-Apr-202536 55

Android.bpH A D25-Apr-20251.2 KiB4340

CHANGES.mdH A D25-Apr-202510.5 KiB398255

CODE_OF_CONDUCT.mdH A D25-Apr-2025269 52

LICENSEH A D01-Jan-19700

LICENSE.txtH A D25-Apr-2025596 1615

METADATAH A D25-Apr-2025619 2119

MODULE_LICENSE_APACHE2HD25-Apr-20250

NOTICEH A D01-Jan-19700

OWNERSH A D25-Apr-202519 21

README.mdH A D25-Apr-202515.6 KiB442334

RELEASE.mdH A D25-Apr-20252.3 KiB6949

build.gradleH A D25-Apr-20255.1 KiB127105

bump-version.shH A D25-Apr-2025762 3123

gradle.propertiesH A D25-Apr-2025749 3223

gradlewH A D25-Apr-20258.3 KiB249104

gradlew.batH A D25-Apr-20252.7 KiB9371

settings.gradleH A D25-Apr-2025245 86

README.md

1# AtomicFU
2
3[![Kotlin Beta](https://kotl.in/badges/beta.svg)](https://kotlinlang.org/docs/components-stability.html)
4[![JetBrains official project](https://jb.gg/badges/official.svg)](https://confluence.jetbrains.com/display/ALL/JetBrains+on+GitHub)
5[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
6[![Maven Central](https://img.shields.io/maven-central/v/org.jetbrains.kotlinx/atomicfu)](https://search.maven.org/artifact/org.jetbrains.kotlinx/atomicfu/0.23.1/pom)
7
8>Note on Beta status: the plugin is in its active development phase and changes from release to release.
9>We do provide a compatibility of atomicfu-transformed artifacts between releases, but we do not provide
10>strict compatibility guarantees on plugin API and its general stability between Kotlin versions.
11
12**Atomicfu** is a multiplatform library that provides the idiomatic and efficient way of using atomic operations in Kotlin.
13
14## Table of contents
15- [Requirements](#requirements)
16- [Features](#features)
17- [Example](#example)
18- [Quickstart](#quickstart)
19  - [Apply plugin to a project](#apply-plugin)
20    - [Gradle configuration](#gradle-configuration)
21    - [Maven configuration](#maven-configuration)
22- [Usage constraints](#usage-constraints)
23- [Transformation modes](#transformation-modes)
24  - [Atomicfu compiler plugin](#atomicfu-compiler-plugin)
25- [Options for post-compilation transformation](#options-for-post-compilation-transformation)
26  - [JVM options](#jvm-options)
27  - [JS options](#js-options)
28- [More features](#more-features)
29  - [Arrays of atomic values](#arrays-of-atomic-values)
30  - [User-defined extensions on atomics](#user-defined-extensions-on-atomics)
31  - [Locks](#locks)
32  - [Tracing operations](#tracing-operations)
33- [Kotlin/Native support](#kotlin-native-support)
34
35## Requirements
36
37Starting from version `0.23.1` of the library your project is required to use:
38
39* Gradle `7.0` or newer
40
41* Kotlin `1.7.0` or newer
42
43## Features
44
45* Complete multiplatform support: JVM, Native, JS and Wasm (since Kotlin 1.9.20).
46* Code it like a boxed value `atomic(0)`, but run it in production efficiently:
47  * For **JVM**: an atomic value is represented as a plain value atomically updated with `java.util.concurrent.atomic.AtomicXxxFieldUpdater` from the Java standard library.
48  * For **JS**: an atomic value is represented as a plain value.
49  * For **Native**: atomic operations are delegated to Kotlin/Native atomic intrinsics.
50  * For **Wasm**: an atomic value is not transformed, it remains boxed, and `kotlinx-atomicfu` library is used as a runtime dependency.
51* Use Kotlin-specific extensions (e.g. inline `loop`, `update`, `updateAndGet` functions).
52* Use atomic arrays, user-defined extensions on atomics and locks (see [more features](#more-features)).
53* [Tracing operations](#tracing-operations) for debugging.
54
55## Example
56
57Let us declare a `top` variable for a lock-free stack implementation:
58
59```kotlin
60import kotlinx.atomicfu.* // import top-level functions from kotlinx.atomicfu
61
62private val top = atomic<Node?>(null)
63```
64
65Use `top.value` to perform volatile reads and writes:
66
67```kotlin
68fun isEmpty() = top.value == null  // volatile read
69fun clear() { top.value = null }   // volatile write
70```
71
72Use `compareAndSet` function directly:
73
74```kotlin
75if (top.compareAndSet(expect, update)) ...
76```
77
78Use higher-level looping primitives (inline extensions), for example:
79
80```kotlin
81top.loop { cur ->   // while(true) loop that volatile-reads current value
82   ...
83}
84```
85
86Use high-level `update`, `updateAndGet`, and `getAndUpdate`,
87when possible, for idiomatic lock-free code, for example:
88
89```kotlin
90fun push(v: Value) = top.update { cur -> Node(v, cur) }
91fun pop(): Value? = top.getAndUpdate { cur -> cur?.next } ?.value
92```
93
94Declare atomic integers and longs using type inference:
95
96```kotlin
97val myInt = atomic(0)    // note: integer initial value
98val myLong = atomic(0L)  // note: long initial value
99```
100
101Integer and long atomics provide all the usual `getAndIncrement`, `incrementAndGet`, `getAndAdd`, `addAndGet`, and etc
102operations. They can be also atomically modified via `+=` and `-=` operators.
103
104## Quickstart
105### Apply plugin
106#### Gradle configuration
107
108Gradle configuration is supported for all platforms, minimal version is Gradle 6.8.
109
110In top-level build file:
111
112<details open>
113<summary>Kotlin</summary>
114
115```kotlin
116buildscript {
117    repositories {
118        mavenCentral()
119    }
120
121    dependencies {
122      classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.23.1")
123    }
124}
125
126apply(plugin = "kotlinx-atomicfu")
127```
128</details>
129
130<details>
131<summary>Groovy</summary>
132
133```groovy
134buildscript {
135    repositories {
136        mavenCentral()
137    }
138    dependencies {
139        classpath 'org.jetbrains.kotlinx:atomicfu-gradle-plugin:0.23.1'
140    }
141}
142
143apply plugin: 'kotlinx-atomicfu'
144```
145</details>
146
147#### Maven configuration
148
149Maven configuration is supported for JVM projects.
150
151
152<details open>
153<summary>Declare atomicfu version</summary>
154
155```xml
156<properties>
157     <atomicfu.version>0.23.1</atomicfu.version>
158</properties>
159```
160
161</details>
162
163<details>
164<summary>Declare provided dependency on the AtomicFU library</summary>
165
166```xml
167<dependencies>
168    <dependency>
169        <groupId>org.jetbrains.kotlinx</groupId>
170        <artifactId>atomicfu</artifactId>
171        <version>${atomicfu.version}</version>
172        <scope>provided</scope>
173    </dependency>
174</dependencies>
175```
176
177</details>
178
179Configure build steps so that Kotlin compiler puts classes into a different `classes-pre-atomicfu` directory,
180which is then transformed to a regular `classes` directory to be used later by tests and delivery.
181
182<details>
183<summary>Build steps</summary>
184
185```xml
186<build>
187  <plugins>
188    <!-- compile Kotlin files to staging directory -->
189    <plugin>
190      <groupId>org.jetbrains.kotlin</groupId>
191      <artifactId>kotlin-maven-plugin</artifactId>
192      <version>${kotlin.version}</version>
193      <executions>
194        <execution>
195          <id>compile</id>
196          <phase>compile</phase>
197          <goals>
198            <goal>compile</goal>
199          </goals>
200          <configuration>
201            <output>${project.build.directory}/classes-pre-atomicfu</output>
202          </configuration>
203        </execution>
204      </executions>
205    </plugin>
206    <!-- transform classes with AtomicFU plugin -->
207    <plugin>
208      <groupId>org.jetbrains.kotlinx</groupId>
209      <artifactId>atomicfu-maven-plugin</artifactId>
210      <version>${atomicfu.version}</version>
211      <executions>
212        <execution>
213          <goals>
214            <goal>transform</goal>
215          </goals>
216          <configuration>
217            <input>${project.build.directory}/classes-pre-atomicfu</input>
218            <!-- "VH" to use Java 9 VarHandle, "BOTH" to produce multi-version code -->
219            <variant>FU</variant>
220          </configuration>
221        </execution>
222      </executions>
223    </plugin>
224  </plugins>
225</build>
226```
227
228</details>
229
230## Usage constraints
231
232* Declare atomic variables as `private val` or `internal val`. You can use just (public) `val`,
233  but make sure they are not directly accessed outside of your Kotlin module (outside of the source set).
234  Access to the atomic variable itself shall be encapsulated.
235* To expose the value of an atomic property to the public, use a delegated property declared in the same scope
236  (see [atomic delegates](#atomic-delegates) section for details):
237
238```kotlin
239private val _foo = atomic<T>(initial) // private atomic, convention is to name it with leading underscore
240public var foo: T by _foo            // public delegated property (val/var)
241```
242* Only simple operations on atomic variables _directly_ are supported.
243  * Do not read references on atomic variables into local variables,
244    e.g. `top.compareAndSet(...)` is ok, while `val tmp = top; tmp...` is not.
245  * Do not leak references on atomic variables in other way (return, pass as params, etc).
246* Do not introduce complex data flow in parameters to atomic variable operations,
247  i.e. `top.value = complex_expression` and `top.compareAndSet(cur, complex_expression)` are not supported
248  (more specifically, `complex_expression` should not have branches in its compiled representation).
249  Extract `complex_expression` into a variable when needed.
250
251## Atomicfu compiler plugin
252
253To provide a user-friendly atomic API on the frontend and efficient usage of atomic values on the backend kotlinx-atomicfu library uses the compiler plugin to transform
254IR for all the target backends:
255* **JVM**: atomics are replaced with `java.util.concurrent.atomic.AtomicXxxFieldUpdater`.
256* **Native**: atomics are implemented via atomic intrinsics on Kotlin/Native.
257* **JS**: atomics are unboxed and represented as plain values.
258
259To turn on IR transformation set these properties in your `gradle.properties` file:
260
261<details open>
262<summary>For Kotlin >= 1.7.20</summary>
263
264```groovy
265kotlinx.atomicfu.enableJvmIrTransformation=true // for JVM IR transformation
266kotlinx.atomicfu.enableNativeIrTransformation=true // for Native IR transformation
267kotlinx.atomicfu.enableJsIrTransformation=true // for JS IR transformation
268```
269
270</details>
271
272<details>
273
274
275<summary> For Kotlin >= 1.6.20 and Kotlin < 1.7.20</summary>
276
277```groovy
278kotlinx.atomicfu.enableIrTransformation=true // only JS IR transformation is supported
279```
280
281</details>
282
283Also for JS backend make sure that `ir` or `both` compiler mode is set:
284
285```groovy
286kotlin.js.compiler=ir // or both
287```
288
289
290## Options for post-compilation transformation
291
292Some configuration options are available for _post-compilation transform tasks_ on JVM and JS.
293
294To set configuration options you should create `atomicfu` section in a `build.gradle` file,
295like this:
296```groovy
297atomicfu {
298  dependenciesVersion = '0.23.1'
299}
300```
301
302### JVM options
303
304To turn off transformation for Kotlin/JVM set option `transformJvm` to `false`.
305
306Configuration option `jvmVariant` defines the Java class that replaces atomics during bytecode transformation.
307Here are the valid options:
308- `FU` – atomics are replaced with [AtomicXxxFieldUpdater](https://docs.oracle.com/javase/10/docs/api/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.html).
309- `VH` – atomics are replaced with [VarHandle](https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/VarHandle.html),
310  this option is supported for JDK 9+.
311- `BOTH` – [multi-release jar file](https://openjdk.java.net/jeps/238) will be created with both `AtomicXxxFieldUpdater` for JDK <= 8 and `VarHandle` for JDK 9+.
312
313### JS options
314
315To turn off transformation for Kotlin/JS set option `transformJs` to `false`.
316
317Here are all available configuration options (with their defaults):
318```groovy
319atomicfu {
320  dependenciesVersion = '0.23.1' // set to null to turn-off auto dependencies
321  transformJvm = true // set to false to turn off JVM transformation
322  jvmVariant = "FU" // JVM transformation variant: FU,VH, or BOTH
323  transformJs = true // set to false to turn off JVM transformation
324}
325```
326
327## More features
328
329AtomicFU provides some additional features that you can use.
330
331### Arrays of atomic values
332
333You can declare arrays of all supported atomic value types.
334By default arrays are transformed into the corresponding `java.util.concurrent.atomic.Atomic*Array` instances.
335
336If you configure `variant = "VH"` an array will be transformed to plain array using
337[VarHandle](https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/VarHandle.html) to support atomic operations.
338
339```kotlin
340val a = atomicArrayOfNulls<T>(size) // similar to Array constructor
341
342val x = a[i].value // read value
343a[i].value = x // set value
344a[i].compareAndSet(expect, update) // do atomic operations
345```
346
347### Atomic delegates
348
349You can expose the value of an atomic property to the public, using a delegated property
350declared in the same scope:
351
352```kotlin
353private val _foo = atomic<T>(initial) // private atomic, convention is to name it with leading underscore
354public var foo: T by _foo            // public delegated property (val/var)
355```
356
357You can also delegate a property to the atomic factory invocation, that is equal to declaring a volatile property:
358
359```kotlin
360public var foo: T by atomic(0)
361```
362
363This feature is only supported for the IR transformation mode, see the [atomicfu compiler plugin](#atomicfu-compiler-plugin) section for details.
364
365### User-defined extensions on atomics
366
367You can define you own extension functions on `AtomicXxx` types but they must be `inline` and they cannot
368be public and be used outside of the module they are defined in. For example:
369
370```kotlin
371@Suppress("NOTHING_TO_INLINE")
372private inline fun AtomicBoolean.tryAcquire(): Boolean = compareAndSet(false, true)
373```
374
375### Locks
376
377This project includes `kotlinx.atomicfu.locks` package providing multiplatform locking primitives that
378require no additional runtime dependencies on Kotlin/JVM and Kotlin/JS with a library implementation for
379Kotlin/Native.
380
381* `SynchronizedObject` is designed for inheritance. You write `class MyClass : SynchronizedObject()` and then
382use `synchronized(instance) { ... }` extension function similarly to the
383[synchronized](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/synchronized.html)
384function from the standard library that is available for JVM. The `SynchronizedObject` superclass gets erased
385(transformed to `Any`) on JVM and JS, with `synchronized` leaving no trace in the code on JS and getting
386replaced with built-in monitors for locking on JVM.
387
388* `ReentrantLock` is designed for delegation. You write `val lock = reentrantLock()` to construct its instance and
389use `lock`/`tryLock`/`unlock` functions or `lock.withLock { ... }` extension function similarly to the way
390[jucl.ReentrantLock](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantLock.html)
391is used on JVM. On JVM it is a typealias to the later class, erased on JS.
392
393> Note that package `kotlinx.atomicfu.locks` is experimental explicitly even while atomicfu is experimental itself,
394> meaning that no ABI guarantees are provided whatsoever. API from this package is not recommended to use in libraries
395> that other projects depend on.
396
397### Tracing operations
398
399You can debug your tests tracing atomic operations with a special trace object:
400
401```kotlin
402private val trace = Trace()
403private val current = atomic(0, trace)
404
405fun update(x: Int): Int {
406    // custom trace message
407    trace { "calling update($x)" }
408    // automatic tracing of modification operations
409    return current.getAndAdd(x)
410}
411```
412
413All trace messages are stored in a cyclic array inside `trace`.
414
415You can optionally set the size of trace's message array and format function. For example,
416you can add a current thread name to the traced messages:
417
418```kotlin
419private val trace = Trace(size = 64) {
420    index, // index of a trace message
421    text   // text passed when invoking trace { text }
422    -> "$index: [${Thread.currentThread().name}] $text"
423}
424```
425
426`trace` is only seen before transformation and completely erased after on Kotlin/JVM and Kotlin/JS.
427
428## Kotlin Native support
429
430Atomic references for Kotlin/Native are based on
431[FreezableAtomicReference](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/-freezable-atomic-reference/-init-.html)
432and every reference that is stored to the previously
433[frozen](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native.concurrent/freeze.html)
434(shared with another thread) atomic is automatically frozen, too.
435
436Since Kotlin/Native does not generally provide binary compatibility between versions,
437you should use the same version of Kotlin compiler as was used to build AtomicFU.
438See [gradle.properties](gradle.properties) in AtomicFU project for its `kotlin_version`.
439
440Available Kotlin/Native targets are based on non-deprecated official targets [Tier list](https://kotlinlang.org/docs/native-target-support.html)
441 with the corresponding compatibility guarantees.
442