summaryrefslogtreecommitdiffstats
path: root/rsnix/src/sched.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsnix/src/sched.rs46
1 files changed, 45 insertions, 1 deletions
diff --git a/rsnix/src/sched.rs b/rsnix/src/sched.rs
index 0c4938e..107dba6 100644
--- a/rsnix/src/sched.rs
+++ b/rsnix/src/sched.rs
@@ -396,6 +396,31 @@ pub fn spawn(entry: fn(), name: &str) -> Option<usize> {
396 if ok { Some(id) } else { None } 396 if ok { Some(id) } else { None }
397} 397}
398 398
399/// Reserve an empty task slot without installing a frame. The slot is
400/// marked Ready-with-no-frame is NOT valid to schedule — callers must
401/// follow with `launch_at` before yielding (exec does both back-to-back
402/// under the preemption lock window of the caller).
403pub fn reserve_slot() -> Option<usize> {
404 lock();
405 let id = unsafe {
406 let mut slot = None;
407 for i in 2..MAX_TASKS {
408 if TASKS[i].state == TaskState::Done && TASKS[i].stack != 0 {
409 reap(i);
410 slot = Some(i);
411 break;
412 }
413 if TASKS[i].state == TaskState::Done && TASKS[i].stack == 0 && TASKS[i].name_len == 0 {
414 slot = Some(i);
415 break;
416 }
417 }
418 slot
419 };
420 unlock();
421 id
422}
423
399unsafe fn reap(id: usize) { 424unsafe fn reap(id: usize) {
400 unsafe { 425 unsafe {
401 let t = &mut TASKS[id]; 426 let t = &mut TASKS[id];
@@ -408,6 +433,19 @@ unsafe fn reap(id: usize) {
408 } 433 }
409} 434}
410 435
436/// Install the initial frame for a reserved slot and mark it Ready.
437/// The slot must have come from `reserve_slot` and must not have been
438/// scheduled in between (exec stores its context between the two calls).
439pub fn launch_at(id: usize, entry: fn(), name: &str) -> bool {
440 if id >= MAX_TASKS {
441 return false;
442 }
443 lock();
444 let ok = spawn_at(id, entry, name);
445 unlock();
446 ok
447}
448
411fn spawn_at(id: usize, entry: fn(), name: &str) -> bool { 449fn spawn_at(id: usize, entry: fn(), name: &str) -> bool {
412 let Some(base) = memory::alloc_pages(STACK_PAGES) else { 450 let Some(base) = memory::alloc_pages(STACK_PAGES) else {
413 return false; 451 return false;
@@ -483,7 +521,7 @@ unsafe extern "C" fn trampoline(entry: usize) -> ! {
483 task_exit() 521 task_exit()
484} 522}
485 523
486fn task_exit() -> ! { 524pub fn task_exit() -> ! {
487 lock(); 525 lock();
488 unsafe { 526 unsafe {
489 TASKS[CURRENT].state = TaskState::Done; 527 TASKS[CURRENT].state = TaskState::Done;
@@ -648,6 +686,12 @@ pub fn abort_current(msg: &str) -> ! {
648 TASKS[id].stack, 686 TASKS[id].stack,
649 TASKS[id].guard 687 TASKS[id].guard
650 ); 688 );
689 // An exec'd binary died: unblock the waiting spawner with a
690 // completion message (exit code -1 encoded as u64::MAX). The
691 // shell's queue is the only waiter; best-effort by design.
692 if id >= 2 {
693 let _ = push_msg(SHELL_TID, TaskMsg::User(u64::MAX));
694 }
651 PREEMPT_DEPTH.store(0, Ordering::Relaxed); 695 PREEMPT_DEPTH.store(0, Ordering::Relaxed);
652 } 696 }
653 yield_int(); 697 yield_int();