Преглед на файлове

[core] Review atomic calls and enable atomicfu compiler. Close #2315

Him188 преди 3 години
родител
ревизия
564a7ce8f8
променени са 33 файла, в които са добавени 232 реда и са изтрити 131 реда
  1. 1 2
      mirai-core-api/build.gradle.kts
  2. 0 2
      mirai-core-api/src/commonMain/kotlin/event/events/friend.kt
  3. 0 7
      mirai-core-api/src/commonMain/kotlin/event/events/group.kt
  4. 0 1
      mirai-core-utils/build.gradle.kts
  5. 50 0
      mirai-core-utils/src/commonMain/kotlin/AtomicInteger.kt
  6. 1 2
      mirai-core/build.gradle.kts
  7. 2 32
      mirai-core/src/commonMain/kotlin/MiraiImpl.kt
  8. 13 1
      mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
  9. 2 2
      mirai-core/src/commonMain/kotlin/message/source/MessageSourceInternal.kt
  10. 25 5
      mirai-core/src/commonMain/kotlin/message/source/incomingSourceImpl.kt
  11. 4 3
      mirai-core/src/commonMain/kotlin/message/source/offlineSourceImpl.kt
  12. 29 5
      mirai-core/src/commonMain/kotlin/message/source/outgoingSourceImpl.kt
  13. 2 2
      mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt
  14. 1 1
      mirai-core/src/commonMain/kotlin/network/components/ConfigPushProcessor.kt
  15. 17 3
      mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt
  16. 6 2
      mirai-core/src/commonMain/kotlin/network/components/SyncController.kt
  17. 1 1
      mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt
  18. 5 2
      mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt
  19. 1 1
      mirai-core/src/commonMain/kotlin/network/highway/ChunkedFlowSession.kt
  20. 1 4
      mirai-core/src/commonMain/kotlin/network/highway/Highway.kt
  21. 2 2
      mirai-core/src/commonMain/kotlin/network/notice/group/GroupNotificationProcessor.kt
  22. 16 13
      mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt
  23. 10 9
      mirai-core/src/commonMain/kotlin/utils/AtomicIntSeq.kt
  24. 2 1
      mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt
  25. 6 6
      mirai-core/src/commonTest/kotlin/event/EventTests.kt
  26. 3 3
      mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt
  27. 10 1
      mirai-core/src/commonTest/kotlin/network/framework/components/TestSsoProcessor.kt
  28. 1 1
      mirai-core/src/commonTest/kotlin/network/handler/SelectorRecoveryTest.kt
  29. 4 3
      mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt
  30. 10 8
      mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHEventTest.kt
  31. 3 3
      mirai-core/src/commonTest/kotlin/network/impl/common/SendPacketTest.kt
  32. 1 1
      mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt
  33. 3 2
      mirai-core/src/jvmBaseTest/kotlin/event/SimpleListenerHostTestJava.kt

+ 1 - 2
mirai-core-api/build.gradle.kts

@@ -14,7 +14,7 @@ plugins {
     kotlin("multiplatform")
     kotlin("plugin.serialization")
 
-    //id("kotlinx-atomicfu")
+    id("kotlinx-atomicfu")
     id("signing")
     id("me.him188.kotlin-jvm-blocking-bridge")
     id("me.him188.kotlin-dynamic-delegation")
@@ -43,7 +43,6 @@ kotlin {
                 implementation(project(":mirai-core-utils"))
                 implementation(project(":mirai-console-compiler-annotations"))
                 implementation(`kotlinx-serialization-protobuf`)
-                implementation(`kotlinx-atomicfu`)
                 implementation(`ktor-io`)
             }
         }

+ 0 - 2
mirai-core-api/src/commonMain/kotlin/event/events/friend.kt

