forked from dlang/druntime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathattach_detach.d
More file actions
160 lines (134 loc) · 3.06 KB
/
attach_detach.d
File metadata and controls
160 lines (134 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
version (Posix)
{
import core.thread;
import core.sys.posix.pthread;
import core.stdc.stdlib;
import core.stdc.time;
// This program creates threads that are started outside of D runtime and
// stresses attaching and detaching those threads to the D runtime.
struct MyThread
{
pthread_t t;
bool stopRequested;
}
enum totalThreads = 4;
enum runTimeSeconds = 5; // Must be less than timelimit's
MyThread[totalThreads] threads;
auto exerciseGC() {
int[] arr;
foreach (i; 0 .. 1000)
arr ~= i;
return arr;
}
// This represents an API function of a non-D framework. Since we don't have any
// control on the lifetime of this thread, we have to attach upon entry and
// detach upon exit.
void api_foo()
{
auto t = thread_attachThis();
scope(exit)
{
// Pick a detachment method
final switch (rand() % 3)
{
case 0:
thread_detachThis();
break;
case 1:
thread_detachByAddr(t.id);
// thread_setThis must be called by the detached thread; it happens
// to be the case in this test.
thread_setThis(null);
break;
case 2:
thread_detachInstance(t);
// thread_setThis must be called by the detached thread; it happens
// to be the case in this test.
thread_setThis(null);
break;
}
}
assert_thread_is_attached(t.id);
cast(void)exerciseGC();
}
// Make calls to an api function and exit when requested
extern(C) void * thread_func(void * arg)
{
MyThread *t = cast(MyThread*)arg;
while (!t.stopRequested)
api_foo();
return arg;
}
void start_thread(ref MyThread t)
{
pthread_attr_t attr;
int err = pthread_attr_init(&attr);
assert(!err);
t.stopRequested = false;
err = pthread_create(&t.t, &attr, &thread_func, cast(void*)&t);
assert(!err);
err = pthread_attr_destroy(&attr);
assert(!err);
}
void start_threads()
{
foreach (ref t; threads)
start_thread(t);
}
void stop_thread(ref MyThread t)
{
t.stopRequested = true;
const err = pthread_join(t.t, null);
assert(!err);
assert_thread_is_gone(t.t);
}
void stop_threads()
{
foreach (ref t; threads)
stop_thread(t);
}
void assert_thread_is_attached(pthread_t tid)
{
size_t found = 0;
foreach (t; Thread.getAll())
if (tid == t.id)
{
++found;
}
assert(found == 1);
}
void assert_thread_is_gone(pthread_t tid)
{
foreach (t; Thread.getAll())
assert(tid != t.id);
}
// Occasionally stop threads and start new ones
void watch_threads()
{
const start = time(null);
while ((time(null) - start) < runTimeSeconds)
{
foreach (ref t; threads)
{
const shouldStop = ((rand() % 100) == 0);
if (shouldStop)
{
stop_thread(t);
start_thread(t);
}
}
}
}
void main()
{
start_threads();
watch_threads();
stop_threads();
}
} // version (Posix)
else
{
void main()
{
}
}