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