@@ -86,8 +86,6 @@ public data class NewFriendRequestEvent @MiraiInternalApi public constructor(
      */
     public val fromNick: String,
 ) : BotEvent, Packet, AbstractEvent(), FriendInfoChangeEvent {
-    internal val responded: AtomicBoolean = atomic(false)
-
     /**
      * @return 申请人来自的群. 当申请人来自其他途径申请时为 `null`
      */

+ 0 - 7
mirai-core-api/src/commonMain/kotlin/event/events/group.kt

@@ -16,8 +16,6 @@
 
 package net.mamoe.mirai.event.events
 
-import kotlinx.atomicfu.AtomicBoolean
-import kotlinx.atomicfu.atomic
 import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.Mirai
@@ -357,8 +355,6 @@ public data class BotInvitedJoinGroupRequestEvent @MiraiInternalApi constructor(
      */
     public val invitor: Friend? get() = this.bot.getFriend(invitorId)
 
-    internal val responded: AtomicBoolean = atomic(false)
-
     @JvmBlockingBridge
     public suspend fun accept(): Unit = Mirai.acceptInvitedJoinGroupRequest(this)
 
@@ -369,7 +365,6 @@ public data class BotInvitedJoinGroupRequestEvent @MiraiInternalApi constructor(
 /**
  * 一个账号请求加入群事件, [Bot] 在此群中是管理员或群主.
  */
-@Suppress("DEPRECATION")
 public data class MemberJoinRequestEvent @MiraiInternalApi constructor(
     override val bot: Bot,
     /**
@@ -405,8 +400,6 @@ public data class MemberJoinRequestEvent @MiraiInternalApi constructor(
      */
     public val invitor: NormalMember? by lazy { invitorId?.let { group?.get(it) } }
 
-    internal val responded: AtomicBoolean = atomic(false)
-
     /**
      * 同意这个请求
      */

+ 0 - 1
mirai-core-utils/build.gradle.kts

@@ -35,7 +35,6 @@ kotlin {
                 api(`kotlinx-serialization-json`)
                 api(`kotlinx-coroutines-core`)
 
-                implementation(`kotlinx-atomicfu`)
                 implementation(`kotlinx-serialization-protobuf`)
                 implementation(`ktor-io`)
             }

+ 50 - 0
mirai-core-utils/src/commonMain/kotlin/AtomicInteger.kt

@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019-2022 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/dev/LICENSE
+ */
+
+package net.mamoe.mirai.utils
+
+import kotlinx.atomicfu.atomic
+
+/**
+ * Wraps a [atomic] to allow more complicated usages.
+ */
+@TestOnly
+public class AtomicInteger(
+    value: Int
+) {
+    private val delegate = atomic(value)
+
+    public var value: Int
+        get() = delegate.value
+        set(value) {
+            delegate.value = value
+        }
+
+    public fun compareAndSet(expect: Int, update: Int): Boolean = delegate.compareAndSet(expect, update)
+    public fun getAndIncrement(): Int = delegate.getAndIncrement()
+    public fun incrementAndGet(): Int = delegate.incrementAndGet()
+}
+
+/**
+ * Wraps a [atomic] to allow more complicated usages.
+ */
+@TestOnly
+public class AtomicBoolean(
+    value: Boolean
+) {
+    private val delegate = atomic(value)
+
+    public var value: Boolean
+        get() = delegate.value
+        set(value) {
+            delegate.value = value
+        }
+
+    public fun compareAndSet(expect: Boolean, update: Boolean): Boolean = delegate.compareAndSet(expect, update)
+}

+ 1 - 2
mirai-core/build.gradle.kts

@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
 
 plugins {
     kotlin("multiplatform")
-    // id("kotlinx-atomicfu")
+    id("kotlinx-atomicfu")
     kotlin("plugin.serialization")
     id("me.him188.kotlin-jvm-blocking-bridge")
     id("me.him188.kotlin-dynamic-delegation")
@@ -42,7 +42,6 @@ kotlin {
 
                 implementation(project(":mirai-core-utils"))
                 implementation(`kotlinx-serialization-protobuf`)
-                implementation(`kotlinx-atomicfu`)
                 implementation(`ktor-io`)
                 implementation(`ktor-client-core`)
             }

+ 2 - 32
mirai-core/src/commonMain/kotlin/MiraiImpl.kt

@@ -93,15 +93,9 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
 
     override var FileCacheStrategy: FileCacheStrategy = net.mamoe.mirai.utils.FileCacheStrategy.PlatformDefault
 
-    @Suppress("PrivatePropertyName")
     private val httpClient: HttpClient = createDefaultHttpClient()
 
     override suspend fun acceptNewFriendRequest(event: NewFriendRequestEvent) {
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $this has already been responded"
-        }
-
         check(!event.bot.friends.contains(event.fromId)) {
             "the request $event is outdated: You had already responded it on another device."
         }
@@ -125,11 +119,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     }
 
     override suspend fun rejectNewFriendRequest(event: NewFriendRequestEvent, blackList: Boolean) {
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $event has already been responded"
-        }
-
         check(!event.bot.friends.contains(event.fromId)) {
             "the request $event is outdated: You had already responded it on another device."
         }
@@ -147,10 +136,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     override suspend fun acceptMemberJoinRequest(event: MemberJoinRequestEvent) {
         @Suppress("DuplicatedCode")
         checkGroupPermission(event.bot, event.groupId) { event::class.simpleName ?: "<anonymous class>" }
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $this has already been responded"
-        }
 
         if (event.group?.contains(event.fromId) == true) return
 
@@ -168,10 +153,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     @Suppress("DuplicatedCode")
     override suspend fun rejectMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean, message: String) {
         checkGroupPermission(event.bot, event.groupId) { event::class.simpleName ?: "<anonymous class>" }
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $this has already been responded"
-        }
 
         if (event.group?.contains(event.fromId) == true) return
 
@@ -222,10 +203,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
 
     override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
         checkGroupPermission(event.bot, event.groupId) { event::class.simpleName ?: "<anonymous class>" }
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $this has already been responded"
-        }
 
         solveMemberJoinRequestEvent(
             bot = event.bot,
@@ -257,11 +234,6 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     }
 
     private suspend fun solveInvitedJoinGroupRequest(event: BotInvitedJoinGroupRequestEvent, accept: Boolean) {
-        @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-        check(event.responded.compareAndSet(false, true)) {
-            "the request $this has already been responded"
-        }
-
         check(!event.bot.groups.contains(event.groupId)) {
             "the request $this is outdated: Bot has been already in the group."
         }
@@ -391,14 +363,12 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         return response is PbMessageSvc.PbMsgWithDraw.Response.Success
     }
 
-    @Suppress("RemoveExplicitTypeArguments") // false positive
     override suspend fun recallMessage(bot: Bot, source: MessageSource) = bot.asQQAndroidBot().run {
         check(source is MessageSourceInternal)
 
         source.ensureSequenceIdAvailable()
 
-        @Suppress("BooleanLiteralArgument", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER") // false positive
-        check(!source.isRecalledOrPlanned.value && source.isRecalledOrPlanned.compareAndSet(false, true)) {
+        check(!source.isRecalledOrPlanned && source.setRecalled()) {
             "$source had already been recalled."
         }
 
@@ -649,7 +619,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
     override fun createUnsupportedMessage(struct: ByteArray): UnsupportedMessage =
         UnsupportedMessageImpl(struct.loadAs(ImMsgBody.Elem.serializer()))
 
-    @Suppress("DEPRECATION", "OverridingDeprecatedMember")
+    @Suppress("OverridingDeprecatedMember")
     override suspend fun queryImageUrl(bot: Bot, image: Image): String = when (image) {
         is ConstOriginUrlAware -> image.originUrl
         is DeferredOriginUrlAware -> image.getUrl(bot)

+ 13 - 1
mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt

@@ -12,6 +12,7 @@
 
 package net.mamoe.mirai.internal.contact
 
+import kotlinx.atomicfu.AtomicRef
 import kotlinx.atomicfu.atomic
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.LowLevelApi
@@ -149,7 +150,18 @@ internal abstract class CommonGroupImpl constructor(
 
     final override val files: RemoteFiles by lazy { RemoteFilesImpl(this) }
 
-    val lastTalkative = atomic(members.find { GroupHonorType.TALKATIVE in it.active.honors })
+
+    private val _lastTalkative: AtomicRef<NormalMemberImpl?> = atomic(null)
+
+    init {
+        // Cannot move to argument of `atomic`, compiler error.
+        val value = members.find { GroupHonorType.TALKATIVE in it.active.honors }
+        _lastTalkative.value = value
+    }
+
+    val lastTalkative get() = _lastTalkative.value
+    fun casLastTalkative(expect: NormalMemberImpl?, update: NormalMemberImpl?): Boolean =
+        _lastTalkative.compareAndSet(expect, update)
 
     final override val announcements: Announcements by lazy {
         AnnouncementsImpl(

+ 2 - 2
mirai-core/src/commonMain/kotlin/message/source/MessageSourceInternal.kt

@@ -9,7 +9,6 @@
 
 package net.mamoe.mirai.internal.message.source
 
-import kotlinx.atomicfu.AtomicBoolean
 import kotlinx.serialization.Transient
 import net.mamoe.mirai.contact.Contact
 import net.mamoe.mirai.internal.message.LightMessageRefiner.dropMiraiInternalFlags
@@ -37,7 +36,8 @@ internal interface MessageSourceInternal : MessageMetadata {
     val ids: IntArray
 
     @Transient
-    val isRecalledOrPlanned: AtomicBoolean
+    val isRecalledOrPlanned: Boolean
+    fun setRecalled(): Boolean // CAS
 
     fun toJceData(): ImMsgBody.SourceMsg
 

+ 25 - 5
mirai-core/src/commonMain/kotlin/message/source/incomingSourceImpl.kt

@@ -11,7 +11,6 @@
 
 package net.mamoe.mirai.internal.message.source
 
-import kotlinx.atomicfu.AtomicBoolean
 import kotlinx.atomicfu.atomic
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.Serializable
@@ -50,7 +49,12 @@ internal class OnlineMessageSourceFromFriendImpl(
     object Serializer : KSerializer<MessageSource> by MessageSourceSerializerImpl("OnlineMessageSourceFromFriend")
 
     override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq }
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
     override val ids: IntArray get() = sequenceIds // msg.msgBody.richText.attr!!.random
     override val internalIds: IntArray = msg.mapToIntArray {
         it.msgBody.richText.attr?.random ?: 0
@@ -83,7 +87,13 @@ internal class OnlineMessageSourceFromStrangerImpl(
     object Serializer : KSerializer<MessageSource> by MessageSourceSerializerImpl("OnlineMessageSourceFromStranger")
 
     override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq }
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
     override val ids: IntArray get() = sequenceIds // msg.msgBody.richText.attr!!.random
     override val internalIds: IntArray = msg.mapToIntArray {
         it.msgBody.richText.attr?.random ?: 0
@@ -156,7 +166,13 @@ internal class OnlineMessageSourceFromTempImpl(
 
     override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq }
     override val internalIds: IntArray = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
     override val ids: IntArray get() = sequenceIds //
     override val time: Int = msg.first().msgHead.msgTime
     override var originalMessageLazy = lazy {
@@ -191,8 +207,12 @@ internal class OnlineMessageSourceFromGroupImpl(
 ) : OnlineMessageSource.Incoming.FromGroup(), IncomingMessageSourceInternal {
     object Serializer : KSerializer<MessageSource> by MessageSourceSerializerImpl("OnlineMessageSourceFromGroupImpl")
 
+
+    private val _isRecalledOrPlanned = atomic(false)
+
     @Transient
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
     override val sequenceIds: IntArray = msg.mapToIntArray { it.msgHead.msgSeq }
     override val internalIds: IntArray = msg.mapToIntArray { it.msgBody.richText.attr!!.random }
     override val ids: IntArray get() = sequenceIds

+ 4 - 3
mirai-core/src/commonMain/kotlin/message/source/offlineSourceImpl.kt

@@ -10,7 +10,6 @@
 
 package net.mamoe.mirai.internal.message.source
 
-import kotlinx.atomicfu.AtomicBoolean
 import kotlinx.atomicfu.atomic
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.Serializable
@@ -60,9 +59,11 @@ internal class OfflineMessageSourceImplData(
     @Transient
     var jceData: ImMsgBody.SourceMsg? = null
 
+    private val _isRecalledOrPlanned = atomic(false)
+
     @Transient
-    @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
 
     override fun toJceData(): ImMsgBody.SourceMsg {
         return jceData ?: ImMsgBody.SourceMsg(

+ 29 - 5
mirai-core/src/commonMain/kotlin/message/source/outgoingSourceImpl.kt

@@ -11,11 +11,11 @@
 
 package net.mamoe.mirai.internal.message.source
 
-import kotlinx.atomicfu.AtomicBoolean
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.*
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.Serializable
+import kotlinx.serialization.Transient
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.event.EventPriority
@@ -98,7 +98,13 @@ internal class OnlineMessageSourceToFriendImpl(
         get() = sender
     override val ids: IntArray
         get() = sequenceIds
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
     private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 
@@ -131,7 +137,13 @@ internal class OnlineMessageSourceToStrangerImpl(
         get() = sender
     override val ids: IntArray
         get() = sequenceIds
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
     private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 
@@ -164,7 +176,13 @@ internal class OnlineMessageSourceToTempImpl(
         get() = sender
     override val ids: IntArray
         get() = sequenceIds
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
     private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 
@@ -193,7 +211,13 @@ internal class OnlineMessageSourceToGroupImpl(
         get() = sequenceIds
     override val bot: Bot
         get() = sender
-    override var isRecalledOrPlanned: AtomicBoolean = atomic(false)
+
+    private val _isRecalledOrPlanned = atomic(false)
+
+    @Transient
+    override val isRecalledOrPlanned: Boolean = _isRecalledOrPlanned.value
+    override fun setRecalled(): Boolean = _isRecalledOrPlanned.compareAndSet(expect = false, update = true)
+
 
     /**
      * Note that in tests result of this Deferred is always `null`. See TestMessageSourceSequenceIdAwaiter.

+ 2 - 2
mirai-core/src/commonMain/kotlin/network/components/BotInitProcessor.kt

@@ -106,10 +106,10 @@ internal class BotInitProcessorImpl(
             }
 
             state.value = INITIALIZED
-            bot.components[SsoProcessor].firstLoginResult.compareAndSet(null, FirstLoginResult.PASSED)
+            bot.components[SsoProcessor].casFirstLoginResult(null, FirstLoginResult.PASSED)
         } catch (e: Throwable) {
             setLoginHalted()
-            bot.components[SsoProcessor].firstLoginResult.compareAndSet(null, FirstLoginResult.OTHER_FAILURE)
+            bot.components[SsoProcessor].casFirstLoginResult(null, FirstLoginResult.OTHER_FAILURE)
             throw e
         }
     }

+ 1 - 1
mirai-core/src/commonMain/kotlin/network/components/ConfigPushProcessor.kt

@@ -45,7 +45,7 @@ internal class ConfigPushProcessorImpl(
                 val e = IllegalStateException("Timeout waiting for ConfigPush.")
                 bdhSyncer.bdhSession.completeExceptionally(e)
                 logger.warning { "Missing ConfigPush. Switching server..." }
-                network.context[SsoProcessor].firstLoginResult.compareAndSet(null, FirstLoginResult.CHANGE_SERVER)
+                network.context[SsoProcessor].casFirstLoginResult(null, FirstLoginResult.CHANGE_SERVER)
                 network.context.bot.components[EventDispatcher].broadcastAsync(
                     BotOfflineEvent.RequireReconnect(
                         network.context.bot,

+ 17 - 3
mirai-core/src/commonMain/kotlin/network/components/SsoProcessor.kt

@@ -44,8 +44,15 @@ internal interface SsoProcessor {
     val client: QQAndroidClient
     val ssoSession: SsoSession
 
-    val firstLoginResult: AtomicRef<FirstLoginResult?> // null means just initialized
-    val firstLoginSucceed: Boolean get() = firstLoginResult.value?.success ?: false
+    val firstLoginResult: FirstLoginResult? // null means just initialized
+    fun casFirstLoginResult(
+        expect: FirstLoginResult?,
+        update: FirstLoginResult?
+    ): Boolean // enable compiler optimization
+
+    fun setFirstLoginResult(value: FirstLoginResult?)
+
+    val firstLoginSucceed: Boolean get() = firstLoginResult?.success ?: false
     val registerResp: StatSvc.Register.Response?
 
     /**
@@ -114,7 +121,14 @@ internal class SsoProcessorImpl(
     // public
     ///////////////////////////////////////////////////////////////////////////
 
-    override val firstLoginResult: AtomicRef<FirstLoginResult?> = atomic(null)
+    private val _firstLoginResult: AtomicRef<FirstLoginResult?> = atomic(null)
+    override val firstLoginResult = _firstLoginResult.value
+    override fun casFirstLoginResult(expect: FirstLoginResult?, update: FirstLoginResult?): Boolean =
+        _firstLoginResult.compareAndSet(expect, update)
+
+    override fun setFirstLoginResult(value: FirstLoginResult?) {
+        _firstLoginResult.value = value
+    }
 
     @Volatile
     override var registerResp: StatSvc.Register.Response? = null

+ 6 - 2
mirai-core/src/commonMain/kotlin/network/components/SyncController.kt

@@ -23,7 +23,9 @@ import net.mamoe.mirai.utils.currentTimeSeconds
 import kotlin.jvm.Volatile
 
 internal interface SyncController {
-    val firstNotify: AtomicBoolean
+    val firstNotify: Boolean
+    fun casFirstNotify(expect: Boolean, update: Boolean): Boolean
+
     var latestMsgNewGroupTime: Long
     var latestMsgNewFriendTime: Long
 
@@ -69,7 +71,9 @@ internal fun SyncController.syncOnlinePush(
 )
 
 internal class SyncControllerImpl : SyncController {
-    override val firstNotify: AtomicBoolean = atomic(true)
+    private val _firstNotify: AtomicBoolean = atomic(true)
+    override val firstNotify get() = _firstNotify.value
+    override fun casFirstNotify(expect: Boolean, update: Boolean): Boolean = _firstNotify.compareAndSet(expect, update)
 
     @Volatile
     override var latestMsgNewGroupTime: Long = currentTimeSeconds()

+ 1 - 1
mirai-core/src/commonMain/kotlin/network/handler/CommonNetworkHandler.kt

@@ -253,7 +253,7 @@ internal abstract class CommonNetworkHandler<Conn>(
                     [email protected] { resumeConnection() } // go to next state.
                 } else {
                     // failed in SSO stage
-                    context[SsoProcessor].firstLoginResult.compareAndSet(null, FirstLoginResult.OTHER_FAILURE)
+                    context[SsoProcessor].casFirstLoginResult(null, FirstLoginResult.OTHER_FAILURE)
 
                     if (error is CancellationException) {
                         // CancellationException is either caused by parent cancellation or manual `connectResult.cancel`.

+ 5 - 2
mirai-core/src/commonMain/kotlin/network/handler/selector/AbstractKeepAliveNetworkHandlerSelector.kt

@@ -119,7 +119,7 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
             lastNetwork = current
 
             if (current != null) {
-                if (current.context[SsoProcessor].firstLoginResult.value?.canRecoverOnFirstLogin == false) {
+                if (current.context[SsoProcessor].firstLoginResult?.canRecoverOnFirstLogin == false) {
                     // == null 只表示
                     // == false 表示第一次登录失败, 且此失败没必要重试
                     logIfEnabled { "[FIRST LOGIN ERROR] current = $current" }
@@ -176,7 +176,7 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
                         // This may return false, meaning the error causing the state to be CLOSED is recoverable.
                         // Otherwise, it throws, meaning it is unrecoverable.
 
-                        if (this@AbstractKeepAliveNetworkHandlerSelector.current.compareAndSet(current, null)) {
+                        if (compareAndSetCurrent(current, null)) {
                             logIfEnabled { "... Set current to null." }
                             // invalidate the instance and try again.
 
@@ -233,6 +233,9 @@ internal abstract class AbstractKeepAliveNetworkHandlerSelector<H : NetworkHandl
         }
     }
 
+    private fun compareAndSetCurrent(expect: H?, update: H?) =
+        current.compareAndSet(expect, update) // to enable compiler optimization
+
     private val lock = SynchronizedObject()
     protected open fun refreshInstance() {
         synchronized(lock) { // avoid concurrent `createInstance()`

+ 1 - 1
mirai-core/src/commonMain/kotlin/network/highway/ChunkedFlowSession.kt

@@ -30,7 +30,7 @@ internal class ChunkedFlowSession<T>(
         input.close()
     }
 
-    private var offset = atomic(0L)
+    private val offset = atomic(0L)
 
     internal suspend inline fun useAll(crossinline block: suspend (T) -> Unit) {
         contract { callsInPlace(block, InvocationKind.UNKNOWN) }

+ 1 - 4
mirai-core/src/commonMain/kotlin/network/highway/Highway.kt

@@ -10,7 +10,6 @@
 package net.mamoe.mirai.internal.network.highway
 
 import io.ktor.utils.io.core.*
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.*
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.channels.ReceiveChannel
@@ -381,8 +380,6 @@ internal fun highwayPacketSession(
     ByteArrayPool.checkBufferSize(sizePerPacket)
     //   require(ticket.size == 128) { "bad uKey. Required size=128, got ${ticket.size}" }
 
-    val ticket = atomic(initialTicket)
-
     return ChunkedFlowSession(data.input(), ByteArray(sizePerPacket), callback) { buffer, size, offset ->
         val head = CSDataHighwayHead.ReqDataHighwayHead(
             msgBasehead = CSDataHighwayHead.DataHighwayHead(
@@ -401,7 +398,7 @@ internal fun highwayPacketSession(
                 datalength = size,
                 dataoffset = offset,
                 filesize = data.size,
-                serviceticket = ticket.value,
+                serviceticket = initialTicket,
                 md5 = buffer.md5(0, size),
                 fileMd5 = fileMd5,
                 flag = 0,

+ 2 - 2
mirai-core/src/commonMain/kotlin/network/notice/group/GroupNotificationProcessor.kt

@@ -363,9 +363,9 @@ internal class GroupNotificationProcessor(
                 val now = grayTip.msgTemplParam["uin"]?.findMember() ?: group.botAsMember
                 val previous = grayTip.msgTemplParam["uin_last"]?.findMember()
 
-                val lastTalkative = group.lastTalkative.value
+                val lastTalkative = group.lastTalkative
                 if (lastTalkative == now) return // duplicate
-                if (!group.lastTalkative.compareAndSet(lastTalkative, now)) return
+                if (!group.casLastTalkative(lastTalkative, now)) return
 
                 if (previous == null) {
                     collect(MemberHonorChangeEvent.Achieve(now, GroupHonorType.TALKATIVE))

+ 16 - 13
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PushNotify.kt

@@ -10,7 +10,6 @@
 package net.mamoe.mirai.internal.network.protocol.packet.chat.receive
 
 import io.ktor.utils.io.core.*
-import kotlinx.atomicfu.loop
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.network.components.SyncController.Companion.syncController
 import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushNotify
@@ -30,19 +29,23 @@ internal object MessageSvcPushNotify : IncomingPacketFactory<RequestPushNotify>(
     }
 
     override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket {
-        syncController.firstNotify.loop { firstNotify ->
-            network.run {
-                return MessageSvcPbGetMsg(
-                    client,
-                    MsgSvc.SyncFlag.START,
-                    if (firstNotify) {
-                        if (!syncController.firstNotify.compareAndSet(firstNotify, false)) {
-                            return@loop
-                        }
-                        null
-                    } else packet.vNotifyCookie,
-                )
+        while (true) {
+            val firstNotify = syncController.firstNotify
+
+            val cookie = if (firstNotify) {
+                if (!syncController.casFirstNotify(firstNotify, false)) {
+                    continue
+                }
+                null
+            } else {
+                packet.vNotifyCookie
             }
+
+            return MessageSvcPbGetMsg(
+                client,
+                MsgSvc.SyncFlag.START,
+                cookie,
+            )
         }
     }
 }

+ 10 - 9
mirai-core/src/commonMain/kotlin/utils/AtomicIntSeq.kt

@@ -16,23 +16,23 @@ import kotlinx.atomicfu.AtomicInt
 import kotlinx.atomicfu.atomic
 import kotlinx.atomicfu.update
 import net.mamoe.mirai.utils.getRandomUnsignedInt
-import kotlin.jvm.JvmInline
 import kotlin.jvm.JvmStatic
 
 internal object AtomicIntSeq {
     @JvmStatic
-    inline fun forMessageSeq(): AtomicIntMaxSeq = AtomicIntMaxSeq(atomic(0))
+    fun forMessageSeq(): AtomicIntMaxSeq = AtomicIntMaxSeq(0)
 
     @JvmStatic
-    inline fun forPrivateSync(): AtomicInt65535Seq = AtomicInt65535Seq(atomic(getRandomUnsignedInt()))
+    fun forPrivateSync(): AtomicInt65535Seq = AtomicInt65535Seq(getRandomUnsignedInt())
 }
 
 // value classes to optimize space
 
-@JvmInline
-internal value class AtomicIntMaxSeq(
-    private val value: AtomicInt
+internal class AtomicIntMaxSeq(
+    value: Int
 ) {
+    private val value: AtomicInt = atomic(value)
+
     /**
      * Increment [value] within the range from `0` (inclusive) to [Int.MAX_VALUE] (exclusive).
      */
@@ -64,10 +64,11 @@ internal value class AtomicIntMaxSeq(
     }
 }
 
-@JvmInline
-internal value class AtomicInt65535Seq(
-    private val value: AtomicInt = atomic(0)
+internal class AtomicInt65535Seq(
+    value: Int
 ) {
+    private val value: AtomicInt = atomic(value)
+
     /**
      * Increment [value] within the range from `0` (inclusive) to `65535` (exclusive).
      */

+ 2 - 1
mirai-core/src/commonTest/kotlin/ScheduledJobTest.kt

@@ -15,6 +15,7 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.internal.test.AbstractTest
 import net.mamoe.mirai.internal.utils.ScheduledJob
+import net.mamoe.mirai.utils.AtomicInteger
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
@@ -25,7 +26,7 @@ internal class ScheduledJobTest : AbstractTest() {
             val scope = CoroutineScope(CoroutineExceptionHandler { _, throwable ->
                 throwable.printStackTrace()
             })
-            val invoked = atomic(0)
+            val invoked = AtomicInteger(0)
             val job = ScheduledJob(scope.coroutineContext, 1000) {
                 invoked.incrementAndGet()
             }

+ 6 - 6
mirai-core/src/commonTest/kotlin/event/EventTests.kt

@@ -9,10 +9,10 @@
 
 package net.mamoe.mirai.internal.event
 
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.*
 import kotlinx.coroutines.test.runTest
 import net.mamoe.mirai.event.*
+import net.mamoe.mirai.utils.AtomicInteger
 import net.mamoe.mirai.utils.childScope
 import kotlin.coroutines.EmptyCoroutineContext
 import kotlin.test.AfterTest
@@ -61,7 +61,7 @@ internal class EventTests : AbstractEventTest() {
     fun `test concurrent listening`() {
         resetEventListeners()
         var listeners = 0
-        val counter = atomic(0)
+        val counter = AtomicInteger(0)
         val channel = scope.globalEventChannel()
         for (p in EventPriority.values()) {
             repeat(2333) {
@@ -85,8 +85,8 @@ internal class EventTests : AbstractEventTest() {
     fun `test concurrent listening 3`() {
         resetEventListeners()
         runBlocking {
-            val called = atomic(0)
-            val registered = atomic(0)
+            val called = AtomicInteger(0)
+            val registered = AtomicInteger(0)
             coroutineScope {
                 println("Step 0")
                 for (priority in EventPriority.values()) {
@@ -116,8 +116,8 @@ internal class EventTests : AbstractEventTest() {
     @Test
     fun `test concurrent listening 2`() = runTest {
         resetEventListeners()
-        val registered = atomic(0)
-        val called = atomic(0)
+        val registered = AtomicInteger(0)
+        val called = AtomicInteger(0)
 
         val supervisor = CoroutineScope(SupervisorJob())
 

+ 3 - 3
mirai-core/src/commonTest/kotlin/network/framework/AbstractRealNetworkHandlerTest.kt

@@ -151,7 +151,7 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
             override suspend fun init() {
                 nhEvents.add(NHEvent.Init)
                 networkLogger.debug { "BotInitProcessor.init" }
-                bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+                bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
             }
         })
         set(ServerList, ServerListImpl())
@@ -207,9 +207,9 @@ internal abstract class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abs
 
     val eventDispatcher get() = bot.components[EventDispatcher]
     var firstLoginResult: FirstLoginResult?
-        get() = bot.components[SsoProcessor].firstLoginResult.value
+        get() = bot.components[SsoProcessor].firstLoginResult
         set(value) {
-            bot.components[SsoProcessor].firstLoginResult.value = value
+            bot.components[SsoProcessor].setFirstLoginResult(value)
         }
 }
 

+ 10 - 1
mirai-core/src/commonTest/kotlin/network/framework/components/TestSsoProcessor.kt

@@ -36,7 +36,16 @@ internal open class TestSsoProcessor(private val bot: QQAndroidBot) : SsoProcess
         )
     }
     override val ssoSession: SsoSession get() = bot.client
-    override val firstLoginResult: AtomicRef<FirstLoginResult?> = atomic(null)
+    private val _firstLoginResult: AtomicRef<FirstLoginResult?> = atomic(null)
+    override val firstLoginResult get() = _firstLoginResult.value
+    override fun casFirstLoginResult(expect: FirstLoginResult?, update: FirstLoginResult?): Boolean {
+        return _firstLoginResult.compareAndSet(expect, update)
+    }
+
+    override fun setFirstLoginResult(value: FirstLoginResult?) {
+        _firstLoginResult.value = value
+    }
+
     override var registerResp: StatSvc.Register.Response? = null
     override suspend fun login(handler: NetworkHandler) {
         bot.network.logger.debug { "SsoProcessor.login" }

+ 1 - 1
mirai-core/src/commonTest/kotlin/network/handler/SelectorRecoveryTest.kt

@@ -53,7 +53,7 @@ internal class SelectorRecoveryTest : AbstractCommonNHTestWithSelector() {
                 throwExceptionOnLogin?.invoke()
             }
         }.apply {
-            firstLoginResult.value = FirstLoginResult.PASSED
+            setFirstLoginResult(FirstLoginResult.PASSED)
         }
     }
 

+ 4 - 3
mirai-core/src/commonTest/kotlin/network/handler/StandaloneSelectorTests.kt

@@ -18,6 +18,7 @@ import net.mamoe.mirai.internal.network.framework.TestCommonNetworkHandler
 import net.mamoe.mirai.internal.network.handler.selector.MaxAttemptsReachedException
 import net.mamoe.mirai.internal.network.handler.selector.NetworkException
 import net.mamoe.mirai.internal.test.runBlockingUnit
+import net.mamoe.mirai.utils.AtomicInteger
 import kotlin.test.*
 
 /**
@@ -59,8 +60,8 @@ internal class StandaloneSelectorTests : AbstractCommonNHTest() {
     // Since #1963, any error during first login will close the bot. So we assume first login succeed to do our test.
     @BeforeTest
     private fun setFirstLoginPassed() {
-        assertEquals(null, bot.components[SsoProcessor].firstLoginResult.value)
-        bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+        assertEquals(null, bot.components[SsoProcessor].firstLoginResult)
+        bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
     }
 
     @Test
@@ -79,7 +80,7 @@ internal class StandaloneSelectorTests : AbstractCommonNHTest() {
     @Test
     fun `NetworkException does not cause retrying if recoverable=false`() = runBlockingUnit {
         // selector should not tolerant any exception during state initialization, or in the Jobs launched in states.
-        val times = atomic(0)
+        val times = AtomicInteger(0)
         val theException = object : NetworkException(false) {}
         throwExceptionOnConnecting = {
             times.incrementAndGet()

+ 10 - 8
mirai-core/src/commonTest/kotlin/network/impl/common/CommonNHEventTest.kt

@@ -50,7 +50,7 @@ internal class CommonNHEventTest : AbstractCommonNHTest() {
     fun `BotOnlineEvent after successful reconnection`() = runBlockingUnit {
         assertEquals(INITIALIZED, network.state)
         bot.login()
-        bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+        bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
         assertEquals(OK, network.state)
         eventDispatcher.joinBroadcast() // `login` launches a job which broadcasts the event
         assertEventBroadcasts<BotOnlineEvent>(1) {
@@ -65,7 +65,7 @@ internal class CommonNHEventTest : AbstractCommonNHTest() {
     fun `BotOfflineEvent after successful reconnection`() = runBlockingUnit {
         assertEquals(INITIALIZED, network.state)
         bot.login()
-        bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+        bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
         assertEquals(OK, network.state)
         eventDispatcher.joinBroadcast() // `login` launches a job which broadcasts the event
         assertEventBroadcasts<BotOfflineEvent>(1) {
@@ -95,24 +95,26 @@ internal class CommonNHEventTest : AbstractCommonNHTest() {
 
     @Test
     fun `from CONNECTING TO OK the second time`() = runBlockingUnit {
-        val ok = atomic(CompletableDeferred<Unit>())
+        val ok = object {
+            val v = atomic(CompletableDeferred<Unit>())
+        }
         setSsoProcessor {
-            ok.value.join()
+            ok.v.value.join()
         }
 
         assertState(INITIALIZED)
 
         network.setStateConnecting()
-        ok.value.complete(Unit)
+        ok.v.value.complete(Unit)
         network.resumeConnection()
         assertState(OK)
 
-        ok.value = CompletableDeferred()
+        ok.v.value = CompletableDeferred()
         network.setStateConnecting()
         eventDispatcher.joinBroadcast()
         println("Starting receiving events")
         assertEventBroadcasts<Event>(2) {
-            ok.value.complete(Unit)
+            ok.v.value.complete(Unit)
             network.resumeConnection()
             eventDispatcher.joinBroadcast()
         }.let { event ->
@@ -169,7 +171,7 @@ internal class CommonNHEventTest : AbstractCommonNHTest() {
             assertState(INITIALIZED)
             bot.login()
             assertState(OK)
-            bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+            bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
             network.setStateConnecting()
             network.resumeConnection()
             assertState(OK)

+ 3 - 3
mirai-core/src/commonTest/kotlin/network/impl/common/SendPacketTest.kt

@@ -10,7 +10,6 @@
 package net.mamoe.mirai.internal.network.impl.common
 
 import io.ktor.utils.io.core.*
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.yield
@@ -19,6 +18,7 @@ import net.mamoe.mirai.internal.network.framework.AbstractCommonNHTest
 import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.test.runBlockingUnit
+import net.mamoe.mirai.utils.AtomicBoolean
 import kotlin.test.Test
 import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
@@ -29,7 +29,7 @@ internal class SendPacketTest : AbstractCommonNHTest() {
 
     @Test
     fun `sendPacketImpl suspends until a valid state`() = runBlockingUnit(singleThreadDispatcher) {
-        val expectStop = atomic(false)
+        val expectStop = AtomicBoolean(false)
 
         // coroutine starts immediately and suspends at `net.mamoe.mirai.internal.network.impl.netty.NettyNetworkHandler.sendPacketImpl`
         launch(singleThreadDispatcher, start = CoroutineStart.UNDISPATCHED) {
@@ -48,7 +48,7 @@ internal class SendPacketTest : AbstractCommonNHTest() {
     @Test
     fun `sendPacketImpl does not suspend if state is valid`() = runBlockingUnit(singleThreadDispatcher) {
         network.setStateOK(conn) // then we can send packet.
-        val expectStop = atomic(false)
+        val expectStop = AtomicBoolean(false)
 
         val job = launch(singleThreadDispatcher, start = CoroutineStart.UNDISPATCHED) {
             assertNotNull(network.sendAndExpect(OutgoingPacket("name", "cmd", 1, ByteReadPacket.Empty)))

+ 1 - 1
mirai-core/src/commonTest/kotlin/notice/processors/AbstractNoticeProcessorTest.kt

@@ -60,7 +60,7 @@ internal abstract class AbstractNoticeProcessorTest : AbstractCommonNHTest(), Gr
         pipeline: NoticeProcessorPipeline = bot.components.noticeProcessorPipeline,
         block: UseTestContext.() -> ProtocolStruct
     ): Collection<Packet> {
-        bot.components[SsoProcessor].firstLoginResult.value = FirstLoginResult.PASSED
+        bot.components[SsoProcessor].setFirstLoginResult(FirstLoginResult.PASSED)
         val handler = LoggingPacketHandlerAdapter(PacketLoggingStrategyImpl(bot), bot.logger)
         val context = UseTestContext(attributes.toMutableTypeSafeMap())
         return pipeline.process(block(context), context.attributes).collected.also { list ->

+ 3 - 2
mirai-core/src/jvmBaseTest/kotlin/event/SimpleListenerHostTestJava.kt

@@ -9,10 +9,10 @@
 
 package net.mamoe.mirai.internal.event
 
-import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.runBlocking
 import net.mamoe.mirai.event.*
+import net.mamoe.mirai.utils.AtomicBoolean
 import net.mamoe.mirai.utils.JavaFriendlyAPI
 import kotlin.coroutines.EmptyCoroutineContext
 import kotlin.test.Test
@@ -23,10 +23,11 @@ import kotlin.test.Test
 internal class SimpleListenerHostTestJava : AbstractEventTest() {
     @Test
     fun testJavaSimpleListenerHostWork() {
-        val called = atomic(false)
+        val called = AtomicBoolean(false)
         val host: SimpleListenerHost = object : SimpleListenerHost() {
             @EventHandler
             @net.mamoe.mirai.utils.EventListenerLikeJava
+            @Suppress("unused")
             fun testListen(
                 event: AbstractEvent?
             ) {