Skip to content

Commit 2b55154

Browse files
ref: add SentryThreadWrapper method to run code on main thread (#3138)
Co-authored-by: Philipp Hofmann <[email protected]>
1 parent 4afae53 commit 2b55154

File tree

6 files changed

+61
-17
lines changed

6 files changed

+61
-17
lines changed

Sentry.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@
639639
8453421228BE855D00C22EEC /* SentrySampleDecision.m in Sources */ = {isa = PBXBuildFile; fileRef = 8453421128BE855D00C22EEC /* SentrySampleDecision.m */; };
640640
8453421628BE8A9500C22EEC /* SentrySpanStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 8453421528BE8A9500C22EEC /* SentrySpanStatus.m */; };
641641
8454CF8D293EAF9A006AC140 /* SentryMetricProfiler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8454CF8B293EAF9A006AC140 /* SentryMetricProfiler.mm */; };
642+
8489B8882A5F7905009A055A /* SentryThreadWrapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8489B8872A5F7905009A055A /* SentryThreadWrapperTests.swift */; };
642643
849AC40029E0C1FF00889C16 /* SentryFormatterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AC3FF29E0C1FF00889C16 /* SentryFormatterTests.swift */; };
643644
84A5D75B29D5170700388BFA /* TimeInterval+Sentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84A5D75A29D5170700388BFA /* TimeInterval+Sentry.swift */; };
644645
84A888FD28D9B11700C51DFD /* SentryProfiler+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 84A888FC28D9B11700C51DFD /* SentryProfiler+Private.h */; };
@@ -1577,6 +1578,7 @@
15771578
8453421128BE855D00C22EEC /* SentrySampleDecision.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySampleDecision.m; sourceTree = "<group>"; };
15781579
8453421528BE8A9500C22EEC /* SentrySpanStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SentrySpanStatus.m; sourceTree = "<group>"; };
15791580
8454CF8B293EAF9A006AC140 /* SentryMetricProfiler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = SentryMetricProfiler.mm; path = Sources/Sentry/SentryMetricProfiler.mm; sourceTree = SOURCE_ROOT; };
1581+
8489B8872A5F7905009A055A /* SentryThreadWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SentryThreadWrapperTests.swift; path = Helper/SentryThreadWrapperTests.swift; sourceTree = "<group>"; };
15801582
849472802971C107002603DE /* SentrySystemWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentrySystemWrapperTests.swift; sourceTree = "<group>"; };
15811583
849472822971C2CD002603DE /* SentryNSProcessInfoWrapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSProcessInfoWrapperTests.swift; sourceTree = "<group>"; };
15821584
849472842971C41A002603DE /* SentryNSTimerFactoryTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryNSTimerFactoryTest.swift; sourceTree = "<group>"; };
@@ -2238,6 +2240,7 @@
22382240
632331F52404FFA8008D91D6 /* SentryScopeTests.m */,
22392241
7B0002312477F0520035FEF1 /* SentrySessionTests.m */,
22402242
63AA75951EB8AEDB00D153DE /* SentryTests.m */,
2243+
8489B8872A5F7905009A055A /* SentryThreadWrapperTests.swift */,
22412244
63AA75941EB8AEDB00D153DE /* Info.plist */,
22422245
7B6D1262265F7CC600C9BE4B /* PrivateSentrySDKOnlyTests.swift */,
22432246
7B4260332630315C00B36EDD /* SampleError.swift */,
@@ -4249,6 +4252,7 @@
42494252
7BFAA6E7297AA16A00E7E02E /* SentryCrashMonitor_CppException_Tests.mm in Sources */,
42504253
9286059929A50BAB00F96038 /* SentryGeoTests.swift in Sources */,
42514254
D8B76B0828081461000A58C4 /* TestSentryScreenShot.swift in Sources */,
4255+
8489B8882A5F7905009A055A /* SentryThreadWrapperTests.swift in Sources */,
42524256
A8AFFCD22907DA7600967CD7 /* SentryHttpStatusCodeRangeTests.swift in Sources */,
42534257
7BE2C7F8257000A4003B66C7 /* SentryTestIntegration.m in Sources */,
42544258
84A8892128DBD8D600C51DFD /* SentryDeviceTests.mm in Sources */,

