Extracting 'safeAutoClose*' functions family to a separate library
This commit is contained in:
parent
834d12c17b
commit
9538888b77
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "libs/int-serializers"]
|
||||
path = libs/int-serializers
|
||||
url = https://git.landgrafhomyak.ru/xomrk/int-serializers.kt
|
||||
[submodule "libs/highlevel-try-finally"]
|
||||
path = libs/highlevel-try-finally
|
||||
url = https://git.landgrafhomyak.ru/xomrk/highlevel-try-finally.kt
|
||||
|
1
libs/highlevel-try-finally
Submodule
1
libs/highlevel-try-finally
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ef1d72ca10c361d2eead443d99241a088e130174
|
@ -8,9 +8,9 @@ import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.sockets.IcmpSocket
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.compareAndExchange
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.IntSerializers
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class)
|
||||
@ -24,7 +24,7 @@ class Pinger1 : AutoCloseable {
|
||||
|
||||
|
||||
internal constructor(rawSocket: IcmpSocket) {
|
||||
safeAutoClose2(onAbort = rawSocket::close) {
|
||||
safeAutoClose2(onError = rawSocket::close) {
|
||||
this._state = atomic(State.READY)
|
||||
this._rawSocket = rawSocket
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package ru.landgrafhomyak.bgtu.networks0.low_level.multithreading
|
||||
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
class CountDownLatch : AutoCloseable {
|
||||
private val _refcnt: CloseableRefCounter
|
||||
@ -14,7 +14,7 @@ class CountDownLatch : AutoCloseable {
|
||||
this._refcnt = CloseableRefCounter("Latch was destroyed")
|
||||
this._counter = initialCounterValue
|
||||
this._mutex = Mutex()
|
||||
safeAutoClose2(onAbort = this._mutex::close) {
|
||||
safeAutoClose2(onError = this._mutex::close) {
|
||||
this._condition = Condition()
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ package ru.landgrafhomyak.bgtu.networks0.low_level.multithreading
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun <R> Mutex.withLock(synchronizedBlock: () -> R): R {
|
||||
|
@ -14,8 +14,8 @@ import platform.posix.pthread_cond_broadcast
|
||||
import platform.posix.pthread_cond_signal
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@ -26,7 +26,7 @@ actual class Condition : AutoCloseable {
|
||||
actual constructor() {
|
||||
this._refcnt = CloseableRefCounter("Pthreads condition was destroyed")
|
||||
this._descriptor = nativeHeap.alloc<pthread_cond_t>().ptr
|
||||
safeAutoClose2(onAbort = { nativeHeap.free(this._descriptor) }) {
|
||||
safeAutoClose2(onError = { nativeHeap.free(this._descriptor) }) {
|
||||
var err = pthread_cond_init(this._descriptor, null)
|
||||
if (err != 0)
|
||||
PosixUtilities.throwErrno { d -> RuntimeException("Failed to initialize pthreads condition: $d") }
|
||||
|
@ -13,8 +13,8 @@ import platform.posix.pthread_mutex_t
|
||||
import platform.posix.pthread_mutex_unlock
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class, Mutex.RefcntAccess::class)
|
||||
actual class Mutex : AutoCloseable {
|
||||
@ -28,7 +28,7 @@ actual class Mutex : AutoCloseable {
|
||||
actual constructor() {
|
||||
this._refcnt = CloseableRefCounter("Pthreads mutex was destroyed")
|
||||
this._descriptor = nativeHeap.alloc<pthread_mutex_t>().ptr
|
||||
safeAutoClose2(onAbort = { nativeHeap.free(this._descriptor) }) {
|
||||
safeAutoClose2(onError = { nativeHeap.free(this._descriptor) }) {
|
||||
var err = pthread_mutex_init(this._descriptor, null)
|
||||
if (err != 0)
|
||||
PosixUtilities.throwErrno(err) { d -> RuntimeException("Failed to create pthreads mutex: $d") }
|
||||
|
@ -9,9 +9,9 @@ import kotlinx.cinterop.StableRef
|
||||
import kotlinx.cinterop.asStableRef
|
||||
import kotlinx.cinterop.staticCFunction
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2e
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2e
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.compareAndExchange
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@ -38,9 +38,9 @@ actual class Thread : AutoCloseable {
|
||||
actual constructor(routine: Routine) {
|
||||
this._state = atomic(State.PENDING)
|
||||
this._bootstrapArgRef = StableRef.create(ThreadBootstrapContext(routine))
|
||||
safeAutoClose2(onAbort = this._bootstrapArgRef::dispose) {
|
||||
safeAutoClose2(onError = this._bootstrapArgRef::dispose) {
|
||||
this._threadBindings = _PthreadsThreadBindings()
|
||||
safeAutoClose2(onAbort = this._threadBindings::free) {
|
||||
safeAutoClose2(onError = this._threadBindings::free) {
|
||||
var err = this._threadBindings.create(
|
||||
null,
|
||||
staticCFunction({ arg -> return@staticCFunction Thread._threadBootstrap(arg) }),
|
||||
@ -60,7 +60,7 @@ actual class Thread : AutoCloseable {
|
||||
State.STARTING, State.RUNNING -> throw IllegalStateException("Pthreads thread already running")
|
||||
State.PENDING -> {}
|
||||
}
|
||||
safeAutoClose2(onAbort = { this._state.value = State.PENDING }) {
|
||||
safeAutoClose2(onError = { this._state.value = State.PENDING }) {
|
||||
this._bootstrapArgRef.get().startSignal.decrement()
|
||||
}
|
||||
}
|
||||
@ -73,13 +73,13 @@ actual class Thread : AutoCloseable {
|
||||
}
|
||||
var err = this._threadBindings.join(null)
|
||||
if (err != 0)
|
||||
PosixUtilities.throwErrno(err) { d -> RuntimeException("Failed to create pthreads thread") }
|
||||
PosixUtilities.throwErrno(err) { d -> RuntimeException("Failed to create pthreads thread: $d") }
|
||||
return this._bootstrapArgRef.get().exitedWithError
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
this._state.update { o ->
|
||||
when (this._state.value) {
|
||||
when (o) {
|
||||
State.CLOSED -> throw IllegalStateException("Pthreads thread is destroyed")
|
||||
State.STARTING, State.RUNNING -> throw IllegalStateException("Can't destroy pthreads thread while it running")
|
||||
State.FINISHED, State.PENDING -> {}
|
||||
@ -113,7 +113,7 @@ actual class Thread : AutoCloseable {
|
||||
}
|
||||
try {
|
||||
safeAutoClose2e(
|
||||
onAbort = { e ->
|
||||
onError = { e ->
|
||||
context.exitedWithError = e
|
||||
context.threadState.value = State.FINISHED
|
||||
},
|
||||
|
@ -30,8 +30,8 @@ import platform.posix.sockaddr_in6
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.withLock
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose1
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.multithreading.Mutex as TMutex
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@ -187,7 +187,7 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
||||
this.read = null
|
||||
this.write = null
|
||||
this.stableRef = StableRef.create(this)
|
||||
safeAutoClose2(onAbort = this.stableRef::dispose) {
|
||||
safeAutoClose2(onError = this.stableRef::dispose) {
|
||||
this.sync = TMutex()
|
||||
}
|
||||
}
|
||||
@ -205,13 +205,13 @@ class EpollSocketEventLoop : SocketEventLoopScope.Closeable {
|
||||
private val __metadata: _SocketMetadata
|
||||
|
||||
constructor(ipv4: CValue<sockaddr_in>) : super(ipv4) {
|
||||
safeAutoClose2(onAbort = { super.close() }) {
|
||||
safeAutoClose2(onError = { super.close() }) {
|
||||
this.__metadata = _SocketMetadata(this._socketFd)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(ipv6: CValue<sockaddr_in6>) : super(ipv6) {
|
||||
safeAutoClose2(onAbort = { super.close() }) {
|
||||
safeAutoClose2(onError = { super.close() }) {
|
||||
this@EpollSocketEventLoop._socketsCount.tryIncref {
|
||||
this.__metadata = _SocketMetadata(this._socketFd)
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ import platform.posix.close as close_lowlevel
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.CUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.low_level.c_interop_utilities.PosixUtilities
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.CloseableRefCounter
|
||||
import ru.landgrafhomyak.bgtu.networks0.utilities.safeAutoClose2
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
@Suppress("CanBeVal")
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@ -82,7 +82,7 @@ internal abstract class NonblockingIcmpSocketImpl : IcmpSocket {
|
||||
else
|
||||
PosixUtilities.throwErrno { d -> RuntimeException("Failed to create ICMP socket over ${protoName}: $d") }
|
||||
}
|
||||
safeAutoClose2(onAbort = { if (0 != close_lowlevel(this._socketFd)) PosixUtilities.throwErrno { d -> RuntimeException("Failed to close ICMP socket: $d") } }) {
|
||||
safeAutoClose2(onError = { if (0 != close_lowlevel(this._socketFd)) PosixUtilities.throwErrno { d -> RuntimeException("Failed to close ICMP socket: $d") } }) {
|
||||
var err = memScoped {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return@memScoped connect(sock, addrValue as CValue<sockaddr>, addrSize)
|
||||
|
@ -22,6 +22,7 @@ kotlin {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation(Dependencies.kotlin_atomicfu)
|
||||
api("ru.landgrafhomyak.utility:highlevel-try-finally:0.4")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ import kotlin.contracts.contract
|
||||
import kotlinx.atomicfu.AtomicLong
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.atomicfu.update
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
|
||||
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose2
|
||||
|
||||
class CloseableRefCounter(private val _errMessage: String) {
|
||||
private val _value: AtomicLong = atomic(0L)
|
||||
@ -28,7 +30,7 @@ class CloseableRefCounter(private val _errMessage: String) {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
this.incref()
|
||||
return safeAutoClose2(onAbort = this::decref, action = block)
|
||||
return safeAutoClose2(onError = this::decref, action = block)
|
||||
}
|
||||
|
||||
fun checkNotClosed() {
|
||||
|
@ -1,100 +0,0 @@
|
||||
@file:OptIn(ExperimentalContracts::class)
|
||||
|
||||
package ru.landgrafhomyak.bgtu.networks0.utilities
|
||||
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
@Suppress("WRONG_INVOCATION_KIND")
|
||||
inline fun <R> safeAutoClose1(
|
||||
finally: () -> Unit,
|
||||
action: () -> R
|
||||
): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(finally, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return safeAutoClose3(onAbort = finally, onSuccess = finally, onCrossReturn = finally, action = action)
|
||||
}
|
||||
|
||||
@Suppress("WRONG_INVOCATION_KIND")
|
||||
inline fun <R> safeAutoClose2(
|
||||
onAbort: () -> Unit = {},
|
||||
onSuccess: () -> Unit = {},
|
||||
action: () -> R
|
||||
): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return safeAutoClose3(onAbort = onAbort, onSuccess = onSuccess, onCrossReturn = onSuccess, action = action)
|
||||
}
|
||||
|
||||
@Suppress("WRONG_INVOCATION_KIND")
|
||||
inline fun <R> safeAutoClose2e(
|
||||
onAbort: (Throwable) -> Unit = { _ -> },
|
||||
onSuccess: () -> Unit = {},
|
||||
action: () -> R
|
||||
): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return safeAutoClose3e(onAbort = onAbort, onSuccess = onSuccess, onCrossReturn = onSuccess, action = action)
|
||||
}
|
||||
|
||||
inline fun <R> safeAutoClose3(
|
||||
onAbort: () -> Unit = {},
|
||||
onSuccess: () -> Unit = {},
|
||||
onCrossReturn: () -> Unit = {},
|
||||
action: () -> R
|
||||
): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onCrossReturn, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return safeAutoClose3e(onAbort = { t -> onAbort() }, onSuccess = onSuccess, onCrossReturn = onCrossReturn, action = action)
|
||||
}
|
||||
|
||||
inline fun <R> safeAutoClose3e(
|
||||
onAbort: (Throwable) -> Unit = { _ -> },
|
||||
onSuccess: () -> Unit = {},
|
||||
onCrossReturn: () -> Unit = {},
|
||||
action: () -> R
|
||||
): R {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
|
||||
callsInPlace(onAbort, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
|
||||
callsInPlace(onCrossReturn, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
|
||||
val ret: R
|
||||
var wasError = false
|
||||
var crossReturned = true
|
||||
try {
|
||||
ret = action()
|
||||
crossReturned = false
|
||||
} catch (e1: Throwable) {
|
||||
wasError = true
|
||||
try {
|
||||
onAbort(e1)
|
||||
} catch (e2: Throwable) {
|
||||
e1.addSuppressed(e2)
|
||||
}
|
||||
throw e1
|
||||
} finally {
|
||||
if (!wasError) {
|
||||
if (crossReturned)
|
||||
onCrossReturn()
|
||||
else
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
@ -24,6 +24,7 @@ pluginManagement {
|
||||
|
||||
|
||||
includeBuild("./libs/int-serializers")
|
||||
includeBuild("./libs/highlevel-try-finally")
|
||||
include(":modules:utilities")
|
||||
include(":modules:low-level:c-interop-utilities")
|
||||
include(":modules:low-level:multithreading")
|
||||
|
Loading…
Reference in New Issue
Block a user