From d0e3d2eb32f32869bb54b5724e19780c83fb592b Mon Sep 17 00:00:00 2001 From: Lunaixsky Date: Sun, 4 May 2025 19:39:46 +0100 Subject: [PATCH] dedicated kthread interface and enablement of lrud auto-recycler * fix potential racing issue on async eviction --- lunaix-os/includes/lunaix/blkbuf.h | 3 + lunaix-os/includes/lunaix/kthread.h | 13 +++++ lunaix-os/includes/lunaix/process.h | 11 ---- lunaix-os/includes/lunaix/sched.h | 7 +++ lunaix-os/kernel/block/blkbuf.c | 68 +++++++++++++++------- lunaix-os/kernel/lrud.c | 88 ++++++++++++++++++++++------- lunaix-os/kernel/lunad.c | 28 ++++----- lunaix-os/kernel/process/sched.c | 32 +---------- lunaix-os/kernel/process/thread.c | 61 ++++++++++++++++++++ 9 files changed, 219 insertions(+), 92 deletions(-) create mode 100644 lunaix-os/includes/lunaix/kthread.h diff --git a/lunaix-os/includes/lunaix/blkbuf.h b/lunaix-os/includes/lunaix/blkbuf.h index decf92f..0a23e87 100644 --- a/lunaix-os/includes/lunaix/blkbuf.h +++ b/lunaix-os/includes/lunaix/blkbuf.h @@ -24,6 +24,9 @@ struct blk_buf { bcobj_t cobj; struct llist_header dirty; struct blkio_req* breq; + + unsigned int dirty_count; + mutex_t lock; }; typedef void* bbuf_t; diff --git a/lunaix-os/includes/lunaix/kthread.h b/lunaix-os/includes/lunaix/kthread.h new file mode 100644 index 0000000..25fa4a4 --- /dev/null +++ b/lunaix-os/includes/lunaix/kthread.h @@ -0,0 +1,13 @@ +#ifndef __LUNAIX_KTHREAD_H +#define __LUNAIX_KTHREAD_H + +#include +#include + +void +kthread_spawn(ptr_t entry); + +void +kthread_sleep(int seconds); + +#endif /* __LUNAIX_KTHREAD_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 868a9fc..d35c234 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -372,17 +372,6 @@ create_thread(struct proc_info* proc, bool with_ustack); void start_thread(struct thread* th, ptr_t entry); -static inline void -spawn_kthread(ptr_t entry) { - assert(kernel_process(__current)); - - struct thread* th = create_thread(__current, false); - - assert(th); - start_thread(th, entry); - detach_thread(th); -} - void exit_thread(void* val); diff --git a/lunaix-os/includes/lunaix/sched.h b/lunaix-os/includes/lunaix/sched.h index 4264307..94afa72 100644 --- a/lunaix-os/includes/lunaix/sched.h +++ b/lunaix-os/includes/lunaix/sched.h @@ -34,4 +34,11 @@ run(struct thread* thread); void cleanup_detached_threads(); +static inline struct scheduler* +scheduler() +{ + extern struct scheduler sched_ctx; + return &sched_ctx; +} + #endif /* __LUNAIX_SCHEDULER_H */ diff --git a/lunaix-os/kernel/block/blkbuf.c b/lunaix-os/kernel/block/blkbuf.c index bb29150..f72aea7 100644 --- a/lunaix-os/kernel/block/blkbuf.c +++ b/lunaix-os/kernel/block/blkbuf.c @@ -5,7 +5,9 @@ #include #include -LOG_MODULE("blkbuf") +LOG_MODULE("blkbuf") + +#define MAX_DIRTY_COUNT 16 #define bb_cache_obj(bcache) \ container_of(bcache, struct blkbuf_cache, cached) @@ -22,6 +24,18 @@ __tolba(struct blkbuf_cache* cache, unsigned int blk_id) cache->blkdev->blk_size); } +static inline void +__blkbuf_lock(struct blk_buf* buf) +{ + mutex_lock(&buf->lock); +} + +static inline void +__blkbuf_unlock(struct blk_buf* buf) +{ + mutex_unlock(&buf->lock); +} + static void __blkbuf_do_sync(struct bcache* bc, unsigned long tag, void* data) { @@ -105,6 +119,7 @@ __blkbuf_take_slow_lockness(struct blkbuf_cache* bc, unsigned int block_id) // give dirty a know state llist_init_head(&buf->dirty); + mutex_init(&buf->lock); blkio_setread(req); blkio_bindctx(req, bc->blkdev->blkio); @@ -169,6 +184,21 @@ blkbuf_put(bbuf_t buf) bcache_return(bbuf->cobj); } + +static void +__schedule_sync_nolock(struct blk_buf* bbuf, bool wait) +{ + struct blkio_req* blkio; + + blkio = bbuf->breq; + + blkio_setwrite(blkio); + blkio_commit(blkio, wait ? BLKIO_WAIT : BLKIO_NOWAIT); + + llist_delete(&bbuf->dirty); + bbuf->dirty_count = 0; +} + void blkbuf_dirty(bbuf_t buf) { @@ -180,26 +210,21 @@ blkbuf_dirty(bbuf_t buf) bbuf = ((struct blk_buf*)buf); bc = bcache_holder_embed(bbuf->cobj, struct blkbuf_cache, cached); - mutex_lock(&bc->lock); + __blkbuf_lock(bbuf); - if (llist_empty(&bbuf->dirty)) { + if (llist_empty(&bbuf->dirty)) + { + mutex_lock(&bc->lock); llist_append(&bc->dirty, &bbuf->dirty); + mutex_unlock(&bc->lock); } - mutex_unlock(&bc->lock); -} - -static inline void -__schedule_sync_event(struct blk_buf* bbuf, bool wait) -{ - struct blkio_req* blkio; - - blkio = bbuf->breq; - - blkio_setwrite(blkio); - blkio_commit(blkio, wait ? BLKIO_WAIT : BLKIO_NOWAIT); + bbuf->dirty_count++; + if (bbuf->dirty_count >= MAX_DIRTY_COUNT) { + __schedule_sync_nolock(bbuf, false); + } - llist_delete(&bbuf->dirty); + __blkbuf_unlock(bbuf); } void @@ -208,7 +233,9 @@ blkbuf_schedule_sync(bbuf_t buf) struct blk_buf* bbuf; bbuf = to_blkbuf(buf); - __schedule_sync_event(bbuf, false); + __blkbuf_lock(bbuf); + __schedule_sync_nolock(bbuf, false); + __blkbuf_unlock(bbuf); } bool @@ -218,8 +245,11 @@ blkbuf_syncall(struct blkbuf_cache* bc, bool async) mutex_lock(&bc->lock); - llist_for_each(pos, n, &bc->dirty, dirty) { - __schedule_sync_event(pos, !async); + llist_for_each(pos, n, &bc->dirty, dirty) + { + __blkbuf_lock(pos); + __schedule_sync_nolock(pos, !async); + __blkbuf_unlock(pos); } mutex_unlock(&bc->lock); diff --git a/lunaix-os/kernel/lrud.c b/lunaix-os/kernel/lrud.c index 0395e42..137cfa6 100644 --- a/lunaix-os/kernel/lrud.c +++ b/lunaix-os/kernel/lrud.c @@ -3,16 +3,18 @@ #include #include #include +#include +#include #include static struct llist_header zone_lead = { .next = &zone_lead, .prev = &zone_lead }; DEFINE_SPINLOCK_OPS(struct lru_zone*, lock); - +static DEFINE_SPINLOCK(zone_list_lock); static void -__do_evict_lockless(struct lru_zone* zone, struct llist_header* elem) +__do_evict_nolock(struct lru_zone* zone, struct llist_header* elem) { llist_delete(elem); if (!zone->try_evict(container_of(elem, struct lru_node, lru_nodes))) { @@ -28,12 +30,16 @@ __do_evict_lockless(struct lru_zone* zone, struct llist_header* elem) } static void -__lru_evict_all_lockness(struct lru_zone* zone) +__lru_evict_all_nolock(struct lru_zone* zone) { - struct llist_header* tail = zone->lead_node.prev; - while (tail != &zone->lead_node) { - __do_evict_lockless(zone, tail); + struct llist_header* tail, *curr; + + tail = zone->lead_node.prev; + while (tail != &zone->lead_node) + { + curr = tail; tail = tail->prev; + __do_evict_nolock(zone, curr); } } @@ -49,9 +55,12 @@ lru_new_zone(const char* name, evict_cb try_evict_cb) strncpy(zone->name, name, sizeof(zone->name) - 1); llist_init_head(&zone->lead_node); - llist_append(&zone_lead, &zone->zones); spinlock_init(&zone->lock); + spinlock_acquire(&zone_list_lock); + llist_append(&zone_lead, &zone->zones); + spinlock_release(&zone_list_lock); + return zone; } @@ -60,10 +69,12 @@ lru_free_zone(struct lru_zone* zone) { lock(zone); - __lru_evict_all_lockness(zone); + __lru_evict_all_nolock(zone); - if (llist_empty(&zone->lead_node)) { + if (llist_empty(&zone->lead_node)) + { llist_delete(&zone->zones); + unlock(zone); vfree(zone); return; } @@ -107,24 +118,31 @@ lru_evict_one(struct lru_zone* zone) struct llist_header* tail = zone->lead_node.prev; if (tail == &zone->lead_node) { - return; + goto done; } - __do_evict_lockless(zone, tail); + __do_evict_nolock(zone, tail); +done: unlock(zone); } void lru_evict_half(struct lru_zone* zone) { + int target; + struct llist_header *tail, *curr; + lock(zone); - int target = (int)(zone->objects / 2); - struct llist_header* tail = zone->lead_node.prev; + target = (int)(zone->objects / 2); + tail = zone->lead_node.prev; + while (tail != &zone->lead_node && target > 0) { - __do_evict_lockless(zone, tail); + curr = tail; tail = tail->prev; + + __do_evict_nolock(zone, curr); target--; } @@ -138,7 +156,7 @@ lru_evict_all(struct lru_zone* zone) { lock(zone); - __lru_evict_all_lockness(zone); + __lru_evict_all_nolock(zone); zone->evict_stats.n_full++; @@ -148,16 +166,48 @@ lru_evict_all(struct lru_zone* zone) void lru_remove(struct lru_zone* zone, struct lru_node* node) { - lock(zone); + if (llist_empty(&node->lru_nodes)) + return; - if (node->lru_nodes.next && node->lru_nodes.prev) { - llist_delete(&node->lru_nodes); - } + lock(zone); + + llist_delete(&node->lru_nodes); zone->objects--; unlock(zone); } + +static void +__lru_pool_daemon() +{ + struct lru_zone *pos, *n; + + while (true) + { + spinlock_acquire(&zone_list_lock); + + // TODO add a watermark check before doing eviction + llist_for_each(pos, n, &zone_lead, zones) { + lru_evict_half(pos); + } + + spinlock_release(&zone_list_lock); + + kthread_sleep(10); + } +} + +static void +__lru_pool_init() +{ + // TODO make sure other are thread-safe first + + // kthread_spawn((ptr_t)__lru_pool_daemon); +} +owloysius_fetch_init(__lru_pool_init, on_postboot) + + static void __twimap_read_lru_pool(struct twimap* map) { diff --git a/lunaix-os/kernel/lunad.c b/lunaix-os/kernel/lunad.c index b808022..25ce7d2 100644 --- a/lunaix-os/kernel/lunad.c +++ b/lunaix-os/kernel/lunad.c @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -84,6 +85,17 @@ lunad_do_usr() { } } +static void +__thread_cleaner() +{ + while (true) + { + cleanup_detached_threads(); + kthread_sleep(30); + } +} + + /** * @brief LunaixOS的内核进程,该进程永远为可执行。 * @@ -95,23 +107,11 @@ lunad_do_usr() { void lunad_main() { - spawn_kthread((ptr_t)init_platform); - - /* - NOTE Kernel preemption after this point. + kthread_spawn((ptr_t)init_platform); + kthread_spawn((ptr_t)__thread_cleaner); - More specifically, it is not a real kernel preemption (as in preemption - happened at any point of kernel, except those marked explicitly). - In Lunaix, things are designed in an non-preemptive fashion, we implement - kernel preemption the other way around: only selected kernel functions which, - of course, with great care of preemptive assumption, will goes into kernel - thread (which is preemptive!) - */ - - set_preemption(); while (1) { - cleanup_detached_threads(); yield_current(); } } diff --git a/lunaix-os/kernel/process/sched.c b/lunaix-os/kernel/process/sched.c index 112741c..ccf0e45 100644 --- a/lunaix-os/kernel/process/sched.c +++ b/lunaix-os/kernel/process/sched.c @@ -224,33 +224,6 @@ done: fail("unexpected return from scheduler"); } -__DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) -{ - if (!seconds) { - return 0; - } - - time_t systime = clock_systime() / 1000; - struct haybed* bed = ¤t_thread->sleep; - - if (bed->wakeup_time) { - return (bed->wakeup_time - systime); - } - - bed->wakeup_time = systime + seconds; - - if (llist_empty(&bed->sleepers)) { - llist_append(&sched_ctx.sleepers, &bed->sleepers); - } - - store_retval(seconds); - - block_current_thread(); - schedule(); - - return 0; -} - __DEFINE_LXSYSCALL1(unsigned int, alarm, unsigned int, seconds) { struct haybed* bed = ¤t_thread->sleep; @@ -396,7 +369,7 @@ alloc_process() proc->root = vfs_sysroot; proc->sigreg = vzalloc(sizeof(struct sigregistry)); - proc->fdtable = vzalloc(sizeof(struct v_fdtable)); + proc->fdtable = fdtable_create(); proc->mm = procvm_create(proc); @@ -632,4 +605,5 @@ orphaned_proc(pid_t pid) // 如果其父进程的状态是terminated 或 destroy中的一种 // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程 return proc_terminated(parent) || parent->created > proc->created; -} \ No newline at end of file +} + diff --git a/lunaix-os/kernel/process/thread.c b/lunaix-os/kernel/process/thread.c index 78cce8b..f4bbac0 100644 --- a/lunaix-os/kernel/process/thread.c +++ b/lunaix-os/kernel/process/thread.c @@ -83,6 +83,35 @@ found:; return align_stack(ptep_va(ptep, LFT_SIZE) - 1); } +static int +__thread_putsleep(int seconds) +{ + if (!seconds) { + return 0; + } + + struct scheduler* sched; + time_t systime; + struct haybed* bed; + + sched = scheduler(); + systime = clock_systime() / 1000; + bed = ¤t_thread->sleep; + + if (bed->wakeup_time) { + return (bed->wakeup_time - systime); + } + + bed->wakeup_time = systime + seconds; + + if (llist_empty(&bed->sleepers)) { + llist_append(&sched->sleepers, &bed->sleepers); + } + + block_current_thread(); + return seconds; +} + void thread_release_mem(struct thread* thread) { @@ -237,6 +266,25 @@ thread_stats_update(bool inbound, bool voluntary) stats->last_entry = now; } +void +kthread_spawn(ptr_t entry) +{ + assert(kernel_process(__current)); + + struct thread* th = create_thread(__current, false); + + assert(th); + start_thread(th, entry); + detach_thread(th); +} + +void +kthread_sleep(int seconds) +{ + if (__thread_putsleep(seconds)) + yield_current(); +} + __DEFINE_LXSYSCALL3(int, th_create, tid_t*, tid, struct uthread_param*, thparam, void*, entry) { @@ -332,3 +380,16 @@ __DEFINE_LXSYSCALL2(int, th_kill, tid_t, tid, int, signum) return 0; } + +__DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) +{ + int sec; + + sec = __thread_putsleep(seconds); + store_retval(seconds); + + if (sec) + schedule(); + + return 0; +} \ No newline at end of file -- 2.27.0