kern: implement KThread::Finalize

This commit is contained in:
Michael Scire 2020-07-21 04:58:54 -07:00 committed by SciresM
parent 3265927ed7
commit 3cf793f87e
4 changed files with 117 additions and 2 deletions

View file

@ -216,6 +216,7 @@ namespace ams::kern {
size_t GetTotalNonSystemUserPhysicalMemorySize() const;
Result CreateThreadLocalRegion(KProcessAddress *out);
Result DeleteThreadLocalRegion(KProcessAddress addr);
void *GetThreadLocalRegionPointer(KProcessAddress addr);
constexpr KProcessAddress GetProcessLocalRegionAddress() const { return this->plr_address; }

View file

@ -1358,7 +1358,31 @@ namespace ams::kern {
}
Result KPageTableBase::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) {
MESOSPHERE_UNIMPLEMENTED();
/* Check that the unmap is in range. */
const size_t size = num_pages * PageSize;
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
/* Lock the table. */
KScopedLightLock lk(this->general_lock);
/* Check the memory state. */
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, state, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
/* Create an update allocator. */
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
R_TRY(allocator.GetResult());
/* We're going to perform an update, so create a helper. */
KScopedPageTableUpdater updater(this);
/* Perform the unmap. */
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, false };
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
/* Update the blocks. */
this->memory_block_manager.Update(&allocator, address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None);
return ResultSuccess();
}
Result KPageTableBase::MapPageGroup(KProcessAddress *out_addr, const KPageGroup &pg, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {

View file

@ -212,6 +212,54 @@ namespace ams::kern {
return ResultSuccess();
}
Result KProcess::DeleteThreadLocalRegion(KProcessAddress addr) {
KThreadLocalPage *page_to_free = nullptr;
/* Release the region. */
{
KScopedSchedulerLock sl;
/* Try to find the page in the partially used list. */
auto it = this->partially_used_tlp_tree.find(KThreadLocalPage(util::AlignDown(GetInteger(addr), PageSize)));
if (it == this->partially_used_tlp_tree.end()) {
/* If we don't find it, it has to be in the fully used list. */
it = this->fully_used_tlp_tree.find(KThreadLocalPage(util::AlignDown(GetInteger(addr), PageSize)));
R_UNLESS(it != this->fully_used_tlp_tree.end(), svc::ResultInvalidAddress());
/* Release the region. */
it->Release(addr);
/* Move the page out of the fully used list. */
KThreadLocalPage *tlp = std::addressof(*it);
this->fully_used_tlp_tree.erase(it);
if (tlp->IsAllFree()) {
page_to_free = tlp;
} else {
this->partially_used_tlp_tree.insert(*tlp);
}
} else {
/* Release the region. */
it->Release(addr);
/* Handle the all-free case. */
KThreadLocalPage *tlp = std::addressof(*it);
if (tlp->IsAllFree()) {
this->partially_used_tlp_tree.erase(it);
page_to_free = tlp;
}
}
}
/* If we should free the page it was in, do so. */
if (page_to_free != nullptr) {
page_to_free->Finalize();
KThreadLocalPage::Free(page_to_free);
}
return ResultSuccess();
}
void *KProcess::GetThreadLocalRegionPointer(KProcessAddress addr) {
KThreadLocalPage *tlp = nullptr;
{

View file

@ -251,7 +251,49 @@ namespace ams::kern {
}
void KThread::Finalize() {
MESOSPHERE_UNIMPLEMENTED();
MESOSPHERE_ASSERT_THIS();
/* If the thread has an owner process, unregister it. */
if (this->parent != nullptr) {
this->parent->UnregisterThread(this);
}
/* If the thread has a local region, delete it. */
if (this->tls_address != Null<KProcessAddress>) {
MESOSPHERE_R_ABORT_UNLESS(this->parent->DeleteThreadLocalRegion(this->tls_address));
}
/* Release any waiters. */
{
MESOSPHERE_ASSERT(this->lock_owner == nullptr);
KScopedSchedulerLock sl;
auto it = this->waiter_list.begin();
while (it != this->waiter_list.end()) {
/* The thread shouldn't be a kernel waiter. */
MESOSPHERE_ASSERT(!IsKernelAddressKey(it->GetAddressKey()));
it->SetLockOwner(nullptr);
it->SetSyncedObject(nullptr, svc::ResultInvalidState());
it->Wakeup();
it = this->waiter_list.erase(it);
}
}
/* Finalize the thread context. */
this->thread_context.Finalize();
/* Cleanup the kernel stack. */
if (this->kernel_stack_top != nullptr) {
CleanupKernelStack(reinterpret_cast<uintptr_t>(this->kernel_stack_top));
}
/* Decrement the parent process's thread count. */
if (this->parent != nullptr) {
this->parent->DecrementThreadCount();
}
/* Perform inherited finalization. */
KAutoObjectWithSlabHeapAndContainer<KThread, KSynchronizationObject>::Finalize();
}
bool KThread::IsSignaled() const {