pEpObjCAdapter/PEPSessionProvider.m
author Dirk Zimmermann <dirk@pep-project.org>
Wed, 04 Jul 2018 13:21:53 +0200
changeset 637 2910f5cf61ea
parent 636 11d6508b7c62
child 638 f67f4bd9e683
permissions -rw-r--r--
IOS-1143 logging wrapped main session release
andreas@262
     1
//
andreas@262
     2
//  PEPSessionProvider.m
andreas@262
     3
//  pEpObjCAdapter
andreas@262
     4
//
andreas@262
     5
//  Created by Andreas Buff on 09.10.17.
andreas@262
     6
//  Copyright © 2017 p≡p. All rights reserved.
andreas@262
     7
//
andreas@262
     8
andreas@262
     9
#import "PEPSessionProvider.h"
andreas@262
    10
andreas@416
    11
#import "PEPObjCAdapter+Internal.h"
andreas@269
    12
#import "PEPInternalSession.h"
andreas@262
    13
#import "PEPCopyableThread.h"
dirk@636
    14
#import "PEPObjHolder.h"
andreas@262
    15
andreas@262
    16
@implementation PEPSessionProvider
andreas@262
    17
andreas@262
    18
static NSLock *s_sessionForThreadLock = nil;
andreas@269
    19
static NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *s_sessionForThreadDict;
andreas@262
    20
andreas@290
    21
/** We have to conform to the Engines rule: "The first session has to be created on the main thread and kept
andreas@290
    22
 alive until all sessiopns created afterwards have been teared down."
andreas@290
    23
 Here we hold it.
andreas@290
    24
 */
dirk@636
    25
static PEPObjHolder *s_sessionForMainThread = nil;
andreas@290
    26
andreas@262
    27
#pragma mark - Public API
andreas@262
    28
andreas@269
    29
+ (PEPInternalSession * _Nonnull)session
andreas@262
    30
{
andreas@262
    31
    [[self sessionForThreadLock] lock];
andreas@273
    32
andreas@290
    33
    // Assure a session for the main thread exists and is kept alive before anyother session is created.
andreas@290
    34
    [self assureSessionForMainThreadExists];
andreas@290
    35
andreas@290
    36
    if ([NSThread isMainThread]) {
andreas@292
    37
        [[self sessionForThreadLock] unlock];
dirk@636
    38
        return s_sessionForMainThread.object;
andreas@290
    39
    }
andreas@290
    40
andreas@288
    41
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@262
    42
    PEPCopyableThread *currentThread = [[PEPCopyableThread alloc] initWithThread:[NSThread currentThread]];
dirk@550
    43
    PEPInternalSession * __strong newOrExistingSession = dict[currentThread];
dirk@550
    44
    if (!newOrExistingSession) {
dirk@550
    45
        newOrExistingSession = [PEPInternalSession new];
dirk@550
    46
        dict[currentThread] = newOrExistingSession;
andreas@262
    47
    }
dirk@625
    48
dirk@625
    49
    // configuration
dirk@601
    50
    [self setConfigUnEncryptedSubjectOnSession:newOrExistingSession];
dirk@625
    51
    [self setPassiveModeOnSession:newOrExistingSession];
dirk@625
    52
andreas@272
    53
    [self nullifySessionsOfFinishedThreads];
andreas@273
    54
andreas@262
    55
    [[self sessionForThreadLock] unlock];
andreas@273
    56
dirk@550
    57
    return newOrExistingSession;
andreas@262
    58
}
andreas@262
    59
andreas@262
    60
+ (void)cleanup
andreas@262
    61
{
andreas@262
    62
    [[self sessionForThreadLock] lock];
andreas@273
    63
andreas@273
    64
    [self cleanupInternal];
andreas@273
    65
andreas@262
    66
    [[self sessionForThreadLock] unlock];
andreas@262
    67
}
andreas@262
    68
andreas@262
    69
#pragma mark - Life Cycle
andreas@262
    70
andreas@262
    71
+ (void)initialize
andreas@262
    72
{
andreas@262
    73
    s_sessionForThreadLock = [NSLock new];
andreas@262
    74
    s_sessionForThreadDict = [NSMutableDictionary new];
dirk@636
    75
    s_sessionForMainThread = [PEPObjHolder new];
andreas@262
    76
}
andreas@262
    77
andreas@262
    78
#pragma mark - Lock
andreas@262
    79
andreas@262
    80
+ (NSLock *)sessionForThreadLock
andreas@262
    81
{
andreas@262
    82
    return s_sessionForThreadLock;
andreas@262
    83
}
andreas@262
    84
andreas@262
    85
