pEpObjCAdapter/PEPSessionProvider.m
author buff <andreas@pep-project.org>
Fri, 13 Oct 2017 10:34:46 +0200
branchIOSAD-50
changeset 273 d6c7bcbbefd2
parent 272 c456123edfa7
child 274 b91a9babb652
permissions -rw-r--r--
IOSAD-50 the client is responsible not to use a session after calling cleanup()
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@269
    11
#import "PEPInternalSession.h"
andreas@262
    12
#import "PEPCopyableThread.h"
andreas@262
    13
andreas@262
    14
@implementation PEPSessionProvider
andreas@262
    15
andreas@262
    16
static NSLock *s_sessionForThreadLock = nil;
andreas@269
    17
static NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *s_sessionForThreadDict;
andreas@262
    18
andreas@262
    19
#pragma mark - Public API
andreas@262
    20
andreas@269
    21
+ (PEPInternalSession * _Nonnull)session
andreas@262
    22
{
andreas@262
    23
    [[self sessionForThreadLock] lock];
andreas@273
    24
andreas@262
    25
    PEPCopyableThread *currentThread = [[PEPCopyableThread alloc] initWithThread:[NSThread currentThread]];
andreas@269
    26
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@269
    27
    PEPInternalSession *session = dict[currentThread];
andreas@262
    28
    if (!session) {
andreas@269
    29
        session = [[PEPInternalSession alloc] initInternal];
andreas@262
    30
        dict[currentThread] = session;
andreas@262
    31
    }
andreas@272
    32
    [self nullifySessionsOfFinishedThreads];
andreas@273
    33
    NSLog(@"#################\nnum sessions is now %lu\n#################", (unsigned long)[self sessionForThreadDict].count);
andreas@273
    34
andreas@262
    35
    [[self sessionForThreadLock] unlock];
andreas@273
    36
andreas@262
    37
    return session;
andreas@262
    38
}
andreas@262
    39
andreas@262
    40
+ (void)cleanup
andreas@262
    41
{
andreas@262
    42
    [[self sessionForThreadLock] lock];
andreas@273
    43
andreas@273
    44
    [self cleanupInternal];
andreas@273
    45
andreas@262
    46
    [[self sessionForThreadLock] unlock];
andreas@262
    47
}
andreas@262
    48
andreas@262
    49
#pragma mark - Life Cycle
andreas@262
    50
andreas@262
    51
+ (void)initialize
andreas@262
    52
{
andreas@262
    53
    s_sessionForThreadLock = [NSLock new];
andreas@262
    54
    s_sessionForThreadDict = [NSMutableDictionary new];
andreas@262
    55
}
andreas@262
    56
andreas@262
    57
#pragma mark - Lock
andreas@262
    58
andreas@262
    59
+ (NSLock *)sessionForThreadLock
andreas@262
    60
{
andreas@262
    61
    return s_sessionForThreadLock;
andreas@262
    62
}
andreas@262
    63
andreas@262
    64
+ (NSMutableDictionary *)sessionForThreadDict
andreas@262
    65
{
andreas@262
    66
    return s_sessionForThreadDict;
andreas@262
    67
}
andreas@262
    68
andreas@262
    69
#pragma mark -
andreas@262
    70
andreas@273
    71
+ (void)cleanupInternal
andreas@273
    72
{
andreas@273
    73
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@273
    74
andreas@273
    75
    for (PEPCopyableThread *thread in dict.allKeys) {
andreas@273
    76
        if (thread.isFinished) {
andreas@273
    77
            [self nullifySessionForThread:thread];
andreas@273
    78
        } else {
andreas@273
    79
            PEPInternalSession *session = dict[thread];
andreas@273
    80
            [session logTitle:@"Cleaning session that is potentially still in use"
andreas@273
    81
                       entity:[[self class] description]
andreas@273
    82
                  description:@"We are going to nullify a session for an active thread.\
andreas@273
    83
             This must not happen. \
andreas@273
    84
             It is the clients responsibility to assure no session is in use anymore when calling cleanup()."
andreas@273
    85
                      comment:nil];
andreas@273
    86
            [self nullifySessionForThread:thread];
andreas@273
    87
        }
andreas@273
    88
    }
andreas@273
    89
    NSLog(@"All sessions have been cleaned up. Session count is %lu", (unsigned long)dict.count); //BUFF:
andreas@273
    90
}
andreas@273
    91
andreas@273
    92
/**
andreas@273
    93
 Tears down all sessions that belong to a thread that has finish executing forever.
andreas@273
    94
 */
andreas@272
    95
+ (void)nullifySessionsOfFinishedThreads
andreas@262
    96
{
andreas@269
    97
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@262
    98
    for (PEPCopyableThread *thread in dict.allKeys) {
andreas@262
    99
        if (thread.isFinished) {
andreas@273
   100
            // The session has been created to run on the one and only thread.
andreas@273
   101
            // As this thread did finish executing forever, we can be sure the session can not be
andreas@273
   102
            // accessed anymore, thus it is OK to nullify it on another thread as the one it has been
andreas@273
   103
            // created for.
andreas@262
   104
            [self nullifySessionForThread:thread];
andreas@262
   105
        }
andreas@262
   106
    }
andreas@262
   107
}
andreas@262
   108
andreas@262
   109
+ (void)nullifySessionForThread:(PEPCopyableThread *)thread
andreas@262
   110
{
andreas@269
   111
    NSMutableDictionary<PEPCopyableThread*,PEPInternalSession*> *dict = [self sessionForThreadDict];
andreas@269
   112
    PEPInternalSession *session = dict[thread];
andreas@262
   113
    dict[thread] = nil;
andreas@262
   114
    session = nil;
andreas@262
   115
}
andreas@262
   116
andreas@262
   117
@end