Sources/Sentry/SentryProfiler.mm

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
# import "SentrySpanId.h"
3333
# import "SentrySystemWrapper.h"
3434
# import "SentryThread.h"
35+
# import "SentryThreadWrapper.h"
3536
# import "SentryTime.h"
3637
# import "SentryTracer.h"
3738
# import "SentryTracerConcurrency.h"
@@ -312,7 +313,8 @@ - (instancetype)initWithHub:(SentryHub *)hub
312313
- (void)scheduleTimeoutTimer
313314
{
314315
__weak SentryProfiler *weakSelf = self;
315-
void (^block)(void) = ^(void) {
316+
317+
[SentryThreadWrapper onMainThread:^{
316318
if (![weakSelf isRunning]) {
317319
return;
318320
}
@@ -324,13 +326,7 @@ - (void)scheduleTimeoutTimer
324326
selector:@selector(timeoutAbort)
325327
userInfo:nil
326328
repeats:NO];
327-
};
328-
329-
if (NSThread.isMainThread) {
330-
block();
331-
} else {
332-
dispatch_async(dispatch_get_main_queue(), block);
333-
}
329+
}];
334330
}
335331

336332
# pragma mark - Public

Sources/Sentry/SentryThreadWrapper.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ - (void)threadFinished:(NSUUID *)threadID
1919
// No op. Only needed for testing.
2020
}
2121

22+
+ (void)onMainThread:(void (^)(void))block
23+
{
24+
if ([NSThread isMainThread]) {
25+
block();
26+
} else {
27+
dispatch_async(dispatch_get_main_queue(), block);
28+
}
29+
}
30+
2231
@end
2332

2433
NS_ASSUME_NONNULL_END

Sources/Sentry/SentryTracer.m

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#import "SentrySpanContext+Private.h"
2222
#import "SentrySpanContext.h"
2323
#import "SentrySpanId.h"
24+
#import "SentryThreadWrapper.h"
2425
#import "SentryTime.h"
2526
#import "SentryTraceContext.h"
2627
#import "SentryTraceOrigins.h"
@@ -212,15 +213,14 @@ - (void)cancelIdleTimeout
212213
- (void)startDeadlineTimer
213214
{
214215
__weak SentryTracer *weakSelf = self;
215-
self.deadlineTimer =
216-
[_configuration.timerFactory scheduledTimerWithTimeInterval:SENTRY_AUTO_TRANSACTION_DEADLINE
217-
repeats:NO
218-
block:^(NSTimer *_Nonnull timer) {
219-
if (weakSelf == nil) {
220-
return;
221-
}
222-
[weakSelf deadlineTimerFired];
223-
}];
216+
[SentryThreadWrapper onMainThread:^{
217+
weakSelf.deadlineTimer = [weakSelf.configuration.timerFactory
218+
scheduledTimerWithTimeInterval:SENTRY_AUTO_TRANSACTION_DEADLINE
219+
repeats:NO
220+
block:^(NSTimer *_Nonnull timer) {
221+
[weakSelf deadlineTimerFired];
222+
}];
223+
}];
224224
}
225225

226226
- (void)deadlineTimerFired

Sources/Sentry/include/SentryThreadWrapper.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ NS_ASSUME_NONNULL_BEGIN
1313

1414
- (void)threadFinished:(NSUUID *)threadID;
1515

16+
/**
17+
* Ensure a block runs on the main thread. If called from the main thread, execute the block
18+
* synchronously. If called from a non-main thread, then dispatch the block to the main queue
19+
* asynchronously.
20+
* @warning The block will not execute until the main queue is freed by the caller. Try to return up
21+
* the call stack as soon as possible after calling this method if you need the block to execute in
22+
* a timely manner.
23+
*/
24+
+ (void)onMainThread:(void (^)(void))block;
25+
1626
@end
1727

1828
NS_ASSUME_NONNULL_END
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import XCTest
2+
3+
final class SentryThreadWrapperTests: XCTestCase {
4+
func testOnMainThreadFromMainThread() {
5+
let e = expectation(description: "Asserted that execution happened on main thread")
6+
SentryThreadWrapper.onMainThread {
7+
XCTAssertTrue(Thread.isMainThread)
8+
e.fulfill()
9+
}
10+
waitForExpectations(timeout: 1)
11+
}
12+
13+
func testOnMainThreadFromNonMainContext() {
14+
let e = expectation(description: "Asserted that execution happened on main thread")
15+
let q = DispatchQueue(label: "a nonmain queue", qos: .background)
16+
q.async {
17+
XCTAssertFalse(Thread.isMainThread)
18+
SentryThreadWrapper.onMainThread {
19+
XCTAssertTrue(Thread.isMainThread)
20+
e.fulfill()
21+
}
22+
}
23+
waitForExpectations(timeout: 1)
24+
}
25+
}

0 commit comments

Comments
 (0)