+ (NSMutableDictionary *)sessionForThreadDict
andreas@262
    86
{
andreas@262
    87
    return s_sessionForThreadDict;
andreas@262
    88
}
andreas@262
    89
dirk@625
    90
#pragma mark - configuration
andreas@416
    91
dirk@601
    92
+ (void)setConfigUnEncryptedSubjectOnSession:(PEPInternalSession *)session
andreas@416
    93
{
dirk@601
    94
    BOOL unEncryptedSubjectEnabled = [PEPObjCAdapter unEncryptedSubjectEnabled];
dirk@601
    95
    [session configUnEncryptedSubjectEnabled:unEncryptedSubjectEnabled];
andreas@416
    96
}
andreas@416
    97
dirk@625
    98
+ (void)setPassiveModeOnSession:(PEPInternalSession *)session
dirk@625
    99
{
dirk@625
   100
    BOOL passiveModeEnabled = [PEPObjCAdapter passiveModeEnabled];
dirk@625
   101
    [session configurePassiveModeEnabled:passiveModeEnabled];
dirk@625
   102
}
dirk@625
   103
dirk@625
   104
#pragma mark -
dirk@625
   105
andreas@290
   106
/**
andreas@290
   107
 Assures a session for the main thread is set.
andreas@290
   108
 */
andreas@290
   109
+ (void)assureSessionForMainThreadExists
andreas@290
   110
{
dirk@627
   111
    // shared code to set global configuration every time
dirk@627
   112
    void (^configurationBlock)(void) = ^{
dirk@636
   113
        [self setConfigUnEncryptedSubjectOnSession:s_sessionForMainThread.object];
dirk@636
   114
        [self setPassiveModeOnSession:s_sessionForMainThread.object];
dirk@627
   115
    };
dirk@627
   116
dirk@636
   117
    if (s_sessionForMainThread.object) {
dirk@627
   118
        configurationBlock();
dirk@549
   119
        return;
dirk@549
   120
    }
dirk@549
   121
dirk@627
   122
    // shared code that is executed in any case, either on the main thread or in the background
dirk@548
   123
    void (^creationBlock)(void) = ^{
dirk@636
   124
        if (s_sessionForMainThread.object) {
dirk@548
   125
            return;
dirk@548
   126
        }
dirk@636
   127
        s_sessionForMainThread.object = [PEPInternalSession new];
dirk@627
   128
        configurationBlock();
dirk@548
   129
    };
dirk@548
   130
andreas@290
   131
andreas@290
   132
    if ([NSThread isMainThread]) {
dirk@548
   133
        creationBlock();
andreas@290
   134
    } else {
dirk@548
   135
        dispatch_sync(dispatch_get_main_queue(), creationBlock);
andreas@290
   136
    }
andreas@290
   137
}
andreas@262
   138
andreas@273
   139
+ (void)cleanupInternal
andreas@273
   140
{
andreas@273
   141
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@273
   142
andreas@273
   143
    for (PEPCopyableThread *thread in dict.allKeys) {
andreas@275
   144
        [self nullifySessionForThread:thread];
andreas@273
   145
    }
dirk@636
   146
dirk@636
   147
    if (s_sessionForMainThread.object != nil) {
dirk@637
   148
        NSLog(@"*** 0x%lu (niling s_sessionForMainThread)",
dirk@637
   149
              (u_long) s_sessionForMainThread.object);
dirk@636
   150
        s_sessionForMainThread.object = nil;
dirk@636
   151
    }
dirk@636
   152
andreas@288
   153
    [dict removeAllObjects];
andreas@273
   154
}
andreas@273
   155
andreas@273
   156
/**
andreas@273
   157
 Tears down all sessions that belong to a thread that has finish executing forever.
andreas@273
   158
 */
andreas@272
   159
+ (void)nullifySessionsOfFinishedThreads
andreas@262
   160
{
andreas@269
   161
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@262
   162
    for (PEPCopyableThread *thread in dict.allKeys) {
andreas@262
   163
        if (thread.isFinished) {
andreas@273
   164
            // The session has been created to run on the one and only thread.
andreas@273
   165
            // As this thread did finish executing forever, we can be sure the session can not be
andreas@273
   166
            // accessed anymore, thus it is OK to nullify it on another thread as the one it has been
andreas@273
   167
            // created for.
andreas@262
   168
            [self nullifySessionForThread:thread];
andreas@262
   169
        }
andreas@262
   170
    }
andreas@262
   171
}
andreas@262
   172
andreas@262
   173
+ (void)nullifySessionForThread:(PEPCopyableThread *)thread
andreas@262
   174
{
andreas@269
   175
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@262
   176
    dict[thread] = nil;
andreas@262
   177
}
andreas@262
   178
andreas@262
   179
@end