Skip to content

Commit

Permalink
RUMM-2606 avoid recursive lock
Browse files Browse the repository at this point in the history
  • Loading branch information
maxep committed Oct 21, 2022
1 parent 60a8aff commit fbc11e4
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@
buildConfiguration = "Integration"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
enableThreadSanitizer = "YES"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
12 changes: 6 additions & 6 deletions Sources/Datadog/DatadogCore/Context/LaunchTimePublisher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import _Datadog_Private
internal struct LaunchTimePublisher: ContextValuePublisher {
private typealias AppLaunchHandler = __dd_private_AppLaunchHandler

var initialValue: LaunchTime
let initialValue: LaunchTime

init() {
initialValue = LaunchTime(
Expand All @@ -24,17 +24,17 @@ internal struct LaunchTimePublisher: ContextValuePublisher {
}

func publish(to receiver: @escaping ContextValueReceiver<LaunchTime>) {
AppLaunchHandler.shared.setCallback { handler in
AppLaunchHandler.shared.setApplicationDidBecomeActiveCallback { launchTime in
let value = LaunchTime(
launchTime: handler.launchTime?.doubleValue,
launchDate: handler.launchDate,
isActivePrewarm: handler.isActivePrewarm
launchTime: launchTime,
launchDate: initialValue.launchDate,
isActivePrewarm: initialValue.isActivePrewarm
)
receiver(value)
}
}

func cancel() {
AppLaunchHandler.shared.setCallback { _ in }
AppLaunchHandler.shared.setApplicationDidBecomeActiveCallback { _ in }
}
}
28 changes: 13 additions & 15 deletions Sources/_Datadog_Private/ObjcAppLaunchHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,17 @@
@implementation __dd_private_AppLaunchHandler {
NSTimeInterval _processStartTime;
NSTimeInterval _timeToApplicationDidBecomeActive;
AppLaunchCallback _callback;
BOOL _isActivePrewarm;
UIApplicationDidBecomeActiveCallback _applicationDidBecomeActiveCallback;
}

/// Shared instance of the Application Launch Handler.
static __dd_private_AppLaunchHandler *_shared;

/// The framework load time in seconds relative to the absolute reference date of Jan 1 2001 00:00:00 GMT.
static NSTimeInterval _frameworkLoadTime;

@synthesize isActivePrewarm = _isActivePrewarm;

+ (void)load {
// This is called at the `_Datadog_Private` load time, keep the work minimal
_frameworkLoadTime = CFAbsoluteTimeGetCurrent();
_shared = [[self alloc] initWithProcessInfo:NSProcessInfo.processInfo];
_shared = [[self alloc] initWithProcessInfo:NSProcessInfo.processInfo
loadTime:CFAbsoluteTimeGetCurrent()];

NSNotificationCenter * __weak center = NSNotificationCenter.defaultCenter;
id __block token = [center addObserverForName:UIApplicationDidBecomeActiveNotification
Expand All @@ -51,8 +47,9 @@ + (void)load {
usingBlock:^(NSNotification *_){

@synchronized(_shared) {
_shared->_timeToApplicationDidBecomeActive = CFAbsoluteTimeGetCurrent() - _shared->_processStartTime;
_shared->_callback(_shared);
NSTimeInterval time = CFAbsoluteTimeGetCurrent() - _shared->_processStartTime;
_shared->_timeToApplicationDidBecomeActive = time;
_shared->_applicationDidBecomeActiveCallback(time);
}

[center removeObserver:token];
Expand All @@ -64,10 +61,11 @@ + (__dd_private_AppLaunchHandler *)shared {
return _shared;
}

- (instancetype)initWithProcessInfo:(NSProcessInfo *)processInfo {
- (instancetype)initWithProcessInfo:(NSProcessInfo *)processInfo loadTime:(NSTimeInterval)loadTime {
NSTimeInterval startTime;
if (processStartTimeIntervalSinceReferenceDate(&startTime) != 0) {
startTime = _frameworkLoadTime;
// fallback on the loading time
startTime = loadTime;
}

// The ActivePrewarm variable indicates whether the app was launched via pre-warming.
Expand All @@ -80,7 +78,7 @@ - (instancetype)initWithStartTime:(NSTimeInterval)startTime isActivePrewarm:(BOO
if (!self) return nil;
_processStartTime = startTime;
_isActivePrewarm = isActivePrewarm;
_callback = ^(__dd_private_AppLaunchHandler *handler) {};
_applicationDidBecomeActiveCallback = ^(NSTimeInterval _) {};
return self;
}

Expand All @@ -104,9 +102,9 @@ - (BOOL)isActivePrewarm {
}
}

- (void)setCallback:(AppLaunchCallback)callback {
- (void)setApplicationDidBecomeActiveCallback:(UIApplicationDidBecomeActiveCallback)callback {
@synchronized(self) {
_callback = callback;
_applicationDidBecomeActiveCallback = callback;
}
}

Expand Down
15 changes: 7 additions & 8 deletions Sources/_Datadog_Private/include/ObjcAppLaunchHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,17 @@ NS_ASSUME_NONNULL_BEGIN
/// ref. https://developer.apple.com/documentation/uikit/app_and_environment/responding_to_the_launch_of_your_app/about_the_app_launch_sequence
@interface __dd_private_AppLaunchHandler : NSObject

typedef void (^AppLaunchCallback) (__dd_private_AppLaunchHandler *handler);
typedef void (^UIApplicationDidBecomeActiveCallback) (NSTimeInterval);

/// Sole instance of the Application Launch Handler.
@property (class, readonly) __dd_private_AppLaunchHandler *shared;

/// Returns the Application process launch date.
@property (atomic, readonly) NSDate* launchDate;

/// Returns the time interval between startup of the application process and the
/// `UIApplicationDidBecomeActiveNotification`.
///
/// If the `UIApplicationDidBecomeActiveNotification` has not been reached yet,
/// it returns time interval between startup of the application process and now.
/// Returns the time interval in seconds between startup of the application process and the
/// `UIApplicationDidBecomeActiveNotification`. Or `nil` If the
/// `UIApplicationDidBecomeActiveNotification` has not been reached yet.
@property (atomic, readonly, nullable) NSNumber* launchTime;

/// Returns `true` when the application is pre-warmed.
Expand All @@ -36,10 +34,11 @@ typedef void (^AppLaunchCallback) (__dd_private_AppLaunchHandler *handler);

/// Sets the callback to be invoked when the application becomes active.
///
/// The closure get the updated handler as argument.
/// The closure get the updated handler as argument. You will not get any
/// notification if the application became active before setting the callback
///
/// - Parameter callback: The callback closure.
- (void)setCallback:(AppLaunchCallback)callback;
- (void)setApplicationDidBecomeActiveCallback:(UIApplicationDidBecomeActiveCallback)callback;

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class LaunchTimePublisherTests: XCTestCase {
callConcurrently(
closures: [
{ _ = handler.launchTime },
{ handler.setCallback { _ in } },
{ _ = handler.launchDate },
{ _ = handler.isActivePrewarm },
{ handler.setApplicationDidBecomeActiveCallback { _ in } }
],
iterations: 1_000
)
Expand Down

0 comments on commit fbc11e4

Please sign in to comment.