Skip to content

Commit b44b489

Browse files
authored
Merge pull request #2034 from OneSignal/fix/event-producer-thread-safe
[Fix] thread safety with EventProducer's fire events
2 parents 79a2fbd + d798815 commit b44b489

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/events/EventProducer.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ open class EventProducer<THandler> : IEventNotifier<THandler> {
4545
* @param callback The callback will be invoked for each subscribed handler, allowing you to call the handler.
4646
*/
4747
fun fire(callback: (THandler) -> Unit) {
48-
val localList = subscribers.toList()
48+
val localList = synchronized(subscribers) { subscribers.toList() }
4949
for (s in localList) {
5050
callback(s)
5151
}
@@ -60,7 +60,7 @@ open class EventProducer<THandler> : IEventNotifier<THandler> {
6060
*/
6161
fun fireOnMain(callback: (THandler) -> Unit) {
6262
suspendifyOnMain {
63-
val localList = subscribers.toList()
63+
val localList = synchronized(subscribers) { subscribers.toList() }
6464
for (s in localList) {
6565
callback(s)
6666
}
@@ -74,7 +74,7 @@ open class EventProducer<THandler> : IEventNotifier<THandler> {
7474
* @param callback The callback will be invoked for each subscribed handler, allowing you to call the handler.
7575
*/
7676
suspend fun suspendingFire(callback: suspend (THandler) -> Unit) {
77-
val localList = subscribers.toList()
77+
val localList = synchronized(subscribers) { subscribers.toList() }
7878
for (s in localList) {
7979
callback(s)
8080
}
@@ -88,7 +88,7 @@ open class EventProducer<THandler> : IEventNotifier<THandler> {
8888
*/
8989
suspend fun suspendingFireOnMain(callback: suspend (THandler) -> Unit) {
9090
withContext(Dispatchers.Main) {
91-
val localList = subscribers.toList()
91+
val localList = synchronized(subscribers) { subscribers.toList() }
9292
for (s in localList) {
9393
callback(s)
9494
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.onesignal.common
2+
3+
import com.onesignal.common.events.EventProducer
4+
import io.kotest.core.spec.style.FunSpec
5+
import kotlin.concurrent.thread
6+
7+
class EventProducerTest : FunSpec({
8+
9+
fun modifyingSubscribersThread(eventProducer: EventProducer<Boolean>): Thread {
10+
return thread(start = true) {
11+
repeat(10_000) {
12+
eventProducer.subscribe(true)
13+
eventProducer.unsubscribe(true)
14+
}
15+
}
16+
}
17+
18+
test("fire is thread safe") {
19+
val eventProducer = EventProducer<Boolean>()
20+
val modifyingSubscribersThread = modifyingSubscribersThread(eventProducer)
21+
22+
repeat(10_000) {
23+
eventProducer.fire { }
24+
}
25+
26+
modifyingSubscribersThread.join()
27+
}
28+
29+
test("suspendingFire is thread safe") {
30+
val eventProducer = EventProducer<Boolean>()
31+
val modifyingSubscribersThread = modifyingSubscribersThread(eventProducer)
32+
33+
repeat(10_000) {
34+
eventProducer.suspendingFire { }
35+
}
36+
37+
modifyingSubscribersThread.join()
38+
}
39+
40+
test("hasSubscribers is thread safe") {
41+
val eventProducer = EventProducer<Boolean>()
42+
val modifyingSubscribersThread = modifyingSubscribersThread(eventProducer)
43+
44+
repeat(10_000) {
45+
eventProducer.hasSubscribers
46+
}
47+
48+
modifyingSubscribersThread.join()
49+
}
50+
})

0 commit comments

Comments
 (0)