Skip to content

Commit 4e8f0fd

Browse files
Eric Holkgraydon
authored andcommitted
---
yaml --- r: 3358 b: refs/heads/master c: 4bc7734 h: refs/heads/master v: v3
1 parent 87533b6 commit 4e8f0fd

File tree

12 files changed

+179
-31
lines changed

12 files changed

+179
-31
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 91eadfd1ea1544513258fc30bf94ef384db2ad90
2+
refs/heads/master: 4bc773465fe95da37b8c867979786b190de6197c

trunk/src/rt/rust.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ rust_start(uintptr_t main_fn, int argc, char **argv, void* crate_map) {
9595

9696
dom->root_task->start(main_fn, (uintptr_t)args->args);
9797

98-
int ret = dom->start_main_loop();
98+
int ret = dom->start_main_loops(8);
9999
delete args;
100100
kernel->destroy_domain(dom);
101101
kernel->join_all_domains();

trunk/src/rt/rust_dom.cpp

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,14 @@ rust_dom::~rust_dom() {
4747

4848
void
4949
rust_dom::activate(rust_task *task) {
50-
curr_task = task;
51-
5250
context ctx;
5351

5452
task->ctx.next = &ctx;
5553
DLOG(this, task, "descheduling...");
54+
scheduler_lock.unlock();
5655
task->ctx.swap(ctx);
56+
scheduler_lock.lock();
5757
DLOG(this, task, "task has returned");
58-
59-
curr_task = NULL;
6058
}
6159

6260
void
@@ -211,10 +209,13 @@ rust_dom::schedule_task() {
211209
// FIXME: in the face of failing tasks, this is not always right.
212210
// I(this, n_live_tasks() > 0);
213211
if (running_tasks.length() > 0) {
214-
size_t i = rand(&rctx);
215-
i %= running_tasks.length();
216-
if (running_tasks[i]->yield_timer.has_timed_out()) {
217-
return (rust_task *)running_tasks[i];
212+
size_t k = rand(&rctx);
213+
// Look around for a runnable task, starting at k.
214+
for(size_t j = 0; j < running_tasks.length(); ++j) {
215+
size_t i = (j + k) % running_tasks.length();
216+
if (running_tasks[i]->can_schedule()) {
217+
return (rust_task *)running_tasks[i];
218+
}
218219
}
219220
}
220221
return NULL;
@@ -261,15 +262,20 @@ rust_dom::log_state() {
261262
* drop to zero.
262263
*/
263264
int
264-
rust_dom::start_main_loop() {
265+
rust_dom::start_main_loop(int id) {
266+
scheduler_lock.lock();
267+
265268
// Make sure someone is watching, to pull us out of infinite loops.
266269
rust_timer timer(this);
267270

268-
DLOG(this, dom, "started domain loop");
271+
DLOG(this, dom, "started domain loop %d", id);
269272

270273
while (number_of_live_tasks() > 0) {
271274
A(this, kernel->is_deadlocked() == false, "deadlock");
272275

276+
DLOG(this, dom, "worker %d, number_of_live_tasks = %d",
277+
id, number_of_live_tasks());
278+
273279
drain_incoming_message_queue(true);
274280

275281
rust_task *scheduled_task = schedule_task();
@@ -281,8 +287,11 @@ rust_dom::start_main_loop() {
281287
if (scheduled_task == NULL) {
282288
log_state();
283289
DLOG(this, task,
284-
"all tasks are blocked, scheduler yielding ...");
290+
"all tasks are blocked, scheduler id %d yielding ...",
291+
id);
292+
scheduler_lock.unlock();
285293
sync::sleep(100);
294+
scheduler_lock.lock();
286295
DLOG(this, task,
287296
"scheduler resuming ...");
288297
continue;
@@ -303,15 +312,21 @@ rust_dom::start_main_loop() {
303312

304313
interrupt_flag = 0;
305314

315+
DLOG(this, task,
316+
"Running task %p on worker %d",
317+
scheduled_task, id);
318+
scheduled_task->active = true;
306319
activate(scheduled_task);
320+
scheduled_task->active = false;
307321

308322
DLOG(this, task,
309-
"returned from task %s @0x%" PRIxPTR
310-
" in state '%s', sp=0x%" PRIxPTR,
311-
scheduled_task->name,
312-
(uintptr_t)scheduled_task,
313-
scheduled_task->state->name,
314-
scheduled_task->rust_sp);
323+
"returned from task %s @0x%" PRIxPTR
324+
" in state '%s', sp=0x%, worker id=%d" PRIxPTR,
325+
scheduled_task->name,
326+
(uintptr_t)scheduled_task,
327+
scheduled_task->state->name,
328+
scheduled_task->rust_sp,
329+
id);
315330

316331
/*
317332
// These invariants are no longer valid, as rust_sp is not
@@ -341,10 +356,32 @@ rust_dom::start_main_loop() {
341356
reap_dead_tasks();
342357
}
343358

344-
DLOG(this, dom, "finished main-loop (dom.rval = %d)", rval);
359+
DLOG(this, dom, "finished main-loop %d (dom.rval = %d)", id, rval);
360+
361+
scheduler_lock.unlock();
345362
return rval;
346363
}
347364

365+
int rust_dom::start_main_loops(int num_threads)
366+
{
367+
dom_worker *worker = NULL;
368+
369+
// -1, because this thread will also be a worker.
370+
for(int i = 0; i < num_threads - 1; ++i) {
371+
worker = new dom_worker(i + 1, this);
372+
worker->start();
373+
threads.push(worker);
374+
}
375+
376+
start_main_loop(0);
377+
378+
while(threads.pop(&worker)) {
379+
worker->join();
380+
delete worker;
381+
}
382+
383+
return rval;
384+
}
348385

349386
rust_crate_cache *
350387
rust_dom::get_cache() {
@@ -353,14 +390,26 @@ rust_dom::get_cache() {
353390

354391
rust_task *
355392
rust_dom::create_task(rust_task *spawner, const char *name) {
393+
scheduler_lock.lock();
356394
rust_task *task =
357395
new (this) rust_task (this, &newborn_tasks, spawner, name);
358396
DLOG(this, task, "created task: " PTR ", spawner: %s, name: %s",
359397
task, spawner ? spawner->name : "null", name);
360398
newborn_tasks.append(task);
399+
scheduler_lock.unlock();
361400
return task;
362401
}
363402

403+
rust_dom::dom_worker::dom_worker(int id, rust_dom *owner)
404+
: id(id), owner(owner)
405+
{
406+
}
407+
408+
void rust_dom::dom_worker::run()
409+
{
410+
owner->start_main_loop(id);
411+
}
412+
364413
//
365414
// Local Variables:
366415
// mode: C++

trunk/src/rt/rust_dom.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,25 @@ struct rust_dom : public kernel_owned<rust_dom>, rc_base<rust_dom>
9696
void reap_dead_tasks();
9797
rust_task *schedule_task();
9898

99-
int start_main_loop();
99+
int start_main_loop(int id);
100+
int start_main_loops(int num_threads);
100101

101102
void log_state();
102103

103104
rust_task *create_task(rust_task *spawner, const char *name);
105+
106+
class dom_worker : public rust_thread {
107+
int id;
108+
rust_dom *owner;
109+
110+
public:
111+
dom_worker(int id, rust_dom *owner);
112+
113+
virtual void run();
114+
};
115+
116+
lock_and_signal scheduler_lock;
117+
array_list<dom_worker *> threads;
104118
};
105119

106120
inline rust_log &

trunk/src/rt/rust_task.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ rust_task::rust_task(rust_dom *dom, rust_task_list *state,
7070
list_index(-1),
7171
rendezvous_ptr(0),
7272
alarm(this),
73-
handle(NULL)
73+
handle(NULL),
74+
active(false)
7475
{
7576
LOGPTR(dom, "new task", (uintptr_t)this);
7677
DLOG(dom, task, "sizeof(task) = %d (0x%x)", sizeof *this, sizeof *this);
@@ -123,17 +124,12 @@ struct spawn_args {
123124
uintptr_t, uintptr_t);
124125
};
125126

126-
// TODO: rewrite this in LLVM assembly so we can be sure the calling
127-
// conventions will match.
128127
extern "C" CDECL
129128
void task_start_wrapper(spawn_args *a)
130129
{
131130
rust_task *task = a->task;
132131
int rval = 42;
133132

134-
// This is used by the context switching code. LLVM generates fastcall
135-
// functions, but ucontext needs cdecl functions. This massages the
136-
// calling conventions into the right form.
137133
a->f(&rval, task, a->a3, a->a4);
138134

139135
LOG(task, task, "task exited with value %d", rval);
@@ -174,7 +170,10 @@ rust_task::start(uintptr_t spawnee_fn,
174170
ctx.call((void *)task_start_wrapper, a, sp);
175171

176172
yield_timer.reset(0);
177-
transition(&dom->newborn_tasks, &dom->running_tasks);
173+
{
174+
scoped_lock sync(dom->scheduler_lock);
175+
transition(&dom->newborn_tasks, &dom->running_tasks);
176+
}
178177
}
179178

180179
void
@@ -425,7 +424,10 @@ rust_task::block(rust_cond *on, const char* name) {
425424
A(dom, cond == NULL, "Cannot block an already blocked task.");
426425
A(dom, on != NULL, "Cannot block on a NULL object.");
427426

428-
transition(&dom->running_tasks, &dom->blocked_tasks);
427+
{
428+
scoped_lock sync(dom->scheduler_lock);
429+
transition(&dom->running_tasks, &dom->blocked_tasks);
430+
}
429431
cond = on;
430432
cond_name = name;
431433
}
@@ -437,14 +439,18 @@ rust_task::wakeup(rust_cond *from) {
437439
(uintptr_t) cond, (uintptr_t) from);
438440
A(dom, cond == from, "Cannot wake up blocked task on wrong condition.");
439441

440-
transition(&dom->blocked_tasks, &dom->running_tasks);
442+
{
443+
scoped_lock sync(dom->scheduler_lock);
444+
transition(&dom->blocked_tasks, &dom->running_tasks);
445+
}
441446
I(dom, cond == from);
442447
cond = NULL;
443448
cond_name = "none";
444449
}
445450

446451
void
447452
rust_task::die() {
453+
scoped_lock sync(dom->scheduler_lock);
448454
transition(&dom->running_tasks, &dom->dead_tasks);
449455
}
450456

@@ -482,6 +488,11 @@ rust_task::get_handle() {
482488
return handle;
483489
}
484490

491+
bool rust_task::can_schedule()
492+
{
493+
return yield_timer.has_timed_out() && !active;
494+
}
495+
485496
//
486497
// Local Variables:
487498
// mode: C++

trunk/src/rt/rust_task.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ rust_task : public maybe_proxy<rust_task>,
5050
rust_handle<rust_task> *handle;
5151

5252
context ctx;
53+
54+
// This flag indicates that a worker is either currently running the task
55+
// or is about to run this task.
56+
bool active;
5357

5458
// Only a pointer to 'name' is kept, so it must live as long as this task.
5559
rust_task(rust_dom *dom,
@@ -111,6 +115,8 @@ rust_task : public maybe_proxy<rust_task>,
111115

112116
frame_glue_fns *get_frame_glue_fns(uintptr_t fp);
113117
rust_crate_cache * get_crate_cache();
118+
119+
bool can_schedule();
114120
};
115121

116122
//

trunk/src/rt/sync/lock_and_signal.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,16 @@ void lock_and_signal::lock() {
4141
EnterCriticalSection(&_cs);
4242
#else
4343
CHECKED(pthread_mutex_lock(&_mutex));
44+
_holding_thread = pthread_self();
45+
_locked = true;
4446
#endif
4547
}
4648

4749
void lock_and_signal::unlock() {
4850
#if defined(__WIN32__)
4951
LeaveCriticalSection(&_cs);
5052
#else
53+
_locked = false;
5154
CHECKED(pthread_mutex_unlock(&_mutex));
5255
#endif
5356
}
@@ -100,6 +103,26 @@ void lock_and_signal::signal_all() {
100103
#endif
101104
}
102105

106+
bool lock_and_signal::lock_held_by_current_thread()
107+
{
108+
#if defined(__WIN32__)
109+
// TODO: implement this functionality for win32.
110+
return false;
111+
#else
112+
return _locked && _holding_thread == pthread_self();
113+
#endif
114+
}
115+
116+
scoped_lock::scoped_lock(lock_and_signal &lock)
117+
: lock(lock)
118+
{
119+
lock.lock();
120+
}
121+
122+
scoped_lock::~scoped_lock()
123+
{
124+
lock.unlock();
125+
}
103126

104127
//
105128
// Local Variables:

trunk/src/rt/sync/lock_and_signal.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// -*- c++ -*-
12
#ifndef LOCK_AND_SIGNAL_H
23
#define LOCK_AND_SIGNAL_H
34

@@ -8,6 +9,9 @@ class lock_and_signal {
89
#else
910
pthread_cond_t _cond;
1011
pthread_mutex_t _mutex;
12+
13+
pthread_t _holding_thread;
14+
bool _locked;
1115
#endif
1216
public:
1317
lock_and_signal();
@@ -19,6 +23,16 @@ class lock_and_signal {
1923
void timed_wait(size_t timeout_in_ns);
2024
void signal();
2125
void signal_all();
26+
27+
bool lock_held_by_current_thread();
28+
};
29+
30+
class scoped_lock {
31+
lock_and_signal &lock;
32+
33+
public:
34+
scoped_lock(lock_and_signal &lock);
35+
~scoped_lock();
2236
};
2337

2438
#endif /* LOCK_AND_SIGNAL_H */

trunk/src/rt/test/rust_test_runtime.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ rust_task_test::worker::run() {
5353
kernel->create_domain("test");
5454
rust_dom *domain = handle->referent();
5555
domain->root_task->start((uintptr_t)&task_entry, (uintptr_t)NULL);
56-
domain->start_main_loop();
56+
domain->start_main_loop(0);
5757
kernel->destroy_domain(domain);
5858
}
5959

trunk/src/rt/util/array_list.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// -*- c++ -*-
12
#ifndef ARRAY_LIST_H
23
#define ARRAY_LIST_H
34

0 commit comments

Comments
 (0)