Skip to content

Commit

Permalink
Ensure that inline functions only access atomics from the same class (#…
Browse files Browse the repository at this point in the history
…4041)

Calling a function containing atomic operations from a different file results in the failure of Native incremental compilation.

Made BufferedChannel#sendImpl function private.

This is a WA for KT-65554
  • Loading branch information
mvicsokolova committed Mar 11, 2024
1 parent c990f59 commit 29e8213
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 22 deletions.
25 changes: 24 additions & 1 deletion kotlinx-coroutines-core/common/src/channels/BufferedChannel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ internal open class BufferedChannel<E>(
/**
* Abstract send implementation.
*/
protected inline fun <R> sendImpl(
private inline fun <R> sendImpl(
/* The element to be sent. */
element: E,
/* The waiter to be stored in case of suspension,
Expand Down Expand Up @@ -350,6 +350,29 @@ internal open class BufferedChannel<E>(
}
}

// Note: this function is temporarily moved from ConflatedBufferedChannel to BufferedChannel class, because of this issue: KT-65554.
// For now, an inline function, which invokes atomic operations, may only be called within a parent class.
protected fun trySendDropOldest(element: E): ChannelResult<Unit> =
sendImpl( // <-- this is an inline function
element = element,
// Put the element into the logical buffer even
// if this channel is already full, the `onSuspend`
// callback below extract the first (oldest) element.
waiter = BUFFERED,
// Finish successfully when a rendezvous has happened
// or the element has been buffered.
onRendezvousOrBuffered = { return success(Unit) },
// In case the algorithm decided to suspend, the element
// was added to the buffer. However, as the buffer is now
// overflowed, the first (oldest) element has to be extracted.
onSuspend = { segm, i ->
dropFirstElementUntilTheSpecifiedCellIsInTheBuffer(segm.id * SEGMENT_SIZE + i)
return success(Unit)
},
// If the channel is closed, return the corresponding result.
onClosed = { return closed(sendException) }
)

private inline fun sendImplOnNoWaiter(
/* The working cell is specified by
the segment and the index in it. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,6 @@ internal open class ConflatedBufferedChannel<E>(
return success(Unit)
}

private fun trySendDropOldest(element: E): ChannelResult<Unit> =
sendImpl( // <-- this is an inline function
element = element,
// Put the element into the logical buffer even
// if this channel is already full, the `onSuspend`
// callback below extract the first (oldest) element.
waiter = BUFFERED,
// Finish successfully when a rendezvous has happened
// or the element has been buffered.
onRendezvousOrBuffered = { return success(Unit) },
// In case the algorithm decided to suspend, the element
// was added to the buffer. However, as the buffer is now
// overflowed, the first (oldest) element has to be extracted.
onSuspend = { segm, i ->
dropFirstElementUntilTheSpecifiedCellIsInTheBuffer(segm.id * SEGMENT_SIZE + i)
return success(Unit)
},
// If the channel is closed, return the corresponding result.
onClosed = { return closed(sendException) }
)

@Suppress("UNCHECKED_CAST")
override fun registerSelectForSend(select: SelectInstance<*>, element: Any?) {
// The plain `send(..)` operation never suspends. Thus, either this
Expand Down

0 comments on commit 29e8213

Please sign in to comment.