Skip to content

Commit 68e755b

Browse files
Bleibrson
authored andcommitted
core: Allocate threads on demand, not on scheduler startup
API change: rust_kernel::create_scheduler() or rust_scheduler::rust_scheduler() respecitevly now take ownership of the launch factory argument, it is needed to create new threads on demand. Also renames rustrt::sched_threads() to rustrt::rust_sched_threads() for consistency. Added rustrt::rust_max_sched_threads() to return the maximal number of scheduled threads of the current scheduler. Fixes #3493.
1 parent 35a9353 commit 68e755b

File tree

8 files changed

+102
-48
lines changed

8 files changed

+102
-48
lines changed

src/libcore/task.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,7 +1661,8 @@ extern mod rustrt {
16611661

16621662
fn rust_get_sched_id() -> sched_id;
16631663
fn rust_new_sched(num_threads: libc::uintptr_t) -> sched_id;
1664-
fn sched_threads() -> libc::size_t;
1664+
fn rust_max_sched_threads() -> libc::size_t;
1665+
fn rust_sched_threads() -> libc::size_t;
16651666
fn rust_num_threads() -> libc::uintptr_t;
16661667

16671668
fn get_task_id() -> task_id;
@@ -2435,10 +2436,36 @@ fn test_sched_thread_per_core() {
24352436

24362437
do spawn_sched(ThreadPerCore) {
24372438
let cores = rustrt::rust_num_threads();
2438-
let reported_threads = rustrt::sched_threads();
2439+
let reported_threads = rustrt::rust_max_sched_threads();
24392440
assert(cores as uint == reported_threads as uint);
24402441
chan.send(());
24412442
}
24422443

24432444
port.recv();
24442445
}
2446+
2447+
#[test]
2448+
fn test_spawn_thread_on_demand() {
2449+
let (chan, port) = pipes::stream();
2450+
2451+
do spawn_sched(ManualThreads(2)) {
2452+
let max_threads = rustrt::rust_max_sched_threads();
2453+
assert(max_threads as int == 2);
2454+
let running_threads = rustrt::rust_sched_threads();
2455+
assert(running_threads as int == 1);
2456+
2457+
let (chan2, port2) = pipes::stream();
2458+
2459+
do spawn() {
2460+
chan2.send(());
2461+
}
2462+
2463+
let running_threads2 = rustrt::rust_sched_threads();
2464+
assert(running_threads2 as int == 2);
2465+
2466+
port2.recv();
2467+
chan.send(());
2468+
}
2469+
2470+
port.recv();
2471+
}

src/libstd/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export run_tests_console;
2626

2727
#[abi = "cdecl"]
2828
extern mod rustrt {
29-
fn sched_threads() -> libc::size_t;
29+
fn rust_max_sched_threads() -> libc::size_t;
3030
}
3131

3232
// The name of a test. By convention this follows the rules for rust
@@ -327,7 +327,7 @@ const sched_overcommit : uint = 1u;
327327
const sched_overcommit : uint = 4u;
328328
329329
fn get_concurrency() -> uint {
330-
let threads = rustrt::sched_threads() as uint;
330+
let threads = rustrt::rust_max_sched_threads() as uint;
331331
if threads == 1u { 1u }
332332
else { threads * sched_overcommit }
333333
}

src/rt/rust_builtin.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,11 +627,17 @@ start_task(rust_task *target, fn_env_pair *f) {
627627
}
628628

629629
extern "C" CDECL size_t
630-
sched_threads() {
630+
rust_sched_threads() {
631631
rust_task *task = rust_get_current_task();
632632
return task->sched->number_of_threads();
633633
}
634634

635+
extern "C" CDECL size_t
636+
rust_max_sched_threads() {
637+
rust_task *task = rust_get_current_task();
638+
return task->sched->max_number_of_threads();
639+
}
640+
635641
extern "C" CDECL rust_port*
636642
rust_port_take(rust_port_id id) {
637643
rust_task *task = rust_get_current_task();

src/rt/rust_kernel.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ rust_kernel::rust_kernel(rust_env *env) :
3131

3232
// Create the single threaded scheduler that will run on the platform's
3333
// main thread
34-
rust_manual_sched_launcher_factory launchfac;
35-
osmain_scheduler = create_scheduler(&launchfac, 1, false);
36-
osmain_driver = launchfac.get_driver();
34+
rust_manual_sched_launcher_factory *launchfac =
35+
new rust_manual_sched_launcher_factory();
36+
osmain_scheduler = create_scheduler(launchfac, 1, false);
37+
osmain_driver = launchfac->get_driver();
3738
sched_reaper.start();
3839
}
3940

@@ -79,8 +80,9 @@ void rust_kernel::free(void *mem) {
7980

8081
rust_sched_id
8182
rust_kernel::create_scheduler(size_t num_threads) {
82-
rust_thread_sched_launcher_factory launchfac;
83-
return create_scheduler(&launchfac, num_threads, true);
83+
rust_thread_sched_launcher_factory *launchfac =
84+
new rust_thread_sched_launcher_factory();
85+
return create_scheduler(launchfac, num_threads, true);
8486
}
8587

8688
rust_sched_id

src/rt/rust_scheduler.cpp

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,39 @@
66
#include "rust_sched_launcher.h"
77

88
rust_scheduler::rust_scheduler(rust_kernel *kernel,
9-
size_t num_threads,
9+
size_t max_num_threads,
1010
rust_sched_id id,
1111
bool allow_exit,
1212
bool killed,
1313
rust_sched_launcher_factory *launchfac) :
1414
ref_count(1),
1515
kernel(kernel),
16-
live_threads(num_threads),
16+
live_threads(0),
1717
live_tasks(0),
1818
cur_thread(0),
1919
may_exit(allow_exit),
20-
num_threads(num_threads),
20+
killed(killed),
21+
launchfac(launchfac),
22+
max_num_threads(max_num_threads),
2123
id(id)
2224
{
23-
create_task_threads(launchfac, killed);
25+
// Create the first thread
26+
threads.push(create_task_thread(0));
2427
}
2528

2629
void rust_scheduler::delete_this() {
2730
destroy_task_threads();
31+
delete launchfac;
2832
delete this;
2933
}
3034

3135
rust_sched_launcher *
32-
rust_scheduler::create_task_thread(rust_sched_launcher_factory *launchfac,
33-
int id, bool killed) {
36+
rust_scheduler::create_task_thread(int id) {
37+
live_threads++;
3438
rust_sched_launcher *thread = launchfac->create(this, id, killed);
35-
KLOG(kernel, kern, "created task thread: " PTR ", id: %d",
36-
thread, id);
39+
KLOG(kernel, kern, "created task thread: " PTR
40+
", id: %d, live_threads: %d",
41+
thread, id, live_threads);
3742
return thread;
3843
}
3944

@@ -43,27 +48,17 @@ rust_scheduler::destroy_task_thread(rust_sched_launcher *thread) {
4348
delete thread;
4449
}
4550

46-
void
47-
rust_scheduler::create_task_threads(rust_sched_launcher_factory *launchfac,
48-
bool killed) {
49-
KLOG(kernel, kern, "Using %d scheduler threads.", num_threads);
50-
51-
for(size_t i = 0; i < num_threads; ++i) {
52-
threads.push(create_task_thread(launchfac, i, killed));
53-
}
54-
}
55-
5651
void
5752
rust_scheduler::destroy_task_threads() {
58-
for(size_t i = 0; i < num_threads; ++i) {
53+
for(size_t i = 0; i < threads.size(); ++i) {
5954
destroy_task_thread(threads[i]);
6055
}
6156
}
6257

6358
void
6459
rust_scheduler::start_task_threads()
6560
{
66-
for(size_t i = 0; i < num_threads; ++i) {
61+
for(size_t i = 0; i < threads.size(); ++i) {
6762
rust_sched_launcher *thread = threads[i];
6863
thread->start();
6964
}
@@ -72,15 +67,15 @@ rust_scheduler::start_task_threads()
7267
void
7368
rust_scheduler::join_task_threads()
7469
{
75-
for(size_t i = 0; i < num_threads; ++i) {
70+
for(size_t i = 0; i < threads.size(); ++i) {
7671
rust_sched_launcher *thread = threads[i];
7772
thread->join();
7873
}
7974
}
8075

8176
void
8277
rust_scheduler::kill_all_tasks() {
83-
for(size_t i = 0; i < num_threads; ++i) {
78+
for(size_t i = 0; i < threads.size(); ++i) {
8479
rust_sched_launcher *thread = threads[i];
8580
thread->get_loop()->kill_all_tasks();
8681
}
@@ -92,10 +87,29 @@ rust_scheduler::create_task(rust_task *spawner, const char *name) {
9287
{
9388
scoped_lock with(lock);
9489
live_tasks++;
95-
thread_no = cur_thread++;
96-
if (cur_thread >= num_threads)
97-
cur_thread = 0;
90+
91+
// Find unoccupied thread
92+
for (thread_no = 0; thread_no < threads.size(); ++thread_no) {
93+
if (threads[thread_no]->get_loop()->number_of_live_tasks() == 0)
94+
break;
95+
}
96+
97+
if (thread_no == threads.size()) {
98+
if (threads.size() < max_num_threads) {
99+
// Else create new thread
100+
thread_no = threads.size();
101+
rust_sched_launcher *thread = create_task_thread(thread_no);
102+
thread->start();
103+
threads.push(thread);
104+
} else {
105+
// Or use round robin allocation
106+
thread_no = cur_thread++;
107+
if (cur_thread >= max_num_threads)
108+
cur_thread = 0;
109+
}
110+
}
98111
}
112+
KLOG(kernel, kern, "Creating task %s, on thread %d.", name, thread_no);
99113
kernel->register_task();
100114
rust_sched_launcher *thread = threads[thread_no];
101115
return thread->get_loop()->create_task(spawner, name);
@@ -119,17 +133,22 @@ rust_scheduler::release_task() {
119133

120134
void
121135
rust_scheduler::exit() {
122-
// Take a copy of num_threads. After the last thread exits this
136+
// Take a copy of the number of threads. After the last thread exits this
123137
// scheduler will get destroyed, and our fields will cease to exist.
124-
size_t current_num_threads = num_threads;
138+
size_t current_num_threads = threads.size();
125139
for(size_t i = 0; i < current_num_threads; ++i) {
126140
threads[i]->get_loop()->exit();
127141
}
128142
}
129143

144+
size_t
145+
rust_scheduler::max_number_of_threads() {
146+
return max_num_threads;
147+
}
148+
130149
size_t
131150
rust_scheduler::number_of_threads() {
132-
return num_threads;
151+
return threads.size();
133152
}
134153

135154
void

src/rt/rust_scheduler.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,17 @@ class rust_scheduler : public kernel_owned<rust_scheduler> {
3030
uintptr_t live_tasks;
3131
size_t cur_thread;
3232
bool may_exit;
33+
bool killed;
3334

35+
rust_sched_launcher_factory *launchfac;
3436
array_list<rust_sched_launcher *> threads;
35-
const size_t num_threads;
37+
const size_t max_num_threads;
3638

3739
rust_sched_id id;
3840

39-
void create_task_threads(rust_sched_launcher_factory *launchfac,
40-
bool killed);
4141
void destroy_task_threads();
4242

43-
rust_sched_launcher *
44-
create_task_thread(rust_sched_launcher_factory *launchfac, int id,
45-
bool killed);
43+
rust_sched_launcher *create_task_thread(int id);
4644
void destroy_task_thread(rust_sched_launcher *thread);
4745

4846
void exit();
@@ -51,7 +49,7 @@ class rust_scheduler : public kernel_owned<rust_scheduler> {
5149
void delete_this();
5250

5351
public:
54-
rust_scheduler(rust_kernel *kernel, size_t num_threads,
52+
rust_scheduler(rust_kernel *kernel, size_t max_num_threads,
5553
rust_sched_id id, bool allow_exit, bool killed,
5654
rust_sched_launcher_factory *launchfac);
5755

@@ -62,6 +60,7 @@ class rust_scheduler : public kernel_owned<rust_scheduler> {
6260

6361
void release_task();
6462

63+
size_t max_number_of_threads();
6564
size_t number_of_threads();
6665
// Called by each thread when it terminates. When all threads
6766
// terminate the scheduler does as well.

src/rt/rustrt.def.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ rand_new_seeded
3030
rand_next
3131
rand_seed
3232
rust_get_sched_id
33+
rust_max_sched_threads
3334
rust_new_sched
3435
rust_new_task_in_sched
3536
rust_num_threads
@@ -48,6 +49,7 @@ rust_port_size
4849
rust_process_wait
4950
rust_ptr_eq
5051
rust_run_program
52+
rust_sched_threads
5153
rust_set_exit_status
5254
rust_start
5355
rust_getcwd
@@ -58,7 +60,6 @@ rust_get_task
5860
rust_get_stack_segment
5961
rust_task_weaken
6062
rust_task_unweaken
61-
sched_threads
6263
shape_log_str
6364
start_task
6465
vec_reserve_shared_actual

src/test/run-pass/morestack6.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ extern mod rustrt {
88
fn last_os_error() -> ~str;
99
fn rust_getcwd() -> ~str;
1010
fn get_task_id() -> libc::intptr_t;
11-
fn sched_threads();
11+
fn rust_max_sched_threads();
1212
fn rust_get_task();
1313
}
1414

1515
fn calllink01() { rustrt::rust_get_sched_id(); }
1616
fn calllink02() { rustrt::last_os_error(); }
1717
fn calllink03() { rustrt::rust_getcwd(); }
1818
fn calllink08() { rustrt::get_task_id(); }
19-
fn calllink09() { rustrt::sched_threads(); }
19+
fn calllink09() { rustrt::rust_max_sched_threads(); }
2020
fn calllink10() { rustrt::rust_get_task(); }
2121

2222
fn runtest(f: fn~(), frame_backoff: u32) {

0 commit comments

Comments
 (0)