struct process* sleep_prev;
int in_sleep_queue;
+ struct process* alarm_next; // sorted alarm queue (by alarm_tick)
+ struct process* alarm_prev;
+ int in_alarm_queue;
+
/* Thread support */
uint32_t tgid; /* Thread group ID (== pid for group leader) */
uint32_t flags; /* PROCESS_FLAG_* */
// Wake up sleeping processes (called by timer)
void process_wake_check(uint32_t current_tick);
+// Set or cancel an alarm for a process (returns old alarm_tick)
+uint32_t process_alarm_set(struct process* p, uint32_t tick);
+
// The magic function that switches stacks (Implemented in Assembly)
// old_esp_ptr: Address where we save the OLD process's ESP
// new_esp: The NEW process's ESP to load
p->in_sleep_queue = 0;
}
+/* ---------- Sorted alarm queue (by alarm_tick) ---------- */
+static struct process* alarm_head = NULL;
+
+static void alarm_queue_insert(struct process* p) {
+ p->in_alarm_queue = 1;
+ if (!alarm_head || p->alarm_tick <= alarm_head->alarm_tick) {
+ p->alarm_prev = NULL;
+ p->alarm_next = alarm_head;
+ if (alarm_head) alarm_head->alarm_prev = p;
+ alarm_head = p;
+ return;
+ }
+ struct process* cur = alarm_head;
+ while (cur->alarm_next && cur->alarm_next->alarm_tick < p->alarm_tick)
+ cur = cur->alarm_next;
+ p->alarm_next = cur->alarm_next;
+ p->alarm_prev = cur;
+ if (cur->alarm_next) cur->alarm_next->alarm_prev = p;
+ cur->alarm_next = p;
+}
+
+static void alarm_queue_remove(struct process* p) {
+ if (!p->in_alarm_queue) return;
+ if (p->alarm_prev) p->alarm_prev->alarm_next = p->alarm_next;
+ else alarm_head = p->alarm_next;
+ if (p->alarm_next) p->alarm_next->alarm_prev = p->alarm_prev;
+ p->alarm_prev = NULL;
+ p->alarm_next = NULL;
+ p->in_alarm_queue = 0;
+}
+
static struct process* rq_pick_next(void) {
if (rq_active->bitmap) {
uint32_t prio = bsf32(rq_active->bitmap);
rq_remove_if_queued(p);
}
sleep_queue_remove(p);
+ alarm_queue_remove(p);
process_close_all_files_locked(p);
p->exit_status = 128 + sig;
p->state = PROCESS_ZOMBIE;
current_process->exit_status = status;
current_process->state = PROCESS_ZOMBIE;
+ alarm_queue_remove(current_process);
if (current_process->pid != 0) {
struct process* parent = process_find_locked(current_process->parent_pid);
}
}
- /* O(N) alarm scan — alarms are rare so this is acceptable */
- struct process* start = iter;
- do {
- if (iter->alarm_tick != 0 && current_tick >= iter->alarm_tick) {
- iter->alarm_tick = 0;
- iter->sig_pending_mask |= (1U << 14); /* SIGALRM */
- }
- iter = iter->next;
- } while (iter != start);
+ /* O(1) alarm queue: pop expired entries from the sorted head */
+ while (alarm_head && current_tick >= alarm_head->alarm_tick) {
+ struct process* p = alarm_head;
+ alarm_queue_remove(p);
+ p->alarm_tick = 0;
+ p->sig_pending_mask |= (1U << 14); /* SIGALRM */
+ }
+
+ spin_unlock_irqrestore(&sched_lock, flags);
+}
+
+uint32_t process_alarm_set(struct process* p, uint32_t tick) {
+ uintptr_t flags = spin_lock_irqsave(&sched_lock);
+ uint32_t old = p->alarm_tick;
+
+ /* Remove from alarm queue if currently queued */
+ alarm_queue_remove(p);
+
+ if (tick != 0) {
+ p->alarm_tick = tick;
+ alarm_queue_insert(p);
+ } else {
+ p->alarm_tick = 0;
+ }
spin_unlock_irqrestore(&sched_lock, flags);
+ return old;
}
if (!current_process) { sc_ret(regs) = 0; return; }
uint32_t seconds = sc_arg0(regs);
uint32_t now = get_tick_count();
+ uint32_t new_tick = (seconds == 0) ? 0 : now + seconds * 50;
+ uint32_t old_tick = process_alarm_set(current_process, new_tick);
uint32_t old_remaining = 0;
- if (current_process->alarm_tick > now) {
- old_remaining = (current_process->alarm_tick - now) / 50 + 1;
- }
- if (seconds == 0) {
- current_process->alarm_tick = 0;
- } else {
- current_process->alarm_tick = now + seconds * 50;
+ if (old_tick > now) {
+ old_remaining = (old_tick - now) / 50 + 1;
}
sc_ret(regs) = old_remaining;
return;