Skip to content

Commit 4a4dd46

Browse files
authored
Merge pull request #136 from arkivanov/disable-main-thread-assert-if-main-thread-is-unknown
Disable main thread assert if main thread is unknown
2 parents 10ceee5 + 6a36438 commit 4a4dd46

File tree

6 files changed

+80
-78
lines changed

6 files changed

+80
-78
lines changed

utils-internal/src/androidMain/kotlin/com/arkivanov/mvikotlin/utils/internal/MainThreadAssert.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ package com.arkivanov.mvikotlin.utils.internal
44

55
import android.os.Looper
66

7-
internal actual val isMainThread: Boolean get() = Thread.currentThread().id == Looper.getMainLooper().thread.id
7+
internal actual fun getMainThreadId(): MainThreadId? =
8+
try {
9+
MainThreadId(Looper.getMainLooper().thread.id)
10+
} catch (e: Exception) {
11+
e.printStackTrace()
12+
null
13+
}
814

9-
internal actual val currentThreadDescription: String get() = Thread.currentThread().name
15+
internal actual fun isMainThread(mainThreadId: MainThreadId): Boolean = mainThreadId.id == Thread.currentThread().id
16+
17+
internal actual fun getCurrentThreadDescription(): String = Thread.currentThread().toString()
18+
19+
internal actual class MainThreadId(val id: Long)
Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,55 @@
11
package com.arkivanov.mvikotlin.utils.internal
22

33
import com.badoo.reaktive.utils.atomic.AtomicBoolean
4+
import com.badoo.reaktive.utils.atomic.AtomicReference
5+
import com.badoo.reaktive.utils.atomic.getValue
6+
import com.badoo.reaktive.utils.atomic.setValue
47

5-
@Suppress("ObjectPropertyName")
6-
private val _isAssertOnMainThreadEnabled = AtomicBoolean(true)
7-
var isAssertOnMainThreadEnabled: Boolean
8-
get() = _isAssertOnMainThreadEnabled.value
9-
set(value) {
10-
_isAssertOnMainThreadEnabled.value = value
11-
}
12-
13-
internal expect val isMainThread: Boolean
8+
var isAssertOnMainThreadEnabled: Boolean by AtomicBoolean(true)
149

15-
internal expect val currentThreadDescription: String
10+
private val mainThreadIdRef = AtomicReference<MainThreadIdHolder?>(null)
1611

