Skip to content

Remove dead-code in the LockFreeLinkedList implementation after new c… #3624

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 1 addition & 41 deletions kotlinx-coroutines-core/common/src/internal/Atomic.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ public abstract class OpDescriptor {
abstract val atomicOp: AtomicOp<*>?

override fun toString(): String = "$classSimpleName@$hexAddress" // debug

fun isEarlierThan(that: OpDescriptor): Boolean {
val thisOp = atomicOp ?: return false
val thatOp = that.atomicOp ?: return false
return thisOp.opSequence < thatOp.opSequence
}
}

@JvmField
Expand All @@ -55,25 +49,9 @@ internal val NO_DECISION: Any = Symbol("NO_DECISION")
public abstract class AtomicOp<in T> : OpDescriptor() {
private val _consensus = atomic<Any?>(NO_DECISION)

// Returns NO_DECISION when there is not decision yet
val consensus: Any? get() = _consensus.value

val isDecided: Boolean get() = _consensus.value !== NO_DECISION

/**
* Sequence number of this multi-word operation for deadlock resolution.
* An operation with lower number aborts itself with (using [RETRY_ATOMIC] error symbol) if it encounters
* the need to help the operation with higher sequence number and then restarts
* (using higher `opSequence` to ensure progress).
* Simple operations that cannot get into the deadlock always return zero here.
*
* See https://github.com/Kotlin/kotlinx.coroutines/issues/504
*/
open val opSequence: Long get() = 0L

override val atomicOp: AtomicOp<*> get() = this

fun decide(decision: Any?): Any? {
private fun decide(decision: Any?): Any? {
assert { decision !== NO_DECISION }
val current = _consensus.value
if (current !== NO_DECISION) return current
Expand All @@ -98,21 +76,3 @@ public abstract class AtomicOp<in T> : OpDescriptor() {
return decision
}
}

/**
* A part of multi-step atomic operation [AtomicOp].
*
* @suppress **This is unstable API and it is subject to change.**
*/
public abstract class AtomicDesc {
lateinit var atomicOp: AtomicOp<*> // the reference to parent atomicOp, init when AtomicOp is created
abstract fun prepare(op: AtomicOp<*>): Any? // returns `null` if prepared successfully
abstract fun complete(op: AtomicOp<*>, failure: Any?) // decision == null if success
}

/**
* It is returned as an error by [AtomicOp] implementations when they detect potential deadlock
* using [AtomicOp.opSequence] numbers.
*/
@JvmField
internal val RETRY_ATOMIC: Any = Symbol("RETRY_ATOMIC")
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,8 @@ public expect open class LockFreeLinkedListNode() {
public fun addLast(node: LockFreeLinkedListNode)
public fun addOneIfEmpty(node: LockFreeLinkedListNode): Boolean
public inline fun addLastIf(node: LockFreeLinkedListNode, crossinline condition: () -> Boolean): Boolean
public inline fun addLastIfPrev(
node: LockFreeLinkedListNode,
predicate: (LockFreeLinkedListNode) -> Boolean
): Boolean

public inline fun addLastIfPrevAndIf(
node: LockFreeLinkedListNode,
predicate: (LockFreeLinkedListNode) -> Boolean, // prev node predicate
crossinline condition: () -> Boolean // atomically checked condition
): Boolean

public open fun remove(): Boolean

/**
* Helps fully finish [remove] operation, must be invoked after [remove] if needed.
* Ensures that traversing the list via prev pointers sees this node as removed.
* No-op on JS
*/
public fun helpRemove()
public fun removeFirstOrNull(): LockFreeLinkedListNode?
public inline fun <reified T> removeFirstIfIsInstanceOfOrPeekIf(predicate: (T) -> Boolean): T?
}

/** @suppress **This is unstable API and it is subject to change.** */
Expand All @@ -45,45 +26,3 @@ public expect open class LockFreeLinkedListHead() : LockFreeLinkedListNode {
public inline fun <reified T : LockFreeLinkedListNode> forEach(block: (T) -> Unit)
public final override fun remove(): Nothing
}

/** @suppress **This is unstable API and it is subject to change.** */
public expect open class AddLastDesc<T : LockFreeLinkedListNode>(
queue: LockFreeLinkedListNode,
node: T
) : AbstractAtomicDesc {
val queue: LockFreeLinkedListNode
val node: T
override fun finishPrepare(prepareOp: PrepareOp)
override fun finishOnSuccess(affected: LockFreeLinkedListNode, next: LockFreeLinkedListNode)
}

/** @suppress **This is unstable API and it is subject to change.** */
public expect open class RemoveFirstDesc<T>(queue: LockFreeLinkedListNode): AbstractAtomicDesc {
val queue: LockFreeLinkedListNode
public val result: T
override fun finishPrepare(prepareOp: PrepareOp)
final override fun finishOnSuccess(affected: LockFreeLinkedListNode, next: LockFreeLinkedListNode)
}

/** @suppress **This is unstable API and it is subject to change.** */
public expect abstract class AbstractAtomicDesc : AtomicDesc {
final override fun prepare(op: AtomicOp<*>): Any?
final override fun complete(op: AtomicOp<*>, failure: Any?)
protected open fun failure(affected: LockFreeLinkedListNode): Any?
protected open fun retry(affected: LockFreeLinkedListNode, next: Any): Boolean
public abstract fun finishPrepare(prepareOp: PrepareOp) // non-null on failure
public open fun onPrepare(prepareOp: PrepareOp): Any? // non-null on failure
public open fun onRemoved(affected: LockFreeLinkedListNode) // non-null on failure
protected abstract fun finishOnSuccess(affected: LockFreeLinkedListNode, next: LockFreeLinkedListNode)
}

/** @suppress **This is unstable API and it is subject to change.** */
public expect class PrepareOp: OpDescriptor {
val affected: LockFreeLinkedListNode
override val atomicOp: AtomicOp<*>
val desc: AbstractAtomicDesc
fun finishPrepare()
}

@JvmField
internal val REMOVE_PREPARED: Any = Symbol("REMOVE_PREPARED")
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ class ChannelUndeliveredElementFailureTest : TestBase() {
fun testSendDropOldestInvokeHandlerConflated() = runTest(expected = { it is UndeliveredElementException }) {
val channel = Channel<Int>(Channel.CONFLATED, onUndeliveredElement = {
finish(2)
println(TestException().stackTraceToString())
throw TestException()
})
channel.send(42)
Expand Down
Loading