1// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2// REQUIRES: linux
3#include "test.h"
4
5#include <pthread.h>
6#include <sys/types.h>
7#include <unistd.h>
8
9long count_memory_mappings() {
10 pid_t my_pid = getpid();
11 char proc_file_name[128];
12 snprintf(proc_file_name, sizeof(proc_file_name), "/proc/%d/maps", my_pid);
13
14 FILE *proc_file = fopen(proc_file_name, "r");
15 long line_count = 0;
16 int c;
17 do {
18 c = fgetc(proc_file);
19 if (c == '\n') {
20 line_count++;
21 }
22 } while (c != EOF);
23 fclose(proc_file);
24
25 return line_count;
26}
27
28void fiber_iteration() {
29 void *orig_fiber = __tsan_get_current_fiber();
30 void *fiber = __tsan_create_fiber(0);
31
32 pthread_mutex_t mutex;
33 pthread_mutex_init(&mutex, NULL);
34
35 // Running some code on the fiber that triggers handling of pending signals.
36 __tsan_switch_to_fiber(fiber, 0);
37 pthread_mutex_lock(&mutex);
38 pthread_mutex_unlock(&mutex);
39 __tsan_switch_to_fiber(orig_fiber, 0);
40
41 // We expect the fiber to clean up all resources (here the sigcontext) when destroyed.
42 __tsan_destroy_fiber(fiber);
43}
44
45// Magic-Number for some warmup iterations,
46// as tsan maps some memory for the first runs.
47const size_t num_warmup = 100;
48
49int main() {
50 for (size_t i = 0; i < num_warmup; i++) {
51 fiber_iteration();
52 }
53
54 long memory_mappings_before = count_memory_mappings();
55 fiber_iteration();
56 fiber_iteration();
57 long memory_mappings_after = count_memory_mappings();
58
59 // Is there a better way to detect a resource leak in the
60 // ThreadState object? (i.e. a mmap not being freed)
61 if (memory_mappings_before == memory_mappings_after) {
62 fprintf(stderr, "PASS\n");
63 } else {
64 fprintf(stderr, "FAILED\n");
65 }
66
67 return 0;
68}
69
70// CHECK-NOT: WARNING: ThreadSanitizer:
71// CHECK: PASS
72