1/*
2 * Copyright (c) 2010 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LLVM_LICENSE_HEADER@
5 */
6
7//
8//  counting.m
9//  testObjects
10//
11//  Created by Blaine Garst on 9/23/08.
12//  Copyright 2008 Apple. All rights reserved.
13//
14// rdar://6557292
15// TEST_CFLAGS -framework Foundation
16
17#import <Foundation/Foundation.h>
18#import <objc/objc-auto.h>
19#import <Block.h>
20#import <stdio.h>
21#import <libkern/OSAtomic.h>
22#import <pthread.h>
23#import "test.h"
24
25int allocated = 0;
26int recovered = 0;
27
28@interface TestObject : NSObject
29@end
30@implementation TestObject
31- (id)init {
32    // printf("allocated...\n");
33    OSAtomicIncrement32(&allocated);
34    return self;
35}
36- (void)dealloc {
37    // printf("deallocated...\n");
38    OSAtomicIncrement32(&recovered);
39    [super dealloc];
40}
41- (void)finalize {
42    // printf("finalized...\n");
43    OSAtomicIncrement32(&recovered);
44    [super finalize];
45}
46
47#if 0
48- (id)retain {
49    printf("retaining...\n");
50    return [super retain];
51}
52
53- (void)release {
54    printf("releasing...\n");
55    [super release];
56}
57#endif
58@end
59
60void recoverMemory(const char *caller) {
61    objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE);
62    objc_collect(OBJC_EXHAUSTIVE_COLLECTION|OBJC_WAIT_UNTIL_DONE);
63    if (recovered != allocated) {
64        fail("after %s recovered %d vs allocated %d", caller, recovered, allocated);
65    }
66}
67
68// test that basic refcounting works
69void *testsingle(void *arg __unused) {
70    objc_registerThreadWithCollector();
71    TestObject *to = [TestObject new];
72    void (^b)(void) = [^{ printf("hi %p\n", to); } copy];
73    [b release];
74    [to release];
75    return NULL;
76}
77
78void *testlatch(void *arg __unused) {
79    objc_registerThreadWithCollector();
80    TestObject *to = [TestObject new];
81    void (^b)(void) = [^{ printf("hi %p\n", to); } copy];
82    for (int i = 0; i < 0xfffff; ++i) {
83        (void)Block_copy(b);
84    }
85    for (int i = 0; i < 10; ++i) {
86        Block_release(b);
87    }
88    [b release];
89    [to release];
90    // lie - b should not be recovered because it has been over-retained
91    OSAtomicIncrement32(&recovered);
92    return NULL;
93}
94
95void *testmultiple(void *arg __unused) {
96    objc_registerThreadWithCollector();
97    TestObject *to = [TestObject new];
98    void (^b)(void) = [^{ printf("hi %p\n", to); } copy];
99#if 2
100    for (int i = 0; i < 10; ++i) {
101        (void)Block_copy(b);
102    }
103    for (int i = 0; i < 10; ++i) {
104        Block_release(b);
105    }
106#endif
107    [b release];
108    [to release];
109    return NULL;
110}
111
112int main() {
113    pthread_t th;
114
115    pthread_create(&th, NULL, testsingle, NULL);
116    pthread_join(th, NULL);
117    pthread_create(&th, NULL, testsingle, NULL);
118    pthread_join(th, NULL);
119    pthread_create(&th, NULL, testsingle, NULL);
120    pthread_join(th, NULL);
121    pthread_create(&th, NULL, testsingle, NULL);
122    pthread_join(th, NULL);
123    recoverMemory("testsingle");
124
125    pthread_create(&th, NULL, testlatch, NULL);
126    pthread_join(th, NULL);
127    recoverMemory("testlatch");
128
129    pthread_create(&th, NULL, testmultiple, NULL);
130    pthread_join(th, NULL);
131    recoverMemory("testmultiple");
132
133    succeed(__FILE__);
134}
135