diff --git a/alloc.ccp b/alloc.ccp index f9841b0..13f2050 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -179,7 +179,7 @@ kPage *kMemory::alloc_page (): return ret kThread *kMemory::alloc_thread (unsigned size): - kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kCapsP), (void **)&threads) + kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kThread::caps_store), (void **)&threads) if !ret: return NULL ret->receivers = NULL @@ -191,7 +191,9 @@ kThread *kMemory::alloc_thread (unsigned size): ret->schedule_next = NULL ret->slots = size for unsigned i = 0; i < size; ++i: - ret->caps[i] = NULL + ret->slot[i].prev.thread = NULL + ret->slot[i].next.thread = NULL + ret->slot[i].caps = NULL return ret kMessage *kMemory::alloc_message (kReceiver *target): @@ -224,6 +226,7 @@ kCaps *kMemory::alloc_caps (unsigned size): kCaps *ret = (kCaps *)search_free (sizeof (kCaps) + (size - 1) * sizeof (kCapability), (void **)&capses) if !ret: return NULL + ret->first_slot.thread = NULL ret->size = size for unsigned i = 0; i < size; ++i: ret->set (i, NULL, 0, kCapRef (), NULL) @@ -283,10 +286,25 @@ void kMemory::free_page (kPage *page): pfree (page->frame) free_obj (page, (kPointer *)&pages) +void kThread::unset_slot (unsigned s): + if !slot[s].caps: + return + if slot[s].prev.thread: + slot[s].prev.thread->slot[slot[s].prev.index].next = slot[s].next + else: + slot[s].caps->first_slot = slot[s].next + if slot[s].next.thread: + slot[s].next.thread->slot[slot[s].next.index].prev = slot[s].prev + slot[s].prev.thread = NULL + slot[s].next.thread = NULL + slot[s].caps = NULL + void kMemory::free_thread (kThread *thread): thread->unrun () while thread->receivers: thread->receivers->orphan () + for unsigned i = 0; i < thread->slots; ++i: + thread->unset_slot (i) free_obj (thread, (void **)&threads) void kMemory::free_message (kReceiver *owner, kMessage *message): @@ -352,6 +370,8 @@ void kCapability::invalidate (): void kMemory::free_caps (kCaps *c): for unsigned i = 0; i < c->size; ++i: c->caps[i].invalidate () + while c->first_slot.thread: + c->first_slot.thread->unset_slot (c->first_slot.index) free_obj (c, (void **)&capses) void kMemory::free_memory (kMemory *mem): diff --git a/invoke.ccp b/invoke.ccp index d957ac4..c00616a 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -63,19 +63,19 @@ void kThread::raise (unsigned code, unsigned data): dbg_log_num (data) dbg_log_char ('\n') unrun () - if slots < 1 || !caps[0] || !caps[0]->cap (0)->target: + if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target: return kCapability::Context c c.data[0] = Kernel::Num (code, data) - caps[0]->cap (0)->invoke (&c) + slot[0].caps->cap (0)->invoke (&c) // From user-provided, thus untrusted, data, find a capability. kCapRef kThread::find_capability (unsigned code, bool *copy): *copy = code & CAP_COPY unsigned c = code & ~CAP_COPY - unsigned slot = c >> 16 + unsigned s = c >> 16 unsigned num = c & 0xffff - if slot >= slots || !caps[slot] || num >= caps[slot]->size: + if s >= slots || !slot[s].caps || num >= slot[s].caps->size: if c != CAP_NONE: dpanic (code, "debug") dbg_log_num ((unsigned)old_current) @@ -84,15 +84,15 @@ kCapRef kThread::find_capability (unsigned code, bool *copy): dbg_log_char ('\n') dbg_log_num (num) dbg_log_char (':') - dbg_log_num (slot) + dbg_log_num (s) dbg_log (" > ") - if caps[slot]: - dbg_log_num (caps[slot]->size) + if slot[s].caps: + dbg_log_num (slot[s].caps->size) else: dbg_log ("no caps") dbg_log_char ('\n') return kCapRef () - return kCapRef (caps[slot], num) + return kCapRef (slot[s].caps, num) // Try to deliver a message. bool kReceiver::try_deliver (): @@ -428,16 +428,18 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ if slot >= thread->slots: dpanic (0, "using invalid slot") return - if thread->caps[slot]: - // TODO: invalidate slot. - thread->caps[slot] = new_caps + thread->unset_slot (slot) + thread->slot[slot].caps = new_caps if new_caps: - // TODO: link it into a list. + thread->slot[slot].next = new_caps->first_slot + thread->slot[slot].caps = new_caps + new_caps->first_slot.thread = thread + new_caps->first_slot.index = slot break case Kernel::Thread::GET_CAPS & REQUEST_MASK: unsigned slot = c->data[1].l if slot < thread->slots: - reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->caps[slot], &thread->caps[slot]->refs, thread->slots) + reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots) else: reply_num (thread->slots) return diff --git a/kernel.hhp b/kernel.hhp index 825e0e8..1bf13df 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -94,6 +94,10 @@ struct kCapability : public kObject: inline void invoke (kCapability::Context *c) void invalidate () +struct _slot_data: + kThreadP thread + unsigned index + struct kThread : public kObject: kReceiverP receivers unsigned pc, sp @@ -103,8 +107,11 @@ struct kThread : public kObject: unsigned recv_reply, recv_arg // caps is an array of slots pointers to kCapses. unsigned slots - // TODO: handle freeing of capses which are in use. - kCapsP caps[1] + struct caps_store: + _slot_data prev, next + kCapsP caps + caps_store slot[1] + void unset_slot (unsigned s) void raise (unsigned code, unsigned data) void run () void unrun () @@ -145,6 +152,7 @@ struct kPage : public kObject: void forget () struct kCaps : public kObject: + _slot_data first_slot unsigned size kCapability caps[1] kCapability *cap (unsigned idx): diff --git a/mips/init.ccp b/mips/init.ccp index 9729372..122b337 100644 --- a/mips/init.ccp +++ b/mips/init.ccp @@ -201,22 +201,24 @@ static void init_threads (): if !stackpage || !mem->map (stackpage, 0x7ffff000): panic (0x13151719, "unable to map initial stack page") return - thread->caps[0] = mem->alloc_caps (NUM_CAPS) + thread->slot[0].caps = mem->alloc_caps (NUM_CAPS) + thread->slot[0].caps->first_slot.thread = thread + thread->slot[0].caps->first_slot.index = 0 thread->arch.a[0] = NUM_SLOTS thread->arch.a[1] = NUM_CAPS kReceiver *recv = mem->alloc_receiver () recv->owner = thread thread->receivers = recv - thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) - thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Kernel::Num ((unsigned)thread), kCapRef (), &thread->refs) - thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Kernel::Num ((unsigned)mem), kCapRef (), &mem->refs) - thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) + thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) + thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Kernel::Num ((unsigned)thread), kCapRef (), &thread->refs) + thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Kernel::Num ((unsigned)mem), kCapRef (), &mem->refs) + thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs) thread->flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV if !i: first_scheduled = thread init_receiver = recv else: - thread->caps[0]->set (__parent_num, init_receiver, i, kCapRef (), &init_receiver->capabilities) + thread->slot[0].caps->set (__parent_num, init_receiver, i, kCapRef (), &init_receiver->capabilities) previous->schedule_next = thread thread->schedule_prev = previous thread->schedule_next = NULL