1// TEST_CONFIG MEM=mrc
2
3#include "test.h"
4#include <objc/NSObject.h>
5
6static semaphore_t go1;
7static semaphore_t go2;
8static semaphore_t done;
9
10#define VARCOUNT 100000
11static id obj;
12static id vars[VARCOUNT];
13
14
15void *destroyer(void *arg __unused)
16{
17    while (1) {
18        semaphore_wait(go1);
19        for (int i = 0; i < VARCOUNT; i++) {
20            objc_destroyWeak(&vars[i]);
21        }
22        semaphore_signal(done);
23    }
24}
25
26
27void *deallocator(void *arg __unused)
28{
29    while (1) {
30        semaphore_wait(go2);
31        [obj release];
32        semaphore_signal(done);
33    }
34}
35
36
37void cycle(void)
38{
39    // rdar://12896779 objc_destroyWeak() versus weak clear in dealloc
40
41    // Clean up from previous cycle - objc_destroyWeak() doesn't set var to nil
42    for (int i = 0; i < VARCOUNT; i++) {
43        vars[i] = nil;
44    }
45
46    obj = [NSObject new];
47    for (int i = 0; i < VARCOUNT; i++) {
48        objc_storeWeak(&vars[i], obj);
49    }
50
51    // let destroyer start before deallocator runs
52    semaphore_signal(go1);
53    sched_yield();
54    semaphore_signal(go2);
55    
56    semaphore_wait(done);
57    semaphore_wait(done);
58}
59
60
61int main()
62{
63    semaphore_create(mach_task_self(), &go1, 0, 0);
64    semaphore_create(mach_task_self(), &go2, 0, 0);
65    semaphore_create(mach_task_self(), &done, 0, 0);
66
67    pthread_t th[2];
68    pthread_create(&th[1], NULL, deallocator, NULL);
69    pthread_create(&th[1], NULL, destroyer, NULL);
70
71    for (int i = 0; i < 100; i++) {
72        cycle();
73    }
74
75    succeed(__FILE__);
76}
77