1712
fun assertOnMainThread() {
1813
if (isAssertOnMainThreadEnabled) {
19-
require(isMainThread) {
20-
"Not on Main thread, current thread is: $currentThreadDescription"
14+
require(isMainThread()) {
15+
"Not on Main thread, current thread is: ${getCurrentThreadDescription()}"
2116
}
2217
}
2318
}
19+
20+
internal expect fun getMainThreadId(): MainThreadId?
21+
22+
internal expect fun isMainThread(mainThreadId: MainThreadId): Boolean
23+
24+
internal expect fun getCurrentThreadDescription(): String
25+
26+
private fun isMainThread(): Boolean {
27+
val mainThreadId =
28+
mainThreadIdRef.initAndGet {
29+
val id: MainThreadId? = getMainThreadId()
30+
if (id == null) {
31+
logE("Main thread id is undefined, main thread assert is disabled")
32+
}
33+
MainThreadIdHolder(id)
34+
}
35+
36+
return mainThreadId.id?.let(::isMainThread) ?: true
37+
}
38+
39+
private inline fun <T : Any> AtomicReference<T?>.initAndGet(init: () -> T): T {
40+
while (true) {
41+
var v: T? = value
42+
if (v != null) {
43+
return v
44+
}
45+
46+
v = init()
47+
if (compareAndSet(null, v)) {
48+
return v
49+
}
50+
}
51+
}
52+
53+
internal expect class MainThreadId
54+
55+
private class MainThreadIdHolder(val id: MainThreadId?)

utils-internal/src/darwinCommonMain/kotlin/com/arkivanov/mvikotlin/utils/internal/MainThreadAssert.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package com.arkivanov.mvikotlin.utils.internal
22

33
import platform.Foundation.NSThread
44

5-
internal actual val isMainThread: Boolean get() = NSThread.isMainThread()
5+
internal actual fun getMainThreadId(): MainThreadId? = MainThreadId()
66

7-
internal actual val currentThreadDescription: String get() = "Thread(name=${NSThread.currentThread().name()})"
7+
internal actual fun isMainThread(mainThreadId: MainThreadId): Boolean = NSThread.isMainThread()
8+
9+
internal actual fun getCurrentThreadDescription(): String = "Thread(name=${NSThread.currentThread().name()})"
10+
11+
internal actual class MainThreadId
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.arkivanov.mvikotlin.utils.internal
22

3-
internal actual val isMainThread: Boolean = true
3+
internal actual fun getMainThreadId(): MainThreadId? = MainThreadId()
44

5-
internal actual val currentThreadDescription: String = "Main thread"
5+
internal actual fun isMainThread(mainThreadId: MainThreadId): Boolean = true
6+
7+
internal actual fun getCurrentThreadDescription(): String = "Main thread"
8+
9+
internal actual class MainThreadId

utils-internal/src/jvmMain/kotlin/com/arkivanov/mvikotlin/utils/internal/MainThreadAssert.kt

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,18 @@ package com.arkivanov.mvikotlin.utils.internal
55
import java.util.concurrent.atomic.AtomicReference
66

77
@Suppress("ObjectPropertyName")
8-
private var _mainThreadId = AtomicReference<Long?>(null)
8+
private val mainThreadIdRef = AtomicReference<Long?>(null)
99

1010
fun setMainThreadId(id: Long) {
11-
if (!_mainThreadId.compareAndSet(null, id)) {
11+
if (!mainThreadIdRef.compareAndSet(null, id)) {
1212
throw IllegalStateException("Main thread id can be set only once")
1313
}
1414
}
1515

16-
private fun ensureMainThreadId(): Long {
17-
var id: Long
18-
var errorMessage: String?
19-
while (true) {
20-
errorMessage = null
16+
internal actual fun getMainThreadId(): MainThreadId? = mainThreadIdRef.get()?.let(::MainThreadId)
2117

22-
val savedId = _mainThreadId.get()
23-
if (savedId != null) {
24-
id = savedId
25-
break
26-
}
18+
internal actual fun isMainThread(mainThreadId: MainThreadId): Boolean = mainThreadId.id == Thread.currentThread().id
2719

28-
id = Thread.currentThread().id
29-
errorMessage = "Main thread id is not set, current thread is considered as main: $id"
20+
internal actual fun getCurrentThreadDescription(): String = Thread.currentThread().toString()
3021

31-
if (_mainThreadId.compareAndSet(null, id)) {
32-
break
33-
}
34-
}
35-
36-
errorMessage?.also {
37-
System.err.println(it)
38-
}
39-
40-
return id
41-
}
42-
43-
internal actual val isMainThread: Boolean get() = Thread.currentThread().id == ensureMainThreadId()
44-
45-
internal actual val currentThreadDescription: String get() = Thread.currentThread().toString()
22+
internal actual class MainThreadId(val id: Long)

utils-internal/src/linuxX64Main/kotlin/com/arkivanov/mvikotlin/utils/internal/MainThreadAssert.kt

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,22 @@
22

33
package com.arkivanov.mvikotlin.utils.internal
44

5-
import platform.posix.fprintf
65
import platform.posix.pthread_self
7-
import platform.posix.stderr
86
import kotlin.native.concurrent.AtomicReference
97

108
@Suppress("ObjectPropertyName")
11-
private val _mainThreadId = AtomicReference<ULong?>(null)
9+
private val mainThreadIdRef = AtomicReference<ULong?>(null)
1210

1311
fun setMainThreadId(id: ULong) {
14-
if (!_mainThreadId.compareAndSet(null, id)) {
12+
if (!mainThreadIdRef.compareAndSet(null, id)) {
1513
throw IllegalStateException("Main thread id can be set only once")
1614
}
1715
}
1816

19-
private fun ensureMainThreadId(): ULong {
20-
var id: ULong
21-
var errorMessage: String?
22-
while (true) {
23-
errorMessage = null
17+
internal actual fun getMainThreadId(): MainThreadId? = mainThreadIdRef.value?.let(::MainThreadId)
2418

25-
val savedId = _mainThreadId.value
26-
if (savedId != null) {
27-
id = savedId
28-
break
29-
}
19+
internal actual fun isMainThread(mainThreadId: MainThreadId): Boolean = mainThreadId.id == pthread_self()
3020

31-
id = pthread_self()
32-
errorMessage = "Main thread id is not set, current thread is considered as main: $id"
21+
internal actual fun getCurrentThreadDescription(): String = "Thread(id=${pthread_self()})"
3322

34-
if (_mainThreadId.compareAndSet(null, id)) {
35-
break
36-
}
37-
}
38-
39-
errorMessage?.also {
40-
fprintf(stderr, it)
41-
}
42-
43-
return id
44-
}
45-
46-
internal actual val isMainThread: Boolean get() = pthread_self() == ensureMainThreadId()
47-
48-
internal actual val currentThreadDescription: String get() = "Thread(id=${pthread_self()})"
23+
internal actual class MainThreadId(val id: ULong)

0 commit comments

Comments
 (0)