diff --git a/drivers/serial/interrupts.c b/drivers/serial/interrupts.c index fae9540..03d5dcb 100644 --- a/drivers/serial/interrupts.c +++ b/drivers/serial/interrupts.c @@ -42,6 +42,9 @@ #define DR_MASK 1 +struct signal_wait_t* com1_signal; +struct signal_wait_t* com2_signal; + void serial_init_interrupts(void) { uint8_t com1_v = idt_get_vector(); uint8_t com2_v = idt_get_vector(); diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index 9476028..2a567bf 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -55,10 +55,6 @@ #include #include -#ifdef SERIAL -#include -#endif /* SERIAL */ - #define RFL_MASK 0xD5 #define CR4_FSGSBASE (1 << 16) @@ -129,10 +125,6 @@ void kentry(void) { proc_data_get()->sts |= PROC_STS_INT_READY; -#ifdef SERIAL - serial_init_interrupts(); -#endif /* SERIAL */ - logging_log_debug("Early PCIE init"); disk_init(); fs_init(); diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 8005c88..6f7a6ba 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -73,6 +74,8 @@ static struct free_transaction_list_t* transaction_list; uint8_t pending_free_lock; static struct disarm_list_t* disarm_list; +static struct signal_wait_t* free_pending_wait; + static struct mm_tree_node_t* alloc_node(void) { struct mm_tree_node_t* next; lock_acquire(&n_lock); @@ -269,11 +272,13 @@ static uint64_t mm_alloc_max(size_t size, uint64_t align, uint64_t max, struct m return ret + adj; } -extern void mm_init( +void mm_init( void (*first_segment)(uint64_t* handle), void (*next_segment)(uint64_t* handle, struct mem_segment_t* seg)) { kernel_limit = (uint64_t)&_kernel_pend; + free_pending_wait = 0; + lock_init(&p_lock); lock_init(&v_lock); lock_init(&n_lock); @@ -433,6 +438,10 @@ void mm_free_v(uint64_t base, size_t size) { pending->next = pending_free; pending_free = (struct free_transaction_list_t* volatile)pending; lock_release(&pending_free_lock); + + if (free_pending_wait) { + signal_awake(free_pending_wait); + } } static void free_all_pending(void* _ign) { @@ -442,10 +451,14 @@ static void free_all_pending(void* _ign) { struct disarm_list_t* disarm; uint8_t cntrl; + free_pending_wait = signal_wait_alloc(); + while (1) { - do { - time_sleep(SHOOTDOWN_DELAY_MS); - } while (!pending_free); + time_sleep(SHOOTDOWN_DELAY_MS); + + while (!pending_free) { + signal_wait(free_pending_wait); + } lock_acquire(&pending_free_lock); @@ -465,8 +478,6 @@ static void free_all_pending(void* _ign) { lock_release(&pending_free_lock); do { - cpu_pause(); - cntrl = 0; lock_acquire(&pending_free_lock); for (disarm = disarm_list; disarm; disarm = disarm->next) { @@ -476,6 +487,10 @@ static void free_all_pending(void* _ign) { } } lock_release(&pending_free_lock); + + if (cntrl) { + signal_wait(free_pending_wait); + } } while(cntrl); while (transaction_list) { @@ -515,4 +530,6 @@ void mm_barrier_disarm(uint8_t id) { break; } } + + signal_awake(free_pending_wait); } diff --git a/kernel/core/process.c b/kernel/core/process.c index 83f21e7..0717354 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -256,3 +256,10 @@ void process_sleep(uint64_t wake_time) { cpu_hlt(); } } + +void process_set_callback(void (*callback)(struct pcb_t*)) { + struct pcb_t* current = proc_data_get()->current_process; + + current->sleep_state.callback = callback; + current->sched_cntr = SCHED_CALLBACK; +} diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index 7a88438..3aa044e 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -89,7 +90,14 @@ void scheduler_run(void) { lock_release(&lock_sched); break; + case SCHED_CALLBACK: + current_pcb->sleep_state.callback(current_pcb); + break; default: + logging_log_error("Invalid scheduler code %u", current_pcb->sched_cntr); + __attribute__((fallthrough)); + case SCHED_READY: + case SCHED_SIGNAL_READY: scheduler_schedule(current_pcb); break; } diff --git a/kernel/core/signal.c b/kernel/core/signal.c new file mode 100644 index 0000000..e8a91cc --- /dev/null +++ b/kernel/core/signal.c @@ -0,0 +1,77 @@ +/* signal.c - kernel signal implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +struct signal_wait_t { + struct pcb_t* queue; + uint8_t lock; +}; + +static void signal_wait_callback(struct pcb_t* pcb) { + struct signal_wait_t* wait = pcb->meta[0]; + + lock_acquire(&wait->lock); + pcb->next = wait->queue; + wait->queue = pcb; + lock_release(&wait->lock); +} + +struct signal_wait_t* signal_wait_alloc(void) { + struct signal_wait_t* ret = kmalloc(sizeof(struct signal_wait_t)); + + lock_init(&ret->lock); + ret->queue = 0; + + return ret; +} + +void signal_wait(struct signal_wait_t* wait) { + volatile struct pcb_t* current = proc_data_get()->current_process; + + current->meta[0] = wait; + process_set_callback(signal_wait_callback); + + while (current->sched_cntr != SCHED_SIGNAL_READY) { + cpu_wait_loop(); + } + + current->sched_cntr = SCHED_READY; +} + +void signal_awake(struct signal_wait_t* wait) { + struct pcb_t* i, * next; + lock_acquire(&wait->lock); + i = wait->queue; + wait->queue = 0; + lock_release(&wait->lock); + + for (; i; i = next) { + next = i->next; + + i->sched_cntr = SCHED_SIGNAL_READY; + scheduler_schedule(i); + } +} diff --git a/kernel/devfs/tty.c b/kernel/devfs/tty.c index 2c7c60b..8ba73b4 100644 --- a/kernel/devfs/tty.c +++ b/kernel/devfs/tty.c @@ -25,11 +25,16 @@ #include #include #include +#include #include #include #include +#ifdef SERIAL +#include +#endif /* SERIAL */ + #define TTY_RING_MASK 0x3FFF #define MASK(i) ((i) & TTY_RING_MASK) @@ -47,6 +52,7 @@ struct tty_handle_t { uint8_t* read_buffer; volatile uint16_t write_index; volatile uint16_t read_index; + struct signal_wait_t* signal; enum { TTY_MODE_COOKED, TTY_MODE_RAW @@ -67,13 +73,17 @@ void tty_init(void) { com1.read_buffer = (uint8_t*)paging_ident(mm_alloc_p(TTY_READ_BUFFER_SIZE)); com1.write_index = 0; com1.read_index = 0; + com1.signal = signal_wait_alloc(); lock_init(&com1.lock); com2.writer = serial_write_com2; com2.read_buffer = (uint8_t*)paging_ident(mm_alloc_p(TTY_READ_BUFFER_SIZE)); com2.write_index = 0; com2.read_index = 0; + com2.signal = signal_wait_alloc(); lock_init(&com2.lock); + + serial_init_interrupts(); #endif /* SERIAL */ } @@ -108,7 +118,7 @@ size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count) { while (count) { while (EMPTY(tty->read_index, tty->write_index)) { - cpu_pause(); //TODO futex wait + signal_wait(tty->signal); } lock_acquire(&tty->lock); @@ -176,5 +186,7 @@ uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte) { } } + signal_awake(tty->signal); + return 1; } diff --git a/kernel/include/core/process.h b/kernel/include/core/process.h index aa2757a..25e5d74 100644 --- a/kernel/include/core/process.h +++ b/kernel/include/core/process.h @@ -23,8 +23,12 @@ #include #include +#include #define MAX_FD 256 +#define MAX_META 1 + +struct pcb_t; struct pcb_t { // order is important @@ -68,17 +72,21 @@ struct pcb_t { uint8_t fxdata[512] __attribute__((aligned(16))); + union { + uint64_t wake_time; + void (*callback)(struct pcb_t*); + } sleep_state; + + void* meta[MAX_META]; + enum { SCHED_READY, SCHED_KILL, SCHED_SKIP, - SCHED_SLEEP + SCHED_SLEEP, + SCHED_CALLBACK, + SCHED_SIGNAL_READY } sched_cntr; - - union { - uint64_t wake_time; - } sleep_state; - }; struct preempt_frame_t { @@ -131,4 +139,6 @@ extern uint8_t process_create_guarded_stack(uint64_t* init_vaddr, uint64_t* init extern void process_sleep(uint64_t wake_time); +extern void process_set_callback(void (*callback)(struct pcb_t*)); + #endif /* KERNEL_CORE_PROCESS_H */ diff --git a/kernel/include/core/signal.h b/kernel/include/core/signal.h new file mode 100644 index 0000000..70f7138 --- /dev/null +++ b/kernel/include/core/signal.h @@ -0,0 +1,24 @@ +/* signal.h - kernel signal interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +struct signal_wait_t; + +extern struct signal_wait_t* signal_wait_alloc(void); +extern void signal_wait(struct signal_wait_t* wait); +extern void signal_awake(struct signal_wait_t* wait);