Skip to content
This repository has been archived by the owner on Aug 10, 2021. It is now read-only.

Commit

Permalink
Atomic values support.
Browse files Browse the repository at this point in the history
  • Loading branch information
olonho committed Jun 15, 2018
1 parent 7741dfe commit 7e201e0
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 6 deletions.
6 changes: 6 additions & 0 deletions backend.native/tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,12 @@ task freeze2(type: RunKonanTest) {
source = "runtime/workers/freeze2.kt"
}

task atomic0(type: RunKonanTest) {
disabled = (project.testTarget == 'wasm32') // Workers need pthreads.
goldValue = "35\n" + "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n"
source = "runtime/workers/atomic0.kt"
}

task enumIdentity(type: RunKonanTest) {
disabled = (project.testTarget == 'wasm32') // Workers need pthreads.
goldValue = "true\n"
Expand Down
41 changes: 41 additions & 0 deletions backend.native/tests/runtime/workers/atomic0.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package runtime.workers.atomic0

import kotlin.test.*

import konan.worker.*

fun test1(workers: Array<Worker>) {
val atomic = AtomicInt(15)
val futures = Array(workers.size, { workerIndex ->
workers[workerIndex].schedule(TransferMode.CHECKED, { atomic }) {
input -> input.increment()
}
})
futures.forEach {
it.result()
}
println(atomic.get())
}

fun test2(workers: Array<Worker>) {
val atomic = AtomicInt(0)
val futures = Array(workers.size, { workerIndex ->
workers[workerIndex].schedule(TransferMode.CHECKED, { atomic to workerIndex }) {
(place, index) ->
while (place.compareAndSwap(index, index + 1) != index) {}
println(index)
}
})
futures.forEach {
it.result()
}
println(atomic.get())
}

@Test fun runTest() {
val COUNT = 20
val workers = Array(COUNT, { _ -> startWorker()})

test1(workers)
test2(workers)
}
56 changes: 56 additions & 0 deletions runtime/src/main/cpp/Atomic.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "Atomic.h"
#include "Types.h"

namespace {

template <typename T> T addAndGetImpl(KRef thiz, T delta) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1);
return atomicAdd(location, delta);
}

template <typename T> T compareAndSwapImpl(KRef thiz, T expectedValue, T newValue) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1);
return compareAndSwap(location, expectedValue, newValue);
}

} // namespace

extern "C" {

KInt Kotlin_AtomicInt_addAndGet(KRef thiz, KInt delta) {
return addAndGetImpl(thiz, delta);
}

KInt Kotlin_AtomicInt_compareAndSwap(KRef thiz, KInt expectedValue, KInt newValue) {
return compareAndSwapImpl(thiz, expectedValue, newValue);
}

KLong Kotlin_AtomicLong_addAndGet(KRef thiz, KLong delta) {
return addAndGetImpl(thiz, delta);
}

KLong Kotlin_AtomicLong_compareAndSwap(KRef thiz, KLong expectedValue, KLong newValue) {
return compareAndSwapImpl(thiz, expectedValue, newValue);
}

KNativePtr Kotlin_AtomicNativePtr_compareAndSwap(KRef thiz, KNativePtr expectedValue, KNativePtr newValue) {
return compareAndSwapImpl(thiz, expectedValue, newValue);
}

} // extern "C"
17 changes: 16 additions & 1 deletion runtime/src/main/cpp/Atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@

#include "Common.h"

ALWAYS_INLINE inline int atomicAdd(int* where, int what) {
template <typename T>
ALWAYS_INLINE inline T atomicAdd(volatile T* where, T what) {
#ifndef KONAN_NO_THREADS
return __sync_add_and_fetch(where, what);
#else
return *where += what;
#endif
}

template <typename T>
ALWAYS_INLINE inline T compareAndSwap(volatile T* where, T expectedValue, T newValue) {
#ifndef KONAN_NO_THREADS
return __sync_val_compare_and_swap(where, expectedValue, newValue);
#else
T oldValue = *location;
if (oldValue == expectedValue) {
*location = newValue;
}
return oldValue;
return *where += what;
#endif
}


#endif // RUNTIME_ATOMIC_H
3 changes: 0 additions & 3 deletions runtime/src/main/cpp/Worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@
#if WITH_WORKERS
#include <pthread.h>
#include <sys/time.h>

#include <deque>
#include <unordered_map>
#endif

#include "Alloc.h"
Expand Down
5 changes: 3 additions & 2 deletions runtime/src/main/kotlin/konan/internal/Annotations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ annotation class ExportForCompiler
annotation class InlineConstructor

/**
* Class is immutable and is frozen by default.
* Class is immutable and is frozen by default. Also this annotation is (ab)used for marking objects
* where mutability checks are not needed.
*/
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class Immutable
internal annotation class Immutable
181 changes: 181 additions & 0 deletions runtime/src/main/kotlin/konan/worker/Atomics.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* Copyright 2010-2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package konan.worker

import konan.internal.Immutable
import konan.SymbolName
import kotlinx.cinterop.NativePtr

@Immutable
class AtomicInt(private var value: Int = 0) : Number() {
/* Atomic operations. */

/**
* Increments the value by [delta] and returns the new value.
*/
@SymbolName("Kotlin_AtomicInt_addAndGet")
external fun addAndGet(delta: Int): Int

/**
* Compares value with [expected] and replaces it with [new] value if values matches.
* Returns the old value.
*/
@SymbolName("Kotlin_AtomicInt_compareAndSwap")
external fun compareAndSwap(expected: Int, new: Int): Int

/**
* Increments value by one.
*/
fun increment(): Int = addAndGet(1)

/**
* Decrements value by one.
*/
fun decrement(): Int = addAndGet(-1)

/**
* Returns the current value.
*/
fun get(): Int = value

/* Operations from Number. */

/**
* Returns the value of this number as a [Double], which may involve rounding.
*/
public override fun toDouble(): Double = value.toDouble()

/**
* Returns the value of this number as a [Float], which may involve rounding.
*/
public override fun toFloat(): Float = value.toFloat()

/**
* Returns the value of this number as a [Long], which may involve rounding or truncation.
*/
public override fun toLong(): Long = value.toLong()

/**
* Returns the value of this number as an [Int], which may involve rounding or truncation.
*/
public override fun toInt(): Int = value.toInt()

/**
* Returns the [Char] with the numeric value equal to this number, truncated to 16 bits if appropriate.
*/
public override fun toChar(): Char = value.toChar()

/**
* Returns the value of this number as a [Short], which may involve rounding or truncation.
*/
public override fun toShort(): Short = value.toShort()

/**
* Returns the value of this number as a [Byte], which may involve rounding or truncation.
*/
public override fun toByte(): Byte = value.toByte()
}

@Immutable
class AtomicLong(private var value: Long = 0) : Number() {
/* Atomic operations. */

/**
* Increments the value by [delta] and returns the new value.
*/
@SymbolName("Kotlin_AtomicLong_addAndGet")
external fun addAndGet(delta: Long): Long

/**
* Increments the value by [delta] and returns the new value.
*/
fun addAndGet(delta: Int): Long = addAndGet(delta.toLong())

/**
* Compares value with [expected] and replaces it with [new] value if values matches.
* Returns the old value.
*/
@SymbolName("Kotlin_AtomicLong_compareAndSwap")
external fun compareAndSwap(expected: Long, new: Long): Long

/**
* Increments value by one.
*/
fun increment(): Long = addAndGet(1L)

/**
* Decrements value by one.
*/
fun decrement(): Long = addAndGet(-1L)

/**
* Returns the current value.
*/
fun get(): Long = value

/* Operations from Number. */

/**
* Returns the value of this number as a [Double], which may involve rounding.
*/
public override fun toDouble(): Double = value.toDouble()

/**
* Returns the value of this number as a [Float], which may involve rounding.
*/
public override fun toFloat(): Float = value.toFloat()

/**
* Returns the value of this number as a [Long], which may involve rounding or truncation.
*/
public override fun toLong(): Long = value.toLong()

/**
* Returns the value of this number as an [Int], which may involve rounding or truncation.
*/
public override fun toInt(): Int = value.toInt()

/**
* Returns the [Char] with the numeric value equal to this number, truncated to 16 bits if appropriate.
*/
public override fun toChar(): Char = value.toChar()

/**
* Returns the value of this number as a [Short], which may involve rounding or truncation.
*/
public override fun toShort(): Short = value.toShort()

/**
* Returns the value of this number as a [Byte], which may involve rounding or truncation.
*/
public override fun toByte(): Byte = value.toByte()
}

@Immutable
class AtomicNativePtr(private var value: NativePtr) {
/**
* Compares value with [expected] and replaces it with [new] value if values matches.
* Returns the old value.
*/
@SymbolName("Kotlin_AtomicNativePtr_compareAndSwap")
external fun compareAndSwap(expected: NativePtr, new: NativePtr): NativePtr

/**
* Returns the current value.
*/
fun get(): NativePtr = value
}

0 comments on commit 7e201e0

Please sign in to comment.