Skip to content

Commit bde9385

Browse files
committed
rt: Change the scheme used for terminating the kernel
Instead of joining on the scheduler threads, instead keep a count of active schedulers. When there are no more schedulers raise a signal for the main thread to continue. This will be required once schedulers can be added and removed from the running kernel.
1 parent e6a7e43 commit bde9385

File tree

5 files changed

+58
-11
lines changed

5 files changed

+58
-11
lines changed

src/rt/rust_kernel.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ rust_kernel::rust_kernel(rust_srv *srv, size_t num_threads) :
1818
{
1919
sched = new (this, "rust_scheduler")
2020
rust_scheduler(this, srv, num_threads);
21+
live_schedulers = 1;
22+
}
23+
24+
rust_kernel::~rust_kernel() {
25+
delete sched;
2126
}
2227

2328
void
@@ -41,10 +46,6 @@ rust_kernel::fatal(char const *fmt, ...) {
4146
va_end(args);
4247
}
4348

44-
rust_kernel::~rust_kernel() {
45-
delete sched;
46-
}
47-
4849
void *
4950
rust_kernel::malloc(size_t size, const char *tag) {
5051
return _region.malloc(size, tag);
@@ -61,15 +62,34 @@ void rust_kernel::free(void *mem) {
6162

6263
int rust_kernel::start_schedulers()
6364
{
65+
I(this, !sched_lock.lock_held_by_current_thread());
6466
sched->start_task_threads();
65-
return rval;
67+
{
68+
scoped_lock with(sched_lock);
69+
// Schedulers could possibly have already exited
70+
if (live_schedulers != 0) {
71+
sched_lock.wait();
72+
}
73+
return rval;
74+
}
6675
}
6776

6877
rust_scheduler *
6978
rust_kernel::get_default_scheduler() {
7079
return sched;
7180
}
7281

82+
void
83+
rust_kernel::release_scheduler() {
84+
I(this, !sched_lock.lock_held_by_current_thread());
85+
scoped_lock with(sched_lock);
86+
--live_schedulers;
87+
if (live_schedulers == 0) {
88+
// We're all done. Tell the main thread to continue
89+
sched_lock.signal();
90+
}
91+
}
92+
7393
void
7494
rust_kernel::fail() {
7595
// FIXME: On windows we're getting "Application has requested the

src/rt/rust_kernel.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ class rust_kernel {
3535
lock_and_signal rval_lock;
3636
int rval;
3737

38+
// Protects live_schedulers
39+
lock_and_signal sched_lock;
40+
// Tracks the number of schedulers currently running.
41+
// When this hits 0 we will signal the sched_lock and the
42+
// kernel will terminate.
43+
uintptr_t live_schedulers;
44+
3845
public:
3946

4047
struct rust_env *env;
@@ -53,6 +60,8 @@ class rust_kernel {
5360

5461
int start_schedulers();
5562
rust_scheduler* get_default_scheduler();
63+
// Called by a scheduler to indicate that it is terminating
64+
void release_scheduler();
5665

5766
#ifdef __WIN32__
5867
void win32_require(LPCTSTR fn, BOOL ok);

src/rt/rust_scheduler.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rust_scheduler::rust_scheduler(rust_kernel *kernel,
77
kernel(kernel),
88
srv(srv),
99
env(srv->env),
10+
live_threads(num_threads),
1011
num_threads(num_threads)
1112
{
1213
isaac_init(kernel, &rctx);
@@ -59,11 +60,6 @@ rust_scheduler::start_task_threads()
5960
rust_task_thread *thread = threads[i];
6061
thread->start();
6162
}
62-
63-
for(size_t i = 0; i < num_threads; ++i) {
64-
rust_task_thread *thread = threads[i];
65-
thread->join();
66-
}
6763
}
6864

6965
void
@@ -102,3 +98,16 @@ size_t
10298
rust_scheduler::number_of_threads() {
10399
return num_threads;
104100
}
101+
102+
void
103+
rust_scheduler::release_task_thread() {
104+
I(this, !lock.lock_held_by_current_thread());
105+
uintptr_t new_live_threads;
106+
{
107+
scoped_lock with(lock);
108+
new_live_threads = --live_threads;
109+
}
110+
if (new_live_threads == 0) {
111+
kernel->release_scheduler();
112+
}
113+
}

src/rt/rust_scheduler.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ class rust_scheduler : public kernel_owned<rust_scheduler> {
1010
rust_srv *srv;
1111
rust_env *env;
1212
private:
13+
// Protects the random number context and live_threads
1314
lock_and_signal lock;
14-
array_list<rust_task_thread *> threads;
15+
// When this hits zero we'll tell the kernel to release us
16+
uintptr_t live_threads;
1517
randctx rctx;
18+
19+
array_list<rust_task_thread *> threads;
1620
const size_t num_threads;
1721

1822
void create_task_threads();
@@ -31,8 +35,12 @@ class rust_scheduler : public kernel_owned<rust_scheduler> {
3135
const char *name,
3236
size_t init_stack_sz);
3337
rust_task_id create_task(rust_task *spawner, const char *name);
38+
3439
void exit();
3540
size_t number_of_threads();
41+
// Called by each thread when it terminates. When all threads
42+
// terminate the scheduler does as well.
43+
void release_task_thread();
3644
};
3745

3846
#endif /* RUST_SCHEDULER_H */

src/rt/rust_task_thread.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ rust_task_thread::create_task(rust_task *spawner, const char *name,
296296

297297
void rust_task_thread::run() {
298298
this->start_main_loop();
299+
sched->release_task_thread();
299300
}
300301

301302
#ifndef _WIN32

0 commit comments

Comments
 (0)