Skip to content

Commit 79b1563

Browse files
committed
rt: Use rust_task_thread's C-stack pool for native calls
1 parent bfb8006 commit 79b1563

File tree

6 files changed

+96
-28
lines changed

6 files changed

+96
-28
lines changed

src/rt/arch/i386/context.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ struct registers_t {
2929
uint32_t eip;
3030
} __attribute__((aligned(16)));
3131

32-
extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
33-
3432
class context {
3533
public:
3634
registers_t regs;
@@ -41,10 +39,6 @@ class context {
4139

4240
void swap(context &out);
4341
void call(void *f, void *arg, void *sp);
44-
45-
void call_and_change_stacks(void *args, void *fn_ptr) {
46-
__morestack(args, fn_ptr, regs.esp);
47-
}
4842
};
4943

5044
#endif

src/rt/arch/x86_64/context.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ struct registers_t {
2828
uint64_t data[RUSTRT_MAX];
2929
} __attribute__((aligned(16)));
3030

31-
extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
32-
3331
class context {
3432
public:
3533
registers_t regs;
@@ -40,10 +38,6 @@ class context {
4038

4139
void swap(context &out);
4240
void call(void *f, void *arg, void *sp);
43-
44-
void call_and_change_stacks(void *args, void *fn_ptr) {
45-
__morestack(args, fn_ptr, regs.data[RUSTRT_RSP]);
46-
}
4741
};
4842

4943
#endif

src/rt/rust_task.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ rust_task::rust_task(rust_task_thread *thread, rust_task_list *state,
8888
propagate_failure(true),
8989
dynastack(this),
9090
cc_counter(0),
91-
total_stack_sz(0)
91+
total_stack_sz(0),
92+
c_stack(NULL),
93+
next_c_sp(0)
9294
{
9395
LOGPTR(thread, "new task", (uintptr_t)this);
9496
DLOG(thread, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
@@ -166,7 +168,6 @@ cleanup_task(cleanup_args *args) {
166168
}
167169

168170
// This runs on the Rust stack
169-
extern "C" CDECL
170171
void task_start_wrapper(spawn_args *a)
171172
{
172173
rust_task *task = a->task;
@@ -180,8 +181,15 @@ void task_start_wrapper(spawn_args *a)
180181
A(task->thread, ex == task,
181182
"Expected this task to be thrown for unwinding");
182183
threw_exception = true;
184+
185+
if (task->c_stack) {
186+
task->return_c_stack();
187+
}
183188
}
184189

190+
// We should have returned any C stack by now
191+
I(task->thread, task->c_stack == NULL);
192+
185193
rust_opaque_box* env = a->envptr;
186194
if(env) {
187195
// free the environment (which should be a unique closure).
@@ -722,10 +730,35 @@ rust_task::config_notify(chan_handle chan) {
722730
notify_chan = chan;
723731
}
724732

733+
extern "C" void __morestack(void *args, void *fn_ptr, uintptr_t stack_ptr);
734+
725735
void
726736
rust_task::call_on_c_stack(void *args, void *fn_ptr) {
727737
I(thread, on_rust_stack());
728-
thread->c_context.call_and_change_stacks(args, fn_ptr);
738+
739+
bool borrowed_a_c_stack = false;
740+
if (c_stack == NULL) {
741+
c_stack = thread->borrow_c_stack();
742+
next_c_sp = align_down(c_stack->end);
743+
borrowed_a_c_stack = true;
744+
}
745+
746+
__morestack(args, fn_ptr, next_c_sp);
747+
748+
// Note that we may not actually get here if we threw an exception,
749+
// in which case we will return the c stack when the exception is caught.
750+
if (borrowed_a_c_stack) {
751+
return_c_stack();
752+
}
753+
}
754+
755+
void
756+
rust_task::return_c_stack() {
757+
I(thread, on_rust_stack());
758+
I(thread, c_stack != NULL);
759+
thread->return_c_stack(c_stack);
760+
c_stack = NULL;
761+
next_c_sp = 0;
729762
}
730763

731764
//

src/rt/rust_task.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ typedef unsigned long task_result;
3636
#define tr_success 0
3737
#define tr_failure 1
3838

39+
struct spawn_args;
40+
3941
// std::lib::task::task_notification
4042
//
4143
// since it's currently a unary tag, we only add the fields.
@@ -104,6 +106,11 @@ rust_task : public kernel_owned<rust_task>, rust_cond
104106
size_t total_stack_sz;
105107

106108
private:
109+
110+
// The stack used for running C code, borrowed from the scheduler thread
111+
stk_seg *c_stack;
112+
uintptr_t next_c_sp;
113+
107114
// Called when the atomic refcount reaches zero
108115
void delete_this();
109116

@@ -112,6 +119,10 @@ rust_task : public kernel_owned<rust_task>, rust_cond
112119
void free_stack(stk_seg *stk);
113120
size_t get_next_stack_size(size_t min, size_t current, size_t requested);
114121

122+
void return_c_stack();
123+
124+
friend void task_start_wrapper(spawn_args *a);
125+
115126
public:
116127

117128
// Only a pointer to 'name' is kept, so it must live as long as this task.

src/rt/rust_task_thread.cpp

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,16 @@ rust_task_thread::~rust_task_thread() {
6161
#ifndef __WIN32__
6262
pthread_attr_destroy(&attr);
6363
#endif
64-
65-
if (cached_c_stack) {
66-
destroy_stack(kernel, cached_c_stack);
67-
}
6864
}
6965

7066
void
7167
rust_task_thread::activate(rust_task *task) {
7268
task->ctx.next = &c_context;
7369
DLOG(this, task, "descheduling...");
7470
lock.unlock();
71+
prepare_c_stack();
7572
task->ctx.swap(c_context);
73+
unprepare_c_stack();
7674
lock.lock();
7775
DLOG(this, task, "task has returned");
7876
}
@@ -287,6 +285,13 @@ rust_task_thread::start_main_loop() {
287285
DLOG(this, dom, "finished main-loop %d", id);
288286

289287
lock.unlock();
288+
289+
I(this, !extra_c_stack);
290+
if (cached_c_stack) {
291+
unconfig_valgrind_stack(cached_c_stack);
292+
destroy_stack(kernel, cached_c_stack);
293+
cached_c_stack = NULL;
294+
}
290295
}
291296

292297
rust_crate_cache *
@@ -374,24 +379,51 @@ rust_task_thread::exit() {
374379
lock.signal();
375380
}
376381

382+
// Before activating each task, make sure we have a C stack available.
383+
// It needs to be allocated ahead of time (while we're on our own
384+
// stack), because once we're on the Rust stack we won't have enough
385+
// room to do the allocation
386+
void
387+
rust_task_thread::prepare_c_stack() {
388+
I(this, !extra_c_stack);
389+
if (!cached_c_stack) {
390+
cached_c_stack = create_stack(kernel, C_STACK_SIZE);
391+
}
392+
}
393+
394+
void
395+
rust_task_thread::unprepare_c_stack() {
396+
if (extra_c_stack) {
397+
destroy_stack(kernel, extra_c_stack);
398+
extra_c_stack = NULL;
399+
}
400+
}
401+
402+
// NB: Runs on the Rust stack
377403
stk_seg *
378404
rust_task_thread::borrow_c_stack() {
379-
380-
if (cached_c_stack) {
381-
stk_seg *your_stack = cached_c_stack;
382-
cached_c_stack = NULL;
383-
return your_stack;
405+
I(this, cached_c_stack);
406+
stk_seg *your_stack;
407+
if (extra_c_stack) {
408+
your_stack = extra_c_stack;
409+
extra_c_stack = NULL;
384410
} else {
385-
return create_stack(kernel, C_STACK_SIZE);
411+
your_stack = cached_c_stack;
412+
cached_c_stack = NULL;
386413
}
414+
config_valgrind_stack(your_stack);
415+
return your_stack;
387416
}
388417

418+
// NB: Runs on the Rust stack
389419
void
390420
rust_task_thread::return_c_stack(stk_seg *stack) {
391-
if (cached_c_stack) {
392-
destroy_stack(kernel, stack);
393-
} else {
421+
I(this, !extra_c_stack);
422+
unconfig_valgrind_stack(stack);
423+
if (!cached_c_stack) {
394424
cached_c_stack = stack;
425+
} else {
426+
extra_c_stack = stack;
395427
}
396428
}
397429

src/rt/rust_task_thread.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ struct rust_task_thread : public kernel_owned<rust_task_thread>,
9595
private:
9696

9797
stk_seg *cached_c_stack;
98+
stk_seg *extra_c_stack;
99+
100+
void prepare_c_stack();
101+
void unprepare_c_stack();
98102

99103
public:
100104

0 commit comments

Comments
 (0)