mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: implement KThread::Finalize
This commit is contained in:
parent
3265927ed7
commit
3cf793f87e
4 changed files with 117 additions and 2 deletions
|
@ -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; }
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue