@@ -121,12 +121,6 @@ unconfig_valgrind_stack(stk_seg *stk) {
121
121
VALGRIND_STACK_DEREGISTER (stk->valgrind_id );
122
122
}
123
123
124
- static void
125
- free_stk (rust_task *task, stk_seg *stk) {
126
- LOGPTR (task->sched , " freeing stk segment" , (uintptr_t )stk);
127
- task->free (stk);
128
- }
129
-
130
124
static void
131
125
add_stack_canary (stk_seg *stk) {
132
126
memcpy (stk->data , stack_canary, sizeof (stack_canary));
@@ -139,6 +133,21 @@ check_stack_canary(stk_seg *stk) {
139
133
&& " Somebody killed the canary" );
140
134
}
141
135
136
+ // The amount of stack in a segment available to Rust code
137
+ static size_t
138
+ user_stack_size (stk_seg *stk) {
139
+ return (size_t )(stk->end
140
+ - (uintptr_t )&stk->data [0 ]
141
+ - RED_ZONE_SIZE);
142
+ }
143
+
144
+ static void
145
+ free_stk (rust_task *task, stk_seg *stk) {
146
+ LOGPTR (task->sched , " freeing stk segment" , (uintptr_t )stk);
147
+ task->total_stack_sz -= user_stack_size (stk);
148
+ task->free (stk);
149
+ }
150
+
142
151
static stk_seg*
143
152
new_stk (rust_scheduler *sched, rust_task *task, size_t requested_sz)
144
153
{
@@ -152,9 +161,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
152
161
153
162
// Try to reuse an existing stack segment
154
163
if (task->stk != NULL && task->stk ->prev != NULL ) {
155
- size_t prev_sz = (size_t )(task->stk ->prev ->end
156
- - (uintptr_t )&task->stk ->prev ->data [0 ]
157
- - RED_ZONE_SIZE);
164
+ size_t prev_sz = user_stack_size (task->stk ->prev );
158
165
if (min_sz <= prev_sz && requested_sz <= prev_sz) {
159
166
LOG (task, mem, " reusing existing stack" );
160
167
task->stk = task->stk ->prev ;
@@ -171,14 +178,17 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
171
178
// The size of the current stack segment, excluding red zone
172
179
size_t current_sz = 0 ;
173
180
if (task->stk != NULL ) {
174
- current_sz = (size_t )(task->stk ->end
175
- - (uintptr_t )&task->stk ->data [0 ]
176
- - RED_ZONE_SIZE);
181
+ current_sz = user_stack_size (task->stk );
177
182
}
178
183
// The calculated size of the new stack, excluding red zone
179
184
size_t rust_stk_sz = get_next_stk_size (sched, task, min_sz,
180
185
current_sz, requested_sz);
181
186
187
+ if (task->total_stack_sz + rust_stk_sz > sched->env ->max_stack_size ) {
188
+ LOG_ERR (task, task, " task %" PRIxPTR " ran out of stack" , task);
189
+ task->fail ();
190
+ }
191
+
182
192
size_t sz = sizeof (stk_seg) + rust_stk_sz + RED_ZONE_SIZE;
183
193
stk_seg *stk = (stk_seg *)task->malloc (sz, " stack" );
184
194
LOGPTR (task->sched , " new stk" , (uintptr_t )stk);
@@ -191,6 +201,7 @@ new_stk(rust_scheduler *sched, rust_task *task, size_t requested_sz)
191
201
192
202
task->stk = stk;
193
203
config_valgrind_stack (task->stk );
204
+ task->total_stack_sz += user_stack_size (stk);
194
205
return stk;
195
206
}
196
207
@@ -222,6 +233,7 @@ del_stk(rust_task *task, stk_seg *stk)
222
233
unconfig_valgrind_stack (stk);
223
234
if (delete_stack) {
224
235
free_stk (task, stk);
236
+ A (task->sched , task->total_stack_sz == 0 , " Stack size should be 0" );
225
237
}
226
238
}
227
239
@@ -249,7 +261,8 @@ rust_task::rust_task(rust_scheduler *sched, rust_task_list *state,
249
261
killed(false ),
250
262
propagate_failure(true ),
251
263
dynastack(this ),
252
- cc_counter(0 )
264
+ cc_counter(0 ),
265
+ total_stack_sz(0 )
253
266
{
254
267
LOGPTR (sched, " new task" , (uintptr_t )this );
255
268
DLOG (sched, task, " sizeof(task) = %d (0x%x)" , sizeof *this , sizeof *this );
0 commit comments