Skip to content

Commit e325146

Browse files
committed
Merge remote-tracking branch 'brson/mainthread'
Conflicts: src/rt/rust_kernel.cpp src/rt/rust_scheduler.cpp src/rt/rust_scheduler.h
2 parents bd97ee6 + 4cf7efc commit e325146

File tree

11 files changed

+248
-30
lines changed

11 files changed

+248
-30
lines changed

src/libcore/task.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ enum sched_mode {
8888
thread_per_task,
8989
#[doc = "Tasks are distributed among a fixed number of OS threads"]
9090
manual_threads(uint),
91+
#[doc = "
92+
Tasks are scheduled on the main OS thread
93+
94+
The main OS thread is the thread used to launch the runtime which,
95+
in most cases, is the process's initial thread as created by the OS.
96+
"]
97+
osmain
9198
}
9299

93100
#[doc = "
@@ -107,7 +114,7 @@ Scheduler configuration options
107114
"]
108115
type sched_opts = {
109116
mode: sched_mode,
110-
native_stack_size: option<uint>,
117+
native_stack_size: option<uint>
111118
};
112119

113120
#[doc = "
@@ -525,9 +532,14 @@ fn spawn_raw(opts: task_opts, +f: fn~()) unsafe {
525532
}
526533
threads
527534
}
535+
osmain { 0u /* Won't be used */ }
528536
};
529537

530-
let sched_id = rustrt::rust_new_sched(num_threads);
538+
let sched_id = if opts.mode != osmain {
539+
rustrt::rust_new_sched(num_threads)
540+
} else {
541+
rustrt::rust_osmain_sched_id()
542+
};
531543
rustrt::rust_new_task_in_sched(sched_id)
532544
}
533545

@@ -553,6 +565,7 @@ native mod rustrt {
553565

554566
fn rust_task_is_unwinding(rt: *rust_task) -> bool;
555567
fn unsupervise();
568+
fn rust_osmain_sched_id() -> sched_id;
556569
}
557570

558571

@@ -897,3 +910,23 @@ fn test_avoid_copying_the_body_unsupervise() {
897910
}
898911
}
899912
}
913+
914+
#[test]
915+
fn test_osmain() {
916+
let builder = task_builder();
917+
let opts = {
918+
sched: some({
919+
mode: osmain,
920+
native_stack_size: none
921+
})
922+
with get_opts(builder)
923+
};
924+
set_opts(builder, opts);
925+
926+
let po = comm::port();
927+
let ch = comm::chan(po);
928+
run(builder) {||
929+
comm::send(ch, ());
930+
}
931+
comm::recv(po);
932+
}

src/rt/rust.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
9393
root_task->start((spawn_fn)main_fn, NULL, args->args);
9494
root_task = NULL;
9595

96-
int ret = kernel->wait_for_exit();
96+
int ret = kernel->run();
9797
delete args;
9898
delete kernel;
9999

src/rt/rust_builtin.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,12 @@ rust_dbg_call(dbg_callback cb, void *data) {
640640
return cb(data);
641641
}
642642

643+
extern "C" CDECL rust_sched_id
644+
rust_osmain_sched_id() {
645+
rust_task *task = rust_get_current_task();
646+
return task->kernel->osmain_sched_id();
647+
}
648+
643649
//
644650
// Local Variables:
645651
// mode: C++

src/rt/rust_kernel.cpp

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "rust_port.h"
66
#include "rust_util.h"
77
#include "rust_scheduler.h"
8+
#include "rust_sched_launcher.h"
89

910
#define KLOG_(...) \
1011
KLOG(this, kern, __VA_ARGS__)
@@ -19,8 +20,15 @@ rust_kernel::rust_kernel(rust_env *env) :
1920
rval(0),
2021
max_sched_id(0),
2122
sched_reaper(this),
23+
osmain_driver(NULL),
2224
env(env)
2325
{
26+
// Create the single threaded scheduler that will run on the platform's
27+
// main thread
28+
rust_manual_sched_launcher_factory launchfac;
29+
osmain_scheduler = create_scheduler(&launchfac, 1, false);
30+
osmain_driver = launchfac.get_driver();
31+
sched_reaper.start();
2432
}
2533

2634
void
@@ -60,24 +68,36 @@ void rust_kernel::free(void *mem) {
6068

6169
rust_sched_id
6270
rust_kernel::create_scheduler(size_t num_threads) {
71+
rust_thread_sched_launcher_factory launchfac;
72+
return create_scheduler(&launchfac, num_threads, true);
73+
}
74+
75+
rust_sched_id
76+
rust_kernel::create_scheduler(rust_sched_launcher_factory *launchfac,
77+
size_t num_threads, bool allow_exit) {
6378
rust_sched_id id;
6479
rust_scheduler *sched;
6580
{
6681
scoped_lock with(sched_lock);
67-
// If this is the first scheduler then we need to launch
68-
// the scheduler reaper.
69-
bool start_reaper = sched_table.empty();
82+
83+
if (sched_table.size() == 1) {
84+
// The OS main scheduler may not exit while there are other
85+
// schedulers
86+
KLOG_("Disallowing osmain scheduler to exit");
87+
rust_scheduler *sched =
88+
get_scheduler_by_id_nolock(osmain_scheduler);
89+
assert(sched != NULL);
90+
sched->disallow_exit();
91+
}
92+
7093
id = max_sched_id++;
7194
assert(id != INTPTR_MAX && "Hit the maximum scheduler id");
7295
sched = new (this, "rust_scheduler")
73-
rust_scheduler(this, num_threads, id);
96+
rust_scheduler(this, num_threads, id, allow_exit, launchfac);
7497
bool is_new = sched_table
7598
.insert(std::pair<rust_sched_id,
7699
rust_scheduler*>(id, sched)).second;
77100
assert(is_new && "Reusing a sched id?");
78-
if (start_reaper) {
79-
sched_reaper.start();
80-
}
81101
}
82102
sched->start_task_threads();
83103
return id;
@@ -86,6 +106,12 @@ rust_kernel::create_scheduler(size_t num_threads) {
86106
rust_scheduler *
87107
rust_kernel::get_scheduler_by_id(rust_sched_id id) {
88108
scoped_lock with(sched_lock);
109+
return get_scheduler_by_id_nolock(id);
110+
}
111+
112+
rust_scheduler *
113+
rust_kernel::get_scheduler_by_id_nolock(rust_sched_id id) {
114+
sched_lock.must_have_lock();
89115
sched_map::iterator iter = sched_table.find(id);
90116
if (iter != sched_table.end()) {
91117
return iter->second;
@@ -117,23 +143,35 @@ rust_kernel::wait_for_schedulers()
117143
while (!sched_table.empty()) {
118144
while (!join_list.empty()) {
119145
rust_sched_id id = join_list.back();
146+
KLOG_("Deleting scheduler %d", id);
120147
join_list.pop_back();
121148
sched_map::iterator iter = sched_table.find(id);
122149
assert(iter != sched_table.end());
123150
rust_scheduler *sched = iter->second;
124151
sched_table.erase(iter);
125152
sched->join_task_threads();
126153
delete sched;
154+
if (sched_table.size() == 1) {
155+
KLOG_("Allowing osmain scheduler to exit");
156+
// It's only the osmain scheduler left. Tell it to exit
157+
rust_scheduler *sched =
158+
get_scheduler_by_id_nolock(osmain_scheduler);
159+
assert(sched != NULL);
160+
sched->allow_exit();
161+
}
127162
}
128163
if (!sched_table.empty()) {
129164
sched_lock.wait();
130165
}
131166
}
132167
}
133168

134-
/* Called on the main thread to wait for the kernel to exit */
169+
/* Called on the main thread to run the osmain scheduler to completion,
170+
then wait for schedulers to exit */
135171
int
136-
rust_kernel::wait_for_exit() {
172+
rust_kernel::run() {
173+
assert(osmain_driver != NULL);
174+
osmain_driver->start_main_loop();
137175
sched_reaper.join();
138176
return rval;
139177
}

src/rt/rust_kernel.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ typedef intptr_t rust_port_id;
2222

2323
typedef std::map<rust_sched_id, rust_scheduler*> sched_map;
2424

25+
class rust_sched_driver;
26+
class rust_sched_launcher_factory;
27+
2528
/**
2629
* A global object shared by all thread domains. Most of the data structures
2730
* in this class are synchronized since they are accessed from multiple
@@ -54,6 +57,13 @@ class rust_kernel {
5457
std::vector<rust_sched_id> join_list;
5558

5659
rust_sched_reaper sched_reaper;
60+
// The single-threaded scheduler that uses the main thread
61+
rust_sched_id osmain_scheduler;
62+
// Runs the single-threaded scheduler that executes tasks
63+
// on the main thread
64+
rust_sched_driver *osmain_driver;
65+
66+
rust_scheduler* get_scheduler_by_id_nolock(rust_sched_id id);
5767

5868
public:
5969
struct rust_env *env;
@@ -71,11 +81,13 @@ class rust_kernel {
7181
void fail();
7282

7383
rust_sched_id create_scheduler(size_t num_threads);
84+
rust_sched_id create_scheduler(rust_sched_launcher_factory *launchfac,
85+
size_t num_threads, bool allow_exit);
7486
rust_scheduler* get_scheduler_by_id(rust_sched_id id);
7587
// Called by a scheduler to indicate that it is terminating
7688
void release_scheduler_id(rust_sched_id id);
7789
void wait_for_schedulers();
78-
int wait_for_exit();
90+
int run();
7991

8092
#ifdef __WIN32__
8193
void win32_require(LPCTSTR fn, BOOL ok);
@@ -88,6 +100,8 @@ class rust_kernel {
88100
void release_port_id(rust_port_id tid);
89101

90102
void set_exit_status(int code);
103+
104+
rust_sched_id osmain_sched_id() { return osmain_scheduler; }
91105
};
92106

93107
template <typename T> struct kernel_owned {

src/rt/rust_sched_launcher.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,21 @@ rust_thread_sched_launcher::rust_thread_sched_launcher(rust_scheduler *sched,
1616
rust_thread(SCHED_STACK_SIZE) {
1717
}
1818

19+
rust_manual_sched_launcher::rust_manual_sched_launcher(rust_scheduler *sched,
20+
int id)
21+
: rust_sched_launcher(sched, id) {
22+
}
23+
24+
rust_sched_launcher *
25+
rust_thread_sched_launcher_factory::create(rust_scheduler *sched, int id) {
26+
return new(sched->kernel, "rust_thread_sched_launcher")
27+
rust_thread_sched_launcher(sched, id);
28+
}
29+
30+
rust_sched_launcher *
31+
rust_manual_sched_launcher_factory::create(rust_scheduler *sched, int id) {
32+
assert(launcher == NULL && "I can only track one sched_launcher");
33+
launcher = new(sched->kernel, "rust_manual_sched_launcher")
34+
rust_manual_sched_launcher(sched, id);
35+
return launcher;
36+
}

src/rt/rust_sched_launcher.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,42 @@ class rust_thread_sched_launcher
3131
public:
3232
rust_thread_sched_launcher(rust_scheduler *sched, int id);
3333
virtual void start() { rust_thread::start(); }
34-
virtual void run() { driver.start_main_loop(); }
3534
virtual void join() { rust_thread::join(); }
35+
virtual void run() { driver.start_main_loop(); }
36+
};
37+
38+
class rust_manual_sched_launcher : public rust_sched_launcher {
39+
public:
40+
rust_manual_sched_launcher(rust_scheduler *sched, int id);
41+
virtual void start() { }
42+
virtual void join() { }
43+
rust_sched_driver *get_driver() { return &driver; };
44+
};
45+
46+
class rust_sched_launcher_factory {
47+
public:
48+
virtual ~rust_sched_launcher_factory() { }
49+
virtual rust_sched_launcher *
50+
create(rust_scheduler *sched, int id) = 0;
51+
};
52+
53+
class rust_thread_sched_launcher_factory
54+
: public rust_sched_launcher_factory {
55+
public:
56+
virtual rust_sched_launcher *create(rust_scheduler *sched, int id);
57+
};
58+
59+
class rust_manual_sched_launcher_factory
60+
: public rust_sched_launcher_factory {
61+
private:
62+
rust_manual_sched_launcher *launcher;
63+
public:
64+
rust_manual_sched_launcher_factory() : launcher(NULL) { }
65+
virtual rust_sched_launcher *create(rust_scheduler *sched, int id);
66+
rust_sched_driver *get_driver() {
67+
assert(launcher != NULL);
68+
return launcher->get_driver();
69+
}
3670
};
3771

3872
#endif // RUST_SCHED_LAUNCHER_H

0 commit comments

Comments
 (0)