mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-29 13:46:01 +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;
|
size_t GetTotalNonSystemUserPhysicalMemorySize() const;
|
||||||
|
|
||||||
Result CreateThreadLocalRegion(KProcessAddress *out);
|
Result CreateThreadLocalRegion(KProcessAddress *out);
|
||||||
|
Result DeleteThreadLocalRegion(KProcessAddress addr);
|
||||||
void *GetThreadLocalRegionPointer(KProcessAddress addr);
|
void *GetThreadLocalRegionPointer(KProcessAddress addr);
|
||||||
|
|
||||||
constexpr KProcessAddress GetProcessLocalRegionAddress() const { return this->plr_address; }
|
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) {
|
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) {
|
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();
|
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) {
|
void *KProcess::GetThreadLocalRegionPointer(KProcessAddress addr) {
|
||||||
KThreadLocalPage *tlp = nullptr;
|
KThreadLocalPage *tlp = nullptr;
|
||||||
{
|
{
|
||||||
|
|
|
@ -251,7 +251,49 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KThread::Finalize() {
|
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 {
|
bool KThread::IsSignaled() const {
|
||||||
|
|
Loading…
Reference in a new issue