IOSAD-50 we take over the responsibility for creating and holding a session for the main thread IOSAD-50
authorbuff <andreas@pep-project.org>
Fri, 20 Oct 2017 12:47:55 +0200
branchIOSAD-50
changeset 29019e6db3d1767
parent 288 a96780f56daa
child 292 ee62eebf395b
IOSAD-50 we take over the responsibility for creating and holding a session for the main thread
pEpObjCAdapter/PEPInternalSession.h
pEpObjCAdapter/PEPSession.h
pEpObjCAdapter/PEPSession.m
pEpObjCAdapter/PEPSessionProvider.m
     1.1 --- a/pEpObjCAdapter/PEPInternalSession.h	Fri Oct 20 00:22:44 2017 +0200
     1.2 +++ b/pEpObjCAdapter/PEPInternalSession.h	Fri Oct 20 12:47:55 2017 +0200
     1.3 @@ -16,6 +16,8 @@
     1.4   - You must use one session on one thread only to assure no concurrent calls to one session take place.
     1.5   - As long as you can assure the session is not accessed from anywhere else, it is OK to init/deinit a session on another thread than the one it is used on.
     1.6   - N threads <-> N sessions, with the constraint that a session is never used in a pEpEngine call more than once at the same time.
     1.7 +
     1.8 + Also the Engine requires that the first session is created on the main thread and is kept allive until all other created sessions have been terminated.
     1.9   */
    1.10  @interface PEPInternalSession : NSObject
    1.11  
     2.1 --- a/pEpObjCAdapter/PEPSession.h	Fri Oct 20 00:22:44 2017 +0200
     2.2 +++ b/pEpObjCAdapter/PEPSession.h	Fri Oct 20 12:47:55 2017 +0200
     2.3 @@ -23,15 +23,16 @@
     2.4   You can instatntiate and use this session how often and wherever you want. Also over multiple threads.
     2.5  
     2.6   Note: You must call `cleanup()` once before your process gets terminated to be able to gracefully shutdown.
     2.7 - It is the clients responsibility not to make any calls to PEPSession after calling cleanup.
     2.8 -
     2.9 - Also: The Engine requires that the first session is created on the main thread. It is the responibility of the client to call PEPSession init once on the main thread before any other thread is calling it.
    2.10 + It is the clients responsibility not to make any calls to PEPSession in between the last call
    2.11 + // to `cleanup()` and getting terminated.
    2.12   */
    2.13  @interface PEPSession : NSObject
    2.14  
    2.15  /**
    2.16   You must call this method once before your process gets terminated to be able to gracefully shutdown.
    2.17 - You must not make any calls to PEPSession after calling cleanup.
    2.18 + You must not make any calls to PEPSession in between the last call to `cleanup()` and getting terminated.
    2.19 +
    2.20 + Only for performance reasons: call this method only if you have to.
    2.21   */
    2.22  - (void)cleanup;
    2.23  
     3.1 --- a/pEpObjCAdapter/PEPSession.m	Fri Oct 20 00:22:44 2017 +0200
     3.2 +++ b/pEpObjCAdapter/PEPSession.m	Fri Oct 20 12:47:55 2017 +0200
     3.3 @@ -15,16 +15,6 @@
     3.4  
     3.5  #pragma mark - Public API
     3.6  
     3.7 -- (instancetype)init
     3.8 -{
     3.9 -    self = [super init];
    3.10 -    if (self) {
    3.11 -        // Trigger provider to make sure a internal session is kept for the current thread.
    3.12 -        [PEPSessionProvider session];
    3.13 -    }
    3.14 -    return self;
    3.15 -}
    3.16 -
    3.17  - (void)cleanup
    3.18  {
    3.19      [PEPSessionProvider cleanup];
     4.1 --- a/pEpObjCAdapter/PEPSessionProvider.m	Fri Oct 20 00:22:44 2017 +0200
     4.2 +++ b/pEpObjCAdapter/PEPSessionProvider.m	Fri Oct 20 12:47:55 2017 +0200
     4.3 @@ -23,12 +23,25 @@
     4.4  static NSLock *s_sessionForThreadLock = nil;
     4.5  static NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *s_sessionForThreadDict;
     4.6  
     4.7 +/** We have to conform to the Engines rule: "The first session has to be created on the main thread and kept
     4.8 + alive until all sessiopns created afterwards have been teared down."
     4.9 + Here we hold it.
    4.10 + */
    4.11 +static PEPInternalSession *s_sessionForMainThread = nil;
    4.12 +
    4.13  #pragma mark - Public API
    4.14  
    4.15  + (PEPInternalSession * _Nonnull)session
    4.16  {
    4.17      [[self sessionForThreadLock] lock];
    4.18  
    4.19 +    // Assure a session for the main thread exists and is kept alive before anyother session is created.
    4.20 +    [self assureSessionForMainThreadExists];
    4.21 +
    4.22 +    if ([NSThread isMainThread]) {
    4.23 +        return s_sessionForMainThread;
    4.24 +    }
    4.25 +
    4.26      NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
    4.27      PEPCopyableThread *currentThread = [[PEPCopyableThread alloc] initWithThread:[NSThread currentThread]];
    4.28      PEPInternalSession *session = dict[currentThread];
    4.29 @@ -39,11 +52,12 @@
    4.30      [self nullifySessionsOfFinishedThreads];
    4.31  
    4.32  //    NSLog(@"#################\nnum sessions is now %lu",
    4.33 -//          (unsigned long)[self sessionForThreadDict].count);
    4.34 +//          (unsigned long)[self sessionForThreadDict].count + (s_sessionForMainThread ? 1 : 0));
    4.35  //    NSLog(@"Threads:");
    4.36  //    for (PEPCopyableThread *thread in dict.allKeys) {
    4.37  //        NSLog(@"%@", thread.description);
    4.38  //    }
    4.39 +//    NSLog(@"Session for main thread: %@", s_sessionForMainThread);
    4.40  //    NSLog(@"##################################");
    4.41  
    4.42      [[self sessionForThreadLock] unlock];
    4.43 @@ -81,6 +95,23 @@
    4.44  }
    4.45  
    4.46  #pragma mark -
    4.47 +/**
    4.48 + Assures a session for the main thread is set.
    4.49 + */
    4.50 ++ (void)assureSessionForMainThreadExists
    4.51 +{
    4.52 +    if (s_sessionForMainThread) {
    4.53 +        return;
    4.54 +    }
    4.55 +
    4.56 +    if ([NSThread isMainThread]) {
    4.57 +        s_sessionForMainThread = [[PEPInternalSession alloc] initInternal];
    4.58 +    } else {
    4.59 +        dispatch_sync(dispatch_get_main_queue(), ^{
    4.60 +            s_sessionForMainThread = [[PEPInternalSession alloc] initInternal];
    4.61 +        });
    4.62 +    }
    4.63 +}
    4.64  
    4.65  + (void)cleanupInternal
    4.66  {
    4.67 @@ -89,8 +120,10 @@
    4.68      for (PEPCopyableThread *thread in dict.allKeys) {
    4.69          [self nullifySessionForThread:thread];
    4.70      }
    4.71 +    s_sessionForMainThread = nil;
    4.72      [dict removeAllObjects];
    4.73 -//    NSLog(@"All sessions have been cleaned up. Session count is %lu", (unsigned long)dict.count);
    4.74 +//    NSLog(@"All sessions have been cleaned up. Session count is %lu",
    4.75 +//          (unsigned long)dict.count + (s_sessionForMainThread ? 1 : 0));
    4.76  }
    4.77  
    4.78  /**