Skip to content

Commit

Permalink
Revert "Replace dispatch_semaphore use with os_unfair_lock. (#324)"
Browse files Browse the repository at this point in the history
This reverts commit bd6b2fe.
  • Loading branch information
thomasvl committed Nov 8, 2022
1 parent 5b6b646 commit 74aa1bf
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 115 deletions.
142 changes: 67 additions & 75 deletions Sources/Core/GTMSessionFetcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -649,15 +649,74 @@ - (void)beginFetchMayDelay:(BOOL)mayDelay

self.canShareSession = (_service != nil) && !isRecreatingSession && !self.usingBackgroundSession;

if (!self.session && self.canShareSession) {
self.session = [_service sessionForFetcherCreation];
// If _session is nil, then the service's session creation semaphore will block
// until this fetcher invokes fetcherDidCreateSession: below, so this *must* invoke
// that method, even if the session fails to be created.
}

if (!self.session) {
if (self.canShareSession) {
self.session = [_service
sessionWithCreationBlock:^NSURLSession *(id<NSURLSessionDelegate> sessionDelegate) {
return [self createSessionWithDelegate:sessionDelegate
sessionIdentifier:priorSessionIdentifier];
}];
} else {
self.session = [self createSessionWithDelegate:self sessionIdentifier:priorSessionIdentifier];
// Create a session.
if (!_configuration) {
if (priorSessionIdentifier || self.usingBackgroundSession) {
NSString *sessionIdentifier = priorSessionIdentifier;
if (!sessionIdentifier) {
sessionIdentifier = [self createSessionIdentifierWithMetadata:nil];
}
NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap];
[sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier];

_configuration = [NSURLSessionConfiguration
backgroundSessionConfigurationWithIdentifier:sessionIdentifier];
self.usingBackgroundSession = YES;
self.canShareSession = NO;
} else {
_configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
}
#if !GTM_ALLOW_INSECURE_REQUESTS
#if GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
_configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12;
#elif GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
if (@available(iOS 13, tvOS 13, macOS 10.15, *)) {
_configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12;
} else {
_configuration.TLSMinimumSupportedProtocol = kTLSProtocol12;
}
#else
_configuration.TLSMinimumSupportedProtocol = kTLSProtocol12;
#endif // GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
#endif
} // !_configuration
_configuration.HTTPCookieStorage = self.cookieStorage;

if (_configurationBlock) {
_configurationBlock(self, _configuration);
}

id<NSURLSessionDelegate> delegate = [_service sessionDelegate];
if (!delegate || !self.canShareSession) {
delegate = self;
}
self.session = [NSURLSession sessionWithConfiguration:_configuration
delegate:delegate
delegateQueue:self.sessionDelegateQueue];
GTMSESSION_ASSERT_DEBUG(self.session, @"Couldn't create session");

// Tell the service about the session created by this fetcher. This also signals the
// service's semaphore to allow other fetchers to request this session.
[_service fetcherDidCreateSession:self];

// If this assertion fires, the client probably tried to use a session identifier that was
// already used. The solution is to make the client use a unique identifier (or better yet let
// the session fetcher assign the identifier).
GTMSESSION_ASSERT_DEBUG(self.session.delegate == delegate, @"Couldn't assign delegate.");

if (self.session) {
BOOL isUsingSharedDelegate = (delegate != self);
if (!isUsingSharedDelegate) {
_shouldInvalidateSession = YES;
}
}
}

Expand Down Expand Up @@ -935,73 +994,6 @@ - (void)beginFetchMayDelay:(BOOL)mayDelay
}
}

// Helper method to create a new NSURLSession for this fetcher. Because the original
// implementation had this code inline, marking direct to avoid any danger of subclasses
// overriding the behavior.
- (NSURLSession *)createSessionWithDelegate:(id<NSURLSessionDelegate>)sessionDelegate
sessionIdentifier:(nullable NSString *)priorSessionIdentifier
__attribute__((objc_direct)) {
// Create a session.
if (!_configuration) {
if (priorSessionIdentifier || self.usingBackgroundSession) {
NSString *sessionIdentifier = priorSessionIdentifier;
if (!sessionIdentifier) {
sessionIdentifier = [self createSessionIdentifierWithMetadata:nil];
}
NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIdentifierToFetcherMap];
[sessionIdentifierToFetcherMap setObject:self forKey:self.sessionIdentifier];

_configuration = [NSURLSessionConfiguration
backgroundSessionConfigurationWithIdentifier:sessionIdentifier];
self.usingBackgroundSession = YES;
self.canShareSession = NO;
} else {
_configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
}
#if !GTM_ALLOW_INSECURE_REQUESTS
#if GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
_configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12;
#elif GTM_SDK_SUPPORTS_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
if (@available(iOS 13, tvOS 13, macOS 10.15, *)) {
_configuration.TLSMinimumSupportedProtocolVersion = tls_protocol_version_TLSv12;
} else {
_configuration.TLSMinimumSupportedProtocol = kTLSProtocol12;
}
#else
_configuration.TLSMinimumSupportedProtocol = kTLSProtocol12;
#endif // GTM_SDK_REQUIRES_TLSMINIMUMSUPPORTEDPROTOCOLVERSION
#endif
} // !_configuration
_configuration.HTTPCookieStorage = self.cookieStorage;

if (_configurationBlock) {
_configurationBlock(self, _configuration);
}

id<NSURLSessionDelegate> delegate = sessionDelegate;
if (!delegate || !self.canShareSession) {
delegate = self;
}
NSURLSession *session = [NSURLSession sessionWithConfiguration:_configuration
delegate:delegate
delegateQueue:self.sessionDelegateQueue];
GTMSESSION_ASSERT_DEBUG(session, @"Couldn't create session");

// If this assertion fires, the client probably tried to use a session identifier that was
// already used. The solution is to make the client use a unique identifier (or better yet let
// the session fetcher assign the identifier).
GTMSESSION_ASSERT_DEBUG(session.delegate == delegate, @"Couldn't assign delegate.");

if (session) {
BOOL isUsingSharedDelegate = (delegate != self);
if (!isUsingSharedDelegate) {
_shouldInvalidateSession = YES;
}
}

return session;
}

NSData *_Nullable GTMDataFromInputStream(NSInputStream *inputStream, NSError **outError) {
NSMutableData *data = [NSMutableData data];

Expand Down
88 changes: 54 additions & 34 deletions Sources/Core/GTMSessionFetcherService.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

#import "GTMSessionFetcher/GTMSessionFetcherService.h"

#include <os/lock.h>

NSString *const kGTMSessionFetcherServiceSessionBecameInvalidNotification =
@"kGTMSessionFetcherServiceSessionBecameInvalidNotification";
NSString *const kGTMSessionFetcherServiceSessionKey = @"kGTMSessionFetcherServiceSessionKey";
Expand Down Expand Up @@ -83,7 +81,7 @@ @implementation GTMSessionFetcherService {
GTMSessionFetcherSessionDelegateDispatcher *_delegateDispatcher;

// Fetchers will wait on this if another fetcher is creating the shared NSURLSession.
os_unfair_lock _sessionCreationLock;
dispatch_semaphore_t _sessionCreationSemaphore;

BOOL _callbackQueueIsConcurrent;
dispatch_queue_t _callbackQueue;
Expand Down Expand Up @@ -154,7 +152,7 @@ - (instancetype)init {
_delegateQueue.maxConcurrentOperationCount = 1;
_delegateQueue.name = @"com.google.GTMSessionFetcher.NSURLSessionDelegateQueue";

_sessionCreationLock = OS_UNFAIR_LOCK_INIT;
_sessionCreationSemaphore = dispatch_semaphore_create(1);

// Starting with the SDKs for OS X 10.11/iOS 9, the service has a default useragent.
// Apps can remove this and get the default system "CFNetwork" useragent by setting the
Expand Down Expand Up @@ -280,40 +278,42 @@ - (NSURLSession *)session {
}
}

- (NSURLSession *)sessionWithCreationBlock:
(NS_NOESCAPE GTMSessionFetcherSessionCreationBlock)creationBlock {
// Returns a session for the fetcher's host, or nil. For shared sessions, this
// waits on a semaphore, blocking other fetchers while the caller creates the
// session if needed.
- (NSURLSession *)sessionForFetcherCreation {
@synchronized(self) {
GTMSessionMonitorSynchronized(self);
if (!_delegateDispatcher) {
// This fetcher is creating a non-shared session, so skip locking.
return creationBlock(nil);
// This fetcher is creating a non-shared session, so skip the semaphore usage.
return nil;
}
}

@try {
NSURLSession *session;
// Wait if another fetcher is currently creating a session; avoid waiting inside the
// @synchronized block as that could deadlock.
os_unfair_lock_lock(&_sessionCreationLock);
@synchronized(self) {
GTMSessionMonitorSynchronized(self);

// Before getting the NSURLSession for task creation, it is
// important to invalidate and nil out the session discard timer; otherwise
// the session can be invalidated between when it is returned to the
// fetcher, and when the fetcher attempts to create its NSURLSessionTask.
[_delegateDispatcher startSessionUsage];

session = _delegateDispatcher.session;
if (!session) {
session = creationBlock(_delegateDispatcher);
_delegateDispatcher.session = session;
}
// Wait if another fetcher is currently creating a session; avoid waiting
// inside the @synchronized block, as that can deadlock.
dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER);

@synchronized(self) {
GTMSessionMonitorSynchronized(self);

// Before getting the NSURLSession for task creation, it is
// important to invalidate and nil out the session discard timer; otherwise
// the session can be invalidated between when it is returned to the
// fetcher, and when the fetcher attempts to create its NSURLSessionTask.
[_delegateDispatcher startSessionUsage];

NSURLSession *session = _delegateDispatcher.session;
if (session) {
// The calling fetcher will receive a preexisting session, so
// we can allow other fetchers to create a session.
dispatch_semaphore_signal(_sessionCreationSemaphore);
} else {
// No existing session was obtained, so the calling fetcher will create the session;
// it *must* invoke fetcherDidCreateSession: to signal the dispatcher's semaphore after
// the session has been created (or fails to be created) to avoid a hang.
}
return session;
} @finally {
// Ensure the lock is always released, even if creationBlock throws.
os_unfair_lock_unlock(&_sessionCreationLock);
}
}

Expand Down Expand Up @@ -439,6 +439,26 @@ - (GTMSessionFetcherSessionDelegateDispatcher *)delegateDispatcherForFetcher:
return nil;
}

- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher {
if (fetcher.canShareSession) {
NSURLSession *fetcherSession = fetcher.session;
GTMSESSION_ASSERT_DEBUG(fetcherSession != nil, @"Fetcher missing its session: %@", fetcher);

GTMSessionFetcherSessionDelegateDispatcher *delegateDispatcher =
[self delegateDispatcherForFetcher:fetcher];
if (delegateDispatcher) {
GTMSESSION_ASSERT_DEBUG(delegateDispatcher.session == nil,
@"Fetcher made an extra session: %@", fetcher);

// Save this fetcher's session.
delegateDispatcher.session = fetcherSession;

// Allow other fetchers to request this session now.
dispatch_semaphore_signal(_sessionCreationSemaphore);
}
}
}

- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher {
// If this fetcher has a separate delegate with a shared session, then
// this fetcher should be added to the delegate's map of tasks to fetchers.
Expand Down Expand Up @@ -692,14 +712,14 @@ - (void)setReuseSession:(BOOL)shouldReuse {

- (void)resetSession {
GTMSessionCheckNotSynchronized(self);
os_unfair_lock_lock(&_sessionCreationLock);
dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER);

@synchronized(self) {
GTMSessionMonitorSynchronized(self);
[self resetSessionInternal];
}

os_unfair_lock_unlock(&_sessionCreationLock);
dispatch_semaphore_signal(_sessionCreationSemaphore);
}

- (void)resetSessionInternal {
Expand All @@ -717,7 +737,7 @@ - (void)resetSessionInternal {
- (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer {
GTMSessionCheckNotSynchronized(self);

os_unfair_lock_lock(&_sessionCreationLock);
dispatch_semaphore_wait(_sessionCreationSemaphore, DISPATCH_TIME_FOREVER);
@synchronized(self) {
GTMSessionMonitorSynchronized(self);

Expand All @@ -735,7 +755,7 @@ - (void)resetSessionForDispatcherDiscardTimer:(NSTimer *)timer {
}
}

os_unfair_lock_unlock(&_sessionCreationLock);
dispatch_semaphore_signal(_sessionCreationSemaphore);
}

- (NSTimeInterval)unusedSessionTimeout {
Expand Down
6 changes: 2 additions & 4 deletions Sources/Core/Public/GTMSessionFetcher/GTMSessionFetcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,6 @@ typedef void (^GTMSessionFetcherConfigurationBlock)(GTMSessionFetcher *fetcher,
typedef void (^GTMSessionFetcherSystemCompletionHandler)(void);
typedef void (^GTMSessionFetcherCompletionHandler)(NSData *_Nullable data,
NSError *_Nullable error);
typedef NSURLSession *_Nullable (^GTMSessionFetcherSessionCreationBlock)(
id<NSURLSessionDelegate> _Nullable sessionDelegate);
typedef void (^GTMSessionFetcherBodyStreamProviderResponse)(NSInputStream *bodyStream);
typedef void (^GTMSessionFetcherBodyStreamProvider)(
GTMSessionFetcherBodyStreamProviderResponse response);
Expand Down Expand Up @@ -621,6 +619,7 @@ typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLReques
@property(atomic, strong) dispatch_queue_t callbackQueue;

- (BOOL)fetcherShouldBeginFetching:(GTMSessionFetcher *)fetcher;
- (void)fetcherDidCreateSession:(GTMSessionFetcher *)fetcher;
- (void)fetcherDidBeginFetching:(GTMSessionFetcher *)fetcher;
- (void)fetcherDidStop:(GTMSessionFetcher *)fetcher;

Expand All @@ -629,8 +628,7 @@ typedef void (^GTMFetcherDecoratorFetcherWillStartCompletionHandler)(NSURLReques

@property(atomic, assign) BOOL reuseSession;
- (nullable NSURLSession *)session;
- (nullable NSURLSession *)sessionWithCreationBlock:
(nonnull NS_NOESCAPE GTMSessionFetcherSessionCreationBlock)creationBlock;
- (nullable NSURLSession *)sessionForFetcherCreation;
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
- (nullable NSDate *)stoppedAllFetchersDate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,7 @@ extern NSString *const kGTMSessionFetcherServiceSessionKey;

// Methods for use by the fetcher class only.
- (nullable NSURLSession *)session;
- (nullable NSURLSession *)sessionWithCreationBlock:
(nonnull NS_NOESCAPE GTMSessionFetcherSessionCreationBlock)creationBlock;
- (nullable NSURLSession *)sessionForFetcherCreation;
- (nullable id<NSURLSessionDelegate>)sessionDelegate;
- (nullable NSDate *)stoppedAllFetchersDate;

Expand Down

0 comments on commit 74aa1bf

Please sign in to comment.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy