Home | History | Annotate | Download | only in Darwin
      1 // RUN: %clangxx_tsan %s -o %t -framework Foundation
      2 // RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
      3 
      4 #import <Foundation/Foundation.h>
      5 
      6 #import <assert.h>
      7 #import <memory>
      8 #import <stdatomic.h>
      9 
     10 _Atomic(long) shared_call_counter = 0;
     11 _Atomic(long) weak_call_counter = 0;
     12 _Atomic(long) destructor_counter = 0;
     13 _Atomic(long) weak_destroyed_counter = 0;
     14 
     15 struct MyStruct {
     16   _Atomic(long) self_counter = 0;
     17   virtual void shared_call() {
     18     atomic_fetch_add_explicit(&self_counter, 1, memory_order_relaxed);
     19     atomic_fetch_add_explicit(&shared_call_counter, 1, memory_order_relaxed);
     20   }
     21   virtual void weak_call() {
     22     atomic_fetch_add_explicit(&weak_call_counter, 1, memory_order_relaxed);
     23   }
     24   virtual ~MyStruct() {
     25     long n = self_counter;
     26     assert(n == 1000);
     27     atomic_fetch_add_explicit(&destructor_counter, 1, memory_order_relaxed);
     28   }
     29 };
     30 
     31 int main(int argc, const char *argv[]) {
     32   fprintf(stderr, "Hello world.\n");
     33 
     34   dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     35 
     36   dispatch_group_t g = dispatch_group_create();
     37 
     38   for (int i = 0; i < 1000; i++) {
     39     std::shared_ptr<MyStruct> shared(new MyStruct());
     40     std::weak_ptr<MyStruct> weak(shared);
     41 
     42     dispatch_group_async(g, q, ^{
     43       for (int j = 0; j < 1000; j++) {
     44         std::shared_ptr<MyStruct> shared_copy(shared);
     45         shared_copy->shared_call();
     46       }
     47     });
     48     dispatch_group_async(g, q, ^{
     49       for (int j = 0; j < 1000; j++) {
     50         std::shared_ptr<MyStruct> weak_copy = weak.lock();
     51         if (weak_copy) {
     52           weak_copy->weak_call();
     53         } else {
     54           atomic_fetch_add_explicit(&weak_destroyed_counter, 1, memory_order_relaxed);
     55           break;
     56         }
     57       }
     58     });
     59   }
     60 
     61   dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
     62 
     63   fprintf(stderr, "shared_call_counter = %ld\n", shared_call_counter);
     64   fprintf(stderr, "weak_call_counter = %ld\n", weak_call_counter);
     65   fprintf(stderr, "destructor_counter = %ld\n", destructor_counter);
     66   fprintf(stderr, "weak_destroyed_counter = %ld\n", weak_destroyed_counter);
     67 
     68   fprintf(stderr, "Done.\n");
     69 }
     70 
     71 // CHECK: Hello world.
     72 // CHECK: shared_call_counter = 1000000
     73 // CHECK: destructor_counter = 1000
     74 // CHECK: Done.
     75 // CHECK-NOT: WARNING: ThreadSanitizer
     76