-
Notifications
You must be signed in to change notification settings - Fork 376
/
fiber_stack.c
168 lines (143 loc) · 4.3 KB
/
fiber_stack.c
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
161
162
163
164
165
166
167
168
#include "memory.h"
#include "fiber.h"
#include "unit.h"
#include "trivia/util.h"
#include "errinj.h"
static struct fiber_attr default_attr;
/** Total count of allocated fibers in the cord. Including dead ones. */
static int
fiber_count_total(void)
{
size_t res = mempool_count(&cord()->fiber_mempool);
assert(res <= INT_MAX);
return (int)res;
}
static int
noop_f(va_list ap)
{
return 0;
}
static int
main_f(va_list ap)
{
struct slab_cache *slabc = &cord()->slabc;
size_t used_before, used_after;
struct errinj *inj;
struct fiber *fiber;
int fiber_count = fiber_count_total();
struct fiber_attr *fiber_attr;
header();
#ifdef NDEBUG
plan(1);
#else
plan(11);
#endif
/*
* gh-9026. Stack size crafted to be close to 64k so we should
* hit red zone around stack when writing watermark if bug is not
* fixed.
*
* The test is placed at the beginning because stderr is redirected
* to /dev/null at the end of the test and ASAN diagnostic will
* not be visible if the test will be placed at the end.
*/
fiber_attr = fiber_attr_new();
fiber_attr_setstacksize(fiber_attr, (64 << 10) - 128);
fiber = fiber_new_ex("gh-9026", fiber_attr, noop_f);
fiber_set_joinable(fiber, true);
fiber_start(fiber);
fiber_join(fiber);
fiber_attr_delete(fiber_attr);
/*
* Check the default fiber stack size value.
*/
fiber_attr = fiber_attr_new();
ok(default_attr.stack_size == FIBER_STACK_SIZE_DEFAULT,
"fiber_attr: the default stack size is %ld, but %d is set via CMake",
default_attr.stack_size, FIBER_STACK_SIZE_DEFAULT);
#ifndef NDEBUG
/*
* Set non-default stack size to prevent reusing of an
* existing fiber.
*/
fiber_attr_setstacksize(fiber_attr, default_attr.stack_size * 2);
/*
* Clear the fiber's diagnostics area to check that failed
* fiber_new() sets an error.
*/
diag_clear(diag_get());
/*
* Check guard page setup via mprotect. We can't test the fiber
* destroy path since it clears fiber's diag.
*/
inj = errinj(ERRINJ_FIBER_MPROTECT, ERRINJ_INT);
inj->iparam = PROT_NONE;
fiber = fiber_new_ex("test_mprotect", fiber_attr, noop_f);
inj->iparam = -1;
ok(fiber == NULL, "mprotect: failed to setup fiber guard page");
ok(diag_get() != NULL, "mprotect: diag is armed after error");
/*
* Check madvise error on fiber creation.
*/
diag_clear(diag_get());
inj = errinj(ERRINJ_FIBER_MADVISE, ERRINJ_BOOL);
inj->bparam = true;
fiber = fiber_new_ex("test_madvise", fiber_attr, noop_f);
inj->bparam = false;
ok(fiber_count_total() == fiber_count + 1, "allocated new");
ok(fiber != NULL, "madvise: non critical error on madvise hint");
ok(diag_get() != NULL, "madvise: diag is armed after error");
fiber_wakeup(fiber);
fiber_sleep(0);
cord_collect_garbage(cord());
ok(fiber_count_total() == fiber_count, "fiber is deleted");
/*
* Check if we leak on fiber destruction.
* We will print an error and result get
* compared by testing engine.
*/
fiber_attr_delete(fiber_attr);
fiber_attr = fiber_attr_new();
fiber_attr->flags |= FIBER_CUSTOM_STACK;
fiber_attr->stack_size = 64 << 10;
diag_clear(diag_get());
used_before = slabc->allocated.stats.used;
fiber = fiber_new_ex("test_madvise", fiber_attr, noop_f);
ok(fiber != NULL, "fiber with custom stack");
ok(fiber_count_total() == fiber_count + 1, "allocated new");
fiber_set_joinable(fiber, true);
inj = errinj(ERRINJ_FIBER_MPROTECT, ERRINJ_INT);
inj->iparam = PROT_READ | PROT_WRITE;
/* On fiber_mprotect() fail we are logging number of bytes to be
* leaked. However, it depends on system page_size (_SC_PAGESIZE).
* On different OS's this parameter may vary. So let's temporary
* redirect stderr to dev/null to make this test stable regardless
* of OS.
*/
freopen("/dev/null", "w", stderr);
fiber_start(fiber);
fiber_join(fiber);
inj->iparam = -1;
freopen("/dev/stderr", "w", stderr);
used_after = slabc->allocated.stats.used;
ok(used_after > used_before, "expected leak detected");
cord_collect_garbage(cord());
ok(fiber_count_total() == fiber_count, "fiber is deleted");
#endif /* ifndef NDEBUG */
fiber_attr_delete(fiber_attr);
ev_break(loop(), EVBREAK_ALL);
footer();
return 0;
}
int main()
{
memory_init();
fiber_init(fiber_c_invoke);
fiber_attr_create(&default_attr);
struct fiber *f = fiber_new("main", main_f);
fiber_wakeup(f);
ev_run(loop(), 0);
fiber_free();
memory_free();
return check_plan();
}