Merge pull request #503 from DrChat/async_io_fix

Async IO Fix
This commit is contained in:
Ben Vanik 2015-12-30 15:48:19 -08:00
commit 3800e300d4
3 changed files with 57 additions and 11 deletions

View File

@ -83,6 +83,18 @@ class X_FILE_FS_ATTRIBUTE_INFORMATION {
}; };
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16); static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
struct CreateOptions {
// http://processhacker.sourceforge.net/doc/ntioapi_8h.html
static const uint32_t FILE_DIRECTORY_FILE = 0x00000001;
// Optimization - files access will be sequential, not random.
static const uint32_t FILE_SEQUENTIAL_ONLY = 0x00000004;
static const uint32_t FILE_SYNCHRONOUS_IO_ALERT = 0x00000010;
static const uint32_t FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020;
static const uint32_t FILE_NON_DIRECTORY_FILE = 0x00000040;
// Optimization - file access will be random, not sequential.
static const uint32_t FILE_RANDOM_ACCESS = 0x00000800;
};
dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access, dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
pointer_t<X_OBJECT_ATTRIBUTES> object_attrs, pointer_t<X_OBJECT_ATTRIBUTES> object_attrs,
pointer_t<X_IO_STATUS_BLOCK> io_status_block, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
@ -130,7 +142,11 @@ dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access,
X_HANDLE handle = X_INVALID_HANDLE_VALUE; X_HANDLE handle = X_INVALID_HANDLE_VALUE;
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
file = object_ref<XFile>(new XFile(kernel_state(), vfs_file)); // If true, desired_access SYNCHRONIZE flag must be set.
bool synchronous =
(create_options & CreateOptions::FILE_SYNCHRONOUS_IO_ALERT) ||
(create_options & CreateOptions::FILE_SYNCHRONOUS_IO_NONALERT);
file = object_ref<XFile>(new XFile(kernel_state(), vfs_file, synchronous));
// Handle ref is incremented, so return that. // Handle ref is incremented, so return that.
handle = file->handle(); handle = file->handle();
@ -177,7 +193,7 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
} }
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
if (true) { if (true || file->is_synchronous()) {
// Synchronous. // Synchronous.
size_t bytes_read = 0; size_t bytes_read = 0;
result = file->Read(buffer, buffer_length, result = file->Read(buffer, buffer_length,
@ -190,6 +206,7 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
// Queue the APC callback. It must be delivered via the APC mechanism even // Queue the APC callback. It must be delivered via the APC mechanism even
// though were are completing immediately. // though were are completing immediately.
// Low bit probably means do not queue to IO ports.
if ((uint32_t)apc_routine_ptr & ~1) { if ((uint32_t)apc_routine_ptr & ~1) {
if (apc_context) { if (apc_context) {
auto thread = XThread::GetCurrentThread(); auto thread = XThread::GetCurrentThread();
@ -198,6 +215,10 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
} }
} }
if (!file->is_synchronous()) {
result = X_STATUS_PENDING;
}
// Mark that we should signal the event now. We do this after // Mark that we should signal the event now. We do this after
// we have written the info out. // we have written the info out.
signal_event = true; signal_event = true;
@ -262,7 +283,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
// Execute write. // Execute write.
if (XSUCCEEDED(result)) { if (XSUCCEEDED(result)) {
// TODO(benvanik): async path. // TODO(benvanik): async path.
if (true) { if (true || file->is_synchronous()) {
// Synchronous request. // Synchronous request.
size_t bytes_written = 0; size_t bytes_written = 0;
result = file->Write(buffer, buffer_length, result = file->Write(buffer, buffer_length,
@ -272,6 +293,15 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
info = (int32_t)bytes_written; info = (int32_t)bytes_written;
} }
if (!file->is_synchronous()) {
result = X_STATUS_PENDING;
}
if (io_status_block) {
io_status_block->status = X_STATUS_SUCCESS;
io_status_block->information = info;
}
// Mark that we should signal the event now. We do this after // Mark that we should signal the event now. We do this after
// we have written the info out. // we have written the info out.
signal_event = true; signal_event = true;
@ -279,12 +309,17 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
// X_STATUS_PENDING if not returning immediately. // X_STATUS_PENDING if not returning immediately.
result = X_STATUS_PENDING; result = X_STATUS_PENDING;
info = 0; info = 0;
if (io_status_block) {
io_status_block->status = X_STATUS_SUCCESS;
io_status_block->information = info;
}
} }
} }
if (io_status_block) { if (XFAILED(result) && io_status_block) {
io_status_block->status = result; io_status_block->status = result;
io_status_block->information = info; io_status_block->information = 0;
} }
if (ev && signal_event) { if (ev && signal_event) {
@ -306,7 +341,7 @@ dword_result_t NtCreateIoCompletion(lpdword_t out_handle,
return X_STATUS_SUCCESS; return X_STATUS_SUCCESS;
} }
DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub); DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kImplemented);
// Dequeues a packet from the completion port. // Dequeues a packet from the completion port.
dword_result_t NtRemoveIoCompletion( dword_result_t NtRemoveIoCompletion(
@ -341,7 +376,7 @@ dword_result_t NtRemoveIoCompletion(
return status; return status;
} }
DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kStub); DECLARE_XBOXKRNL_EXPORT(NtRemoveIoCompletion, ExportTag::kImplemented);
dword_result_t NtSetInformationFile( dword_result_t NtSetInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block, dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
@ -389,7 +424,8 @@ dword_result_t NtSetInformationFile(
auto port = auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle); kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) { if (!port) {
return X_STATUS_INVALID_HANDLE; result = X_STATUS_INVALID_HANDLE;
break;
} }
file->RegisterIOCompletionPort(key, port); file->RegisterIOCompletionPort(key, port);
@ -496,6 +532,7 @@ dword_result_t NtQueryInformationFile(
file->set_position(cur_pos); file->set_position(cur_pos);
info = 4; info = 4;
*/ */
xe::store_and_swap<uint32_t>(file_info_ptr, 0);
result = X_STATUS_UNSUCCESSFUL; result = X_STATUS_UNSUCCESSFUL;
info = 0; info = 0;
} break; } break;

View File

@ -18,8 +18,10 @@
namespace xe { namespace xe {
namespace kernel { namespace kernel {
XFile::XFile(KernelState* kernel_state, vfs::File* file) XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
: XObject(kernel_state, kTypeFile), file_(file) { : XObject(kernel_state, kTypeFile),
file_(file),
is_synchronous_(synchronous) {
async_event_ = threading::Event::CreateAutoResetEvent(false); async_event_ = threading::Event::CreateAutoResetEvent(false);
} }
@ -174,6 +176,7 @@ bool XFile::Save(ByteStream* stream) {
stream->Write(file_->entry()->absolute_path()); stream->Write(file_->entry()->absolute_path());
stream->Write<uint64_t>(position_); stream->Write<uint64_t>(position_);
stream->Write(file_access()); stream->Write(file_access());
stream->Write<bool>(is_synchronous_);
return true; return true;
} }
@ -190,6 +193,7 @@ object_ref<XFile> XFile::Restore(KernelState* kernel_state,
auto abs_path = stream->Read<std::string>(); auto abs_path = stream->Read<std::string>();
uint64_t position = stream->Read<uint64_t>(); uint64_t position = stream->Read<uint64_t>();
auto access = stream->Read<uint32_t>(); auto access = stream->Read<uint32_t>();
auto is_synchronous = stream->Read<bool>();
XELOGD("XFile %.8X (%s)", file->handle(), abs_path.c_str()); XELOGD("XFile %.8X (%s)", file->handle(), abs_path.c_str());
@ -204,6 +208,7 @@ object_ref<XFile> XFile::Restore(KernelState* kernel_state,
file->file_ = vfs_file; file->file_ = vfs_file;
file->position_ = position; file->position_ = position;
file->is_synchronous_ = is_synchronous;
return object_ref<XFile>(file); return object_ref<XFile>(file);
} }

View File

@ -81,7 +81,7 @@ class XFile : public XObject {
public: public:
static const Type kType = kTypeFile; static const Type kType = kTypeFile;
XFile(KernelState* kernel_state, vfs::File* file); XFile(KernelState* kernel_state, vfs::File* file, bool synchronous);
~XFile() override; ~XFile() override;
vfs::Device* device() const { return file_->entry()->device(); } vfs::Device* device() const { return file_->entry()->device(); }
@ -111,6 +111,8 @@ class XFile : public XObject {
static object_ref<XFile> Restore(KernelState* kernel_state, static object_ref<XFile> Restore(KernelState* kernel_state,
ByteStream* stream); ByteStream* stream);
bool is_synchronous() const { return is_synchronous_; }
protected: protected:
void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification); void NotifyIOCompletionPorts(XIOCompletion::IONotification& notification);
@ -133,6 +135,8 @@ class XFile : public XObject {
xe::filesystem::WildcardEngine find_engine_; xe::filesystem::WildcardEngine find_engine_;
size_t find_index_ = 0; size_t find_index_ = 0;
bool is_synchronous_ = false;
}; };
} // namespace kernel } // namespace kernel