Shuffling kernel util types to util/.
This commit is contained in:
72
src/xenia/kernel/util/native_list.cc
Normal file
72
src/xenia/kernel/util/native_list.cc
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/util/native_list.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace util {
|
||||
|
||||
NativeList::NativeList(Memory* memory)
|
||||
: memory_(memory), head_(kInvalidPointer) {}
|
||||
|
||||
void NativeList::Insert(uint32_t ptr) {
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 0), head_);
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 4), 0);
|
||||
if (head_) {
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(head_ + 4), ptr);
|
||||
}
|
||||
head_ = ptr;
|
||||
}
|
||||
|
||||
bool NativeList::IsQueued(uint32_t ptr) {
|
||||
uint32_t flink =
|
||||
xe::load_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 0));
|
||||
uint32_t blink =
|
||||
xe::load_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 4));
|
||||
return head_ == ptr || flink || blink;
|
||||
}
|
||||
|
||||
void NativeList::Remove(uint32_t ptr) {
|
||||
uint32_t flink =
|
||||
xe::load_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 0));
|
||||
uint32_t blink =
|
||||
xe::load_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 4));
|
||||
if (ptr == head_) {
|
||||
head_ = flink;
|
||||
if (flink) {
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(flink + 4), 0);
|
||||
}
|
||||
} else {
|
||||
if (blink) {
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(blink + 0), flink);
|
||||
}
|
||||
if (flink) {
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(flink + 4), blink);
|
||||
}
|
||||
}
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 0), 0);
|
||||
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(ptr + 4), 0);
|
||||
}
|
||||
|
||||
uint32_t NativeList::Shift() {
|
||||
if (!head_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t ptr = head_;
|
||||
Remove(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool NativeList::HasPending() { return head_ != kInvalidPointer; }
|
||||
|
||||
} // namespace util
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
52
src/xenia/kernel/util/native_list.h
Normal file
52
src/xenia/kernel/util/native_list.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_UTIL_NATIVE_LIST_H_
|
||||
#define XENIA_KERNEL_UTIL_NATIVE_LIST_H_
|
||||
|
||||
#include "xenia/memory.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace util {
|
||||
|
||||
// List is designed for storing pointers to objects in the guest heap.
|
||||
// All values in the list should be assumed to be in big endian.
|
||||
|
||||
// Pass LIST_ENTRY pointers.
|
||||
// struct MYOBJ {
|
||||
// uint32_t stuff;
|
||||
// LIST_ENTRY list_entry; <-- pass this
|
||||
// ...
|
||||
// }
|
||||
|
||||
class NativeList {
|
||||
public:
|
||||
explicit NativeList(Memory* memory);
|
||||
|
||||
void Insert(uint32_t list_entry_ptr);
|
||||
bool IsQueued(uint32_t list_entry_ptr);
|
||||
void Remove(uint32_t list_entry_ptr);
|
||||
uint32_t Shift();
|
||||
bool HasPending();
|
||||
|
||||
private:
|
||||
const uint32_t kInvalidPointer = 0xE0FE0FFF;
|
||||
|
||||
private:
|
||||
Memory* memory_;
|
||||
uint32_t head_;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_UTIL_NATIVE_LIST_H_
|
||||
320
src/xenia/kernel/util/object_table.cc
Normal file
320
src/xenia/kernel/util/object_table.cc
Normal file
@@ -0,0 +1,320 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/kernel/util/object_table.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/kernel/xobject.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace util {
|
||||
|
||||
ObjectTable::ObjectTable() {}
|
||||
|
||||
ObjectTable::~ObjectTable() { Reset(); }
|
||||
|
||||
void ObjectTable::Reset() {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Release all objects.
|
||||
for (uint32_t n = 0; n < table_capacity_; n++) {
|
||||
ObjectTableEntry& entry = table_[n];
|
||||
if (entry.object) {
|
||||
entry.object->Release();
|
||||
}
|
||||
}
|
||||
|
||||
table_capacity_ = 0;
|
||||
last_free_entry_ = 0;
|
||||
free(table_);
|
||||
table_ = nullptr;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::FindFreeSlot(uint32_t* out_slot) {
|
||||
// Find a free slot.
|
||||
uint32_t slot = last_free_entry_;
|
||||
uint32_t scan_count = 0;
|
||||
while (scan_count < table_capacity_) {
|
||||
ObjectTableEntry& entry = table_[slot];
|
||||
if (!entry.object) {
|
||||
*out_slot = slot;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
scan_count++;
|
||||
slot = (slot + 1) % table_capacity_;
|
||||
if (slot == 0) {
|
||||
// Never allow 0 handles.
|
||||
scan_count++;
|
||||
slot++;
|
||||
}
|
||||
}
|
||||
|
||||
// Table out of slots, expand.
|
||||
uint32_t new_table_capacity = std::max(16 * 1024u, table_capacity_ * 2);
|
||||
size_t new_table_size = new_table_capacity * sizeof(ObjectTableEntry);
|
||||
size_t old_table_size = table_capacity_ * sizeof(ObjectTableEntry);
|
||||
auto new_table =
|
||||
reinterpret_cast<ObjectTableEntry*>(realloc(table_, new_table_size));
|
||||
if (!new_table) {
|
||||
return X_STATUS_NO_MEMORY;
|
||||
}
|
||||
// Zero out new memory.
|
||||
if (new_table_size > old_table_size) {
|
||||
std::memset(reinterpret_cast<uint8_t*>(new_table) + old_table_size, 0,
|
||||
new_table_size - old_table_size);
|
||||
}
|
||||
last_free_entry_ = table_capacity_;
|
||||
table_capacity_ = new_table_capacity;
|
||||
table_ = new_table;
|
||||
|
||||
// Never allow 0 handles.
|
||||
slot = ++last_free_entry_;
|
||||
*out_slot = slot;
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::AddHandle(XObject* object, X_HANDLE* out_handle) {
|
||||
assert_not_null(out_handle);
|
||||
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
|
||||
uint32_t slot = 0;
|
||||
{
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Find a free slot.
|
||||
result = FindFreeSlot(&slot);
|
||||
|
||||
// Stash.
|
||||
if (XSUCCEEDED(result)) {
|
||||
ObjectTableEntry& entry = table_[slot];
|
||||
entry.object = object;
|
||||
entry.handle_ref_count = 1;
|
||||
|
||||
// Retain so long as the object is in the table.
|
||||
object->Retain();
|
||||
}
|
||||
}
|
||||
|
||||
if (XSUCCEEDED(result)) {
|
||||
*out_handle = slot << 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::DuplicateHandle(X_HANDLE handle, X_HANDLE* out_handle) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
handle = TranslateHandle(handle);
|
||||
|
||||
XObject* object = LookupObject(handle, false);
|
||||
if (object) {
|
||||
result = AddHandle(object, out_handle);
|
||||
object->Release(); // Release the ref that LookupObject took
|
||||
} else {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::RetainHandle(X_HANDLE handle) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
ObjectTableEntry* entry = LookupTable(handle);
|
||||
if (!entry) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
entry->handle_ref_count++;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::ReleaseHandle(X_HANDLE handle) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
ObjectTableEntry* entry = LookupTable(handle);
|
||||
if (!entry) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (--entry->handle_ref_count == 0) {
|
||||
// No more references. Remove it from the table.
|
||||
return RemoveHandle(handle);
|
||||
}
|
||||
|
||||
// FIXME: Return a status code telling the caller it wasn't released
|
||||
// (but not a failure code)
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::RemoveHandle(X_HANDLE handle) {
|
||||
X_STATUS result = X_STATUS_SUCCESS;
|
||||
|
||||
handle = TranslateHandle(handle);
|
||||
if (!handle) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
ObjectTableEntry* entry = LookupTable(handle);
|
||||
if (!entry) {
|
||||
return X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (entry->object) {
|
||||
auto object = entry->object;
|
||||
entry->object = nullptr;
|
||||
entry->handle_ref_count = 0;
|
||||
|
||||
// Release now that the object has been removed from the table.
|
||||
object->Release();
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ObjectTable::ObjectTableEntry* ObjectTable::LookupTable(X_HANDLE handle) {
|
||||
handle = TranslateHandle(handle);
|
||||
if (!handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
|
||||
// Lower 2 bits are ignored.
|
||||
uint32_t slot = handle >> 2;
|
||||
if (slot <= table_capacity_) {
|
||||
return &table_[slot];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XObject* ObjectTable::LookupObject(X_HANDLE handle, bool already_locked) {
|
||||
handle = TranslateHandle(handle);
|
||||
if (!handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XObject* object = nullptr;
|
||||
if (!already_locked) {
|
||||
global_critical_region_.mutex().lock();
|
||||
}
|
||||
|
||||
// Lower 2 bits are ignored.
|
||||
uint32_t slot = handle >> 2;
|
||||
|
||||
// Verify slot.
|
||||
if (slot < table_capacity_) {
|
||||
ObjectTableEntry& entry = table_[slot];
|
||||
if (entry.object) {
|
||||
object = entry.object;
|
||||
}
|
||||
}
|
||||
|
||||
// Retain the object pointer.
|
||||
if (object) {
|
||||
object->Retain();
|
||||
}
|
||||
|
||||
if (!already_locked) {
|
||||
global_critical_region_.mutex().unlock();
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
void ObjectTable::GetObjectsByType(XObject::Type type,
|
||||
std::vector<object_ref<XObject>>* results) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
for (uint32_t slot = 0; slot < table_capacity_; ++slot) {
|
||||
auto& entry = table_[slot];
|
||||
if (entry.object) {
|
||||
if (entry.object->type() == type) {
|
||||
entry.object->Retain();
|
||||
results->push_back(object_ref<XObject>(entry.object));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X_HANDLE ObjectTable::TranslateHandle(X_HANDLE handle) {
|
||||
if (handle == 0xFFFFFFFF) {
|
||||
// CurrentProcess
|
||||
// assert_always();
|
||||
return 0;
|
||||
} else if (handle == 0xFFFFFFFE) {
|
||||
// CurrentThread
|
||||
return XThread::GetCurrentThreadHandle();
|
||||
} else {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::AddNameMapping(const std::string& name, X_HANDLE handle) {
|
||||
// Names are case-insensitive.
|
||||
std::string lower_name = name;
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
if (name_table_.count(lower_name)) {
|
||||
return X_STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
name_table_.insert({lower_name, handle});
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void ObjectTable::RemoveNameMapping(const std::string& name) {
|
||||
// Names are case-insensitive.
|
||||
std::string lower_name = name;
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = name_table_.find(lower_name);
|
||||
if (it != name_table_.end()) {
|
||||
name_table_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
X_STATUS ObjectTable::GetObjectByName(const std::string& name,
|
||||
X_HANDLE* out_handle) {
|
||||
// Names are case-insensitive.
|
||||
std::string lower_name = name;
|
||||
std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
|
||||
tolower);
|
||||
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = name_table_.find(lower_name);
|
||||
if (it == name_table_.end()) {
|
||||
*out_handle = X_INVALID_HANDLE_VALUE;
|
||||
return X_STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
*out_handle = it->second;
|
||||
|
||||
// We need to ref the handle. I think.
|
||||
auto obj = LookupObject(it->second, true);
|
||||
if (obj) {
|
||||
obj->RetainHandle();
|
||||
obj->Release();
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
81
src/xenia/kernel/util/object_table.h
Normal file
81
src/xenia/kernel/util/object_table.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_UTIL_OBJECT_TABLE_H_
|
||||
#define XENIA_KERNEL_UTIL_OBJECT_TABLE_H_
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/kernel/xobject.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace util {
|
||||
|
||||
class ObjectTable {
|
||||
public:
|
||||
ObjectTable();
|
||||
~ObjectTable();
|
||||
|
||||
void Reset();
|
||||
|
||||
X_STATUS AddHandle(XObject* object, X_HANDLE* out_handle);
|
||||
X_STATUS DuplicateHandle(X_HANDLE orig, X_HANDLE* out_handle);
|
||||
X_STATUS RetainHandle(X_HANDLE handle);
|
||||
X_STATUS ReleaseHandle(X_HANDLE handle);
|
||||
X_STATUS RemoveHandle(X_HANDLE handle);
|
||||
|
||||
template <typename T>
|
||||
object_ref<T> LookupObject(X_HANDLE handle) {
|
||||
auto object = LookupObject(handle, false);
|
||||
auto result = object_ref<T>(reinterpret_cast<T*>(object));
|
||||
return result;
|
||||
}
|
||||
|
||||
X_STATUS AddNameMapping(const std::string& name, X_HANDLE handle);
|
||||
void RemoveNameMapping(const std::string& name);
|
||||
X_STATUS GetObjectByName(const std::string& name, X_HANDLE* out_handle);
|
||||
template <typename T>
|
||||
std::vector<object_ref<T>> GetObjectsByType(XObject::Type type) {
|
||||
std::vector<object_ref<T>> results;
|
||||
GetObjectsByType(
|
||||
type, reinterpret_cast<std::vector<object_ref<XObject>>*>(&results));
|
||||
return results;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef struct {
|
||||
int handle_ref_count = 0;
|
||||
XObject* object = nullptr;
|
||||
} ObjectTableEntry;
|
||||
|
||||
ObjectTableEntry* LookupTable(X_HANDLE handle);
|
||||
XObject* LookupObject(X_HANDLE handle, bool already_locked);
|
||||
void GetObjectsByType(XObject::Type type,
|
||||
std::vector<object_ref<XObject>>* results);
|
||||
|
||||
X_HANDLE TranslateHandle(X_HANDLE handle);
|
||||
X_STATUS FindFreeSlot(uint32_t* out_slot);
|
||||
|
||||
xe::global_critical_region global_critical_region_;
|
||||
uint32_t table_capacity_ = 0;
|
||||
ObjectTableEntry* table_ = nullptr;
|
||||
uint32_t last_free_entry_ = 0;
|
||||
std::unordered_map<std::string, X_HANDLE> name_table_;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_KERNEL_UTIL_OBJECT_TABLE_H_
|
||||
Reference in New Issue
Block a user