Skip to content

Instantly share code, notes, and snippets.

@archshift
Created December 7, 2014 03:06
Show Gist options
  • Save archshift/0c441fd6e790edf66645 to your computer and use it in GitHub Desktop.
Save archshift/0c441fd6e790edf66645 to your computer and use it in GitHub Desktop.
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 647f0de..2e6c73b 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -178,7 +178,7 @@ public:
case FileCommand::Close:
{
DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
- Kernel::g_object_pool.Destroy<File>(GetHandle());
+ Kernel::g_object_pool.Destroy(GetHandle());
break;
}
@@ -233,7 +233,7 @@ public:
case DirectoryCommand::Close:
{
DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
- Kernel::g_object_pool.Destroy<Directory>(GetHandle());
+ Kernel::g_object_pool.Destroy(GetHandle());
break;
}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 80a34c2..e327d44 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -31,6 +31,7 @@ Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) {
if (!occupied[i]) {
occupied[i] = true;
pool[i] = obj;
+ pool[i]->ref_count++;
pool[i]->handle = i + HANDLE_OFFSET;
return i + HANDLE_OFFSET;
}
@@ -52,8 +53,12 @@ bool ObjectPool::IsValid(Handle handle) const {
void ObjectPool::Clear() {
for (int i = 0; i < MAX_COUNT; i++) {
//brutally clear everything, no validation
- if (occupied[i])
- delete pool[i];
+ if (occupied[i]) {
+ if (pool[i]->ref_count == 1)
+ delete pool[i];
+ else
+ pool[i]->ref_count--;
+ }
occupied[i] = false;
}
pool.fill(nullptr);
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 00a2228..7a03090 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -66,6 +66,8 @@ public:
* @return True if the current thread should wait as a result of the wait
*/
virtual ResultVal<bool> WaitSynchronization() = 0;
+
+ int ref_count;
};
class ObjectPool : NonCopyable {
@@ -78,15 +80,29 @@ public:
static Object* CreateByIDType(int type);
- template <class T>
+ bool IsValid(Handle handle) const;
+
void Destroy(Handle handle) {
- if (Get<T>(handle)) {
- occupied[handle - HANDLE_OFFSET] = false;
- delete pool[handle - HANDLE_OFFSET];
+ if (IsValid(handle)) {
+ Handle real_handle = handle - HANDLE_OFFSET;
+ occupied[real_handle] = false;
+ if (pool[real_handle]->ref_count == 1) {
+ delete pool[real_handle];
+ pool[real_handle] = nullptr;
+ } else {
+ pool[real_handle]->ref_count--;
+ }
}
}
- bool IsValid(Handle handle) const;
+ Object* Get(Handle handle) {
+ if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
+ if (handle != 0)
+ WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
+ return nullptr;
+ }
+ return pool[handle - HANDLE_OFFSET];
+ }
template <class T>
T* Get(Handle handle) {
@@ -113,6 +129,10 @@ public:
return static_cast<T*>(pool[realHandle]);
}
+ Handle DuplicateHandle(Handle handle) {
+ return Create(Get(handle));
+ }
+
template <class T, typename ArgT>
void Iterate(bool func(T*, ArgT), ArgT arg) {
int type = T::GetStaticIDType();
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 20e7fb4..a91c0dd 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -69,9 +69,8 @@ public:
}
/// Frees a handle from the service
- template <class T>
void DeleteHandle(const Handle handle) {
- Kernel::g_object_pool.Destroy<T>(handle);
+ Kernel::g_object_pool.Destroy(handle);
m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
}
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 0e7fa9e..5ca2f39 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -42,7 +42,7 @@ static void GetServiceHandle(Service::Interface* self) {
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
if (nullptr != service) {
- cmd_buff[3] = service->GetHandle();
+ cmd_buff[3] = Kernel::g_object_pool.DuplicateHandle(service->GetHandle());
DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} else {
ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a5805ed..afcc73f 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -107,8 +107,9 @@ static Result SendSyncRequest(Handle handle) {
/// Close a handle
static Result CloseHandle(Handle handle) {
- // ImplementMe
- ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
+ Kernel::g_object_pool.Destroy(handle);
+
+ ERROR_LOG(SVC, "called handle=0x%08X", handle);
return 0;
}
@@ -310,11 +311,10 @@ static Result DuplicateHandle(Handle* out, Handle handle) {
if (handle == Kernel::CurrentThread) {
handle = Kernel::GetCurrentThreadHandle();
}
- _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess),
- "(UNIMPLEMENTED) process handle duplication!");
- // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
- *out = handle;
+ *out = Kernel::g_object_pool.DuplicateHandle(handle);
+
+ DEBUG_LOG(SVC, "called handle=0x%08X", handle);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment