POSIX Asynchronous I/O support: fhandler files
This code is where the AIO implementation is wired into existing Cygwin mechanisms for file and device I/O: the fhandler* functions. It makes use of an existing internal routine prw_open to supply a "shadow fd" that permits asynchronous operations on a file the user app accesses via its own fd. This allows AIO to read or write at arbitrary locations within a file without disturbing the app's file pointer. (This was already the case with normal pread|pwrite; we're just adding "async" to the mix.)
This commit is contained in:
parent
a9ffa71a15
commit
87253cbe38
@ -1097,14 +1097,14 @@ fhandler_base::lseek (off_t offset, int whence)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __reg3
|
ssize_t __reg3
|
||||||
fhandler_base::pread (void *, size_t, off_t)
|
fhandler_base::pread (void *, size_t, off_t, void *)
|
||||||
{
|
{
|
||||||
set_errno (ESPIPE);
|
set_errno (ESPIPE);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __reg3
|
ssize_t __reg3
|
||||||
fhandler_base::pwrite (void *, size_t, off_t)
|
fhandler_base::pwrite (void *, size_t, off_t, void *)
|
||||||
{
|
{
|
||||||
set_errno (ESPIPE);
|
set_errno (ESPIPE);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -380,8 +380,8 @@ public:
|
|||||||
virtual ssize_t __stdcall write (const void *ptr, size_t len);
|
virtual ssize_t __stdcall write (const void *ptr, size_t len);
|
||||||
virtual ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
virtual ssize_t __stdcall readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
||||||
virtual ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
virtual ssize_t __stdcall writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
|
||||||
virtual ssize_t __reg3 pread (void *, size_t, off_t);
|
virtual ssize_t __reg3 pread (void *, size_t, off_t, void *aio = NULL);
|
||||||
virtual ssize_t __reg3 pwrite (void *, size_t, off_t);
|
virtual ssize_t __reg3 pwrite (void *, size_t, off_t, void *aio = NULL);
|
||||||
virtual off_t lseek (off_t offset, int whence);
|
virtual off_t lseek (off_t offset, int whence);
|
||||||
virtual int lock (int, struct flock *);
|
virtual int lock (int, struct flock *);
|
||||||
virtual int mand_lock (int, struct flock *);
|
virtual int mand_lock (int, struct flock *);
|
||||||
@ -1430,9 +1430,10 @@ class fhandler_dev_tape: public fhandler_dev_raw
|
|||||||
class fhandler_disk_file: public fhandler_base
|
class fhandler_disk_file: public fhandler_base
|
||||||
{
|
{
|
||||||
HANDLE prw_handle;
|
HANDLE prw_handle;
|
||||||
|
bool prw_handle_isasync;
|
||||||
int __reg3 readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname);
|
int __reg3 readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname);
|
||||||
|
|
||||||
int prw_open (bool);
|
int prw_open (bool, void *);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
fhandler_disk_file ();
|
fhandler_disk_file ();
|
||||||
@ -1473,8 +1474,8 @@ class fhandler_disk_file: public fhandler_base
|
|||||||
void rewinddir (DIR *);
|
void rewinddir (DIR *);
|
||||||
int closedir (DIR *);
|
int closedir (DIR *);
|
||||||
|
|
||||||
ssize_t __reg3 pread (void *, size_t, off_t);
|
ssize_t __reg3 pread (void *, size_t, off_t, void *aio = NULL);
|
||||||
ssize_t __reg3 pwrite (void *, size_t, off_t);
|
ssize_t __reg3 pwrite (void *, size_t, off_t, void *aio = NULL);
|
||||||
|
|
||||||
fhandler_disk_file (void *) {}
|
fhandler_disk_file (void *) {}
|
||||||
dev_t get_dev () { return pc.fs_serial_number (); }
|
dev_t get_dev () { return pc.fs_serial_number (); }
|
||||||
|
@ -24,6 +24,7 @@ details. */
|
|||||||
#include "tls_pbuf.h"
|
#include "tls_pbuf.h"
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
#include "ldap.h"
|
#include "ldap.h"
|
||||||
|
#include <aio.h>
|
||||||
|
|
||||||
#define _COMPILING_NEWLIB
|
#define _COMPILING_NEWLIB
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@ -1511,39 +1512,48 @@ fhandler_base::open_fs (int flags, mode_t mode)
|
|||||||
parameter to the latter. */
|
parameter to the latter. */
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_disk_file::prw_open (bool write)
|
fhandler_disk_file::prw_open (bool write, void *aio)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
ULONG options = get_options ();
|
||||||
|
|
||||||
|
/* If async i/o is intended, turn off the default synchronous operation */
|
||||||
|
if (aio)
|
||||||
|
options &= ~FILE_SYNCHRONOUS_IO_NONALERT;
|
||||||
|
|
||||||
/* First try to open with the original access mask */
|
/* First try to open with the original access mask */
|
||||||
ACCESS_MASK access = get_access ();
|
ACCESS_MASK access = get_access ();
|
||||||
status = NtOpenFile (&prw_handle, access,
|
status = NtOpenFile (&prw_handle, access,
|
||||||
pc.init_reopen_attr (attr, get_handle ()), &io,
|
pc.init_reopen_attr (attr, get_handle ()), &io,
|
||||||
FILE_SHARE_VALID_FLAGS, get_options ());
|
FILE_SHARE_VALID_FLAGS, options);
|
||||||
if (status == STATUS_ACCESS_DENIED)
|
if (status == STATUS_ACCESS_DENIED)
|
||||||
{
|
{
|
||||||
/* If we get an access denied, chmod has been called. Try again
|
/* If we get an access denied, chmod has been called. Try again
|
||||||
with just the required rights to perform the called function. */
|
with just the required rights to perform the called function. */
|
||||||
access &= write ? ~GENERIC_READ : ~GENERIC_WRITE;
|
access &= write ? ~GENERIC_READ : ~GENERIC_WRITE;
|
||||||
status = NtOpenFile (&prw_handle, access, &attr, &io,
|
status = NtOpenFile (&prw_handle, access, &attr, &io,
|
||||||
FILE_SHARE_VALID_FLAGS, get_options ());
|
FILE_SHARE_VALID_FLAGS, options);
|
||||||
}
|
}
|
||||||
debug_printf ("%y = NtOpenFile (%p, %y, %S, io, %y, %y)",
|
debug_printf ("%y = NtOpenFile (%p, %y, %S, io, %y, %y)",
|
||||||
status, prw_handle, access, pc.get_nt_native_path (),
|
status, prw_handle, access, pc.get_nt_native_path (),
|
||||||
FILE_SHARE_VALID_FLAGS, get_options ());
|
FILE_SHARE_VALID_FLAGS, options);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* record prw_handle's asyncness for subsequent pread/pwrite operations */
|
||||||
|
prw_handle_isasync = !!aio;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __reg3
|
ssize_t __reg3
|
||||||
fhandler_disk_file::pread (void *buf, size_t count, off_t offset)
|
fhandler_disk_file::pread (void *buf, size_t count, off_t offset, void *aio)
|
||||||
{
|
{
|
||||||
|
struct aiocb *aiocb = (struct aiocb *) aio;
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
|
|
||||||
if ((get_flags () & O_ACCMODE) == O_WRONLY)
|
if ((get_flags () & O_ACCMODE) == O_WRONLY)
|
||||||
@ -1560,10 +1570,16 @@ fhandler_disk_file::pread (void *buf, size_t count, off_t offset)
|
|||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
LARGE_INTEGER off = { QuadPart:offset };
|
LARGE_INTEGER off = { QuadPart:offset };
|
||||||
|
HANDLE evt = aio ? (HANDLE) aiocb->aio_wincb.event : NULL;
|
||||||
|
PIO_STATUS_BLOCK pio = aio ? (PIO_STATUS_BLOCK) &aiocb->aio_wincb : &io;
|
||||||
|
|
||||||
if (!prw_handle && prw_open (false))
|
/* If existing prw_handle asyncness doesn't match this call's, re-open */
|
||||||
|
if (prw_handle && (prw_handle_isasync != !!aio))
|
||||||
|
NtClose (prw_handle), prw_handle = NULL;
|
||||||
|
|
||||||
|
if (!prw_handle && prw_open (false, aio))
|
||||||
goto non_atomic;
|
goto non_atomic;
|
||||||
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
|
status = NtReadFile (prw_handle, evt, NULL, NULL, pio, buf, count,
|
||||||
&off, NULL);
|
&off, NULL);
|
||||||
if (status == STATUS_END_OF_FILE)
|
if (status == STATUS_END_OF_FILE)
|
||||||
res = 0;
|
res = 0;
|
||||||
@ -1584,11 +1600,12 @@ fhandler_disk_file::pread (void *buf, size_t count, off_t offset)
|
|||||||
switch (mmap_is_attached_or_noreserve (buf, count))
|
switch (mmap_is_attached_or_noreserve (buf, count))
|
||||||
{
|
{
|
||||||
case MMAP_NORESERVE_COMMITED:
|
case MMAP_NORESERVE_COMMITED:
|
||||||
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io,
|
status = NtReadFile (prw_handle, evt, NULL, NULL, pio,
|
||||||
buf, count, &off, NULL);
|
buf, count, &off, NULL);
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
res = io.Information;
|
res = aio ? (ssize_t) aiocb->aio_wincb.info
|
||||||
|
: io.Information;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1602,7 +1619,10 @@ fhandler_disk_file::pread (void *buf, size_t count, off_t offset)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
res = io.Information;
|
{
|
||||||
|
res = aio ? (ssize_t) aiocb->aio_wincb.info : io.Information;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1620,15 +1640,26 @@ non_atomic:
|
|||||||
else
|
else
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If this was a disallowed async request, simulate its conclusion */
|
||||||
|
if (aio)
|
||||||
|
{
|
||||||
|
aiocb->aio_rbytes = res;
|
||||||
|
aiocb->aio_errno = res == -1 ? get_errno () : 0;
|
||||||
|
SetEvent ((HANDLE) aiocb->aio_wincb.event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
debug_printf ("%d = pread(%p, %ld, %D)\n", res, buf, count, offset);
|
debug_printf ("%d = pread(%p, %ld, %D, %p)\n", res, buf, count, offset, aio);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t __reg3
|
ssize_t __reg3
|
||||||
fhandler_disk_file::pwrite (void *buf, size_t count, off_t offset)
|
fhandler_disk_file::pwrite (void *buf, size_t count, off_t offset, void *aio)
|
||||||
{
|
{
|
||||||
|
struct aiocb *aiocb = (struct aiocb *) aio;
|
||||||
|
ssize_t res;
|
||||||
|
|
||||||
if ((get_flags () & O_ACCMODE) == O_RDONLY)
|
if ((get_flags () & O_ACCMODE) == O_RDONLY)
|
||||||
{
|
{
|
||||||
set_errno (EBADF);
|
set_errno (EBADF);
|
||||||
@ -1642,22 +1673,29 @@ fhandler_disk_file::pwrite (void *buf, size_t count, off_t offset)
|
|||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
LARGE_INTEGER off = { QuadPart:offset };
|
LARGE_INTEGER off = { QuadPart:offset };
|
||||||
|
HANDLE evt = aio ? (HANDLE) aiocb->aio_wincb.event : NULL;
|
||||||
|
PIO_STATUS_BLOCK pio = aio ? (PIO_STATUS_BLOCK) &aiocb->aio_wincb : &io;
|
||||||
|
|
||||||
if (!prw_handle && prw_open (true))
|
/* If existing prw_handle asyncness doesn't match this call's, re-open */
|
||||||
|
if (prw_handle && (prw_handle_isasync != !!aio))
|
||||||
|
NtClose (prw_handle), prw_handle = NULL;
|
||||||
|
|
||||||
|
if (!prw_handle && prw_open (true, aio))
|
||||||
goto non_atomic;
|
goto non_atomic;
|
||||||
status = NtWriteFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
|
status = NtWriteFile (prw_handle, evt, NULL, NULL, pio, buf, count,
|
||||||
&off, NULL);
|
&off, NULL);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return io.Information;
|
res = aio ? (ssize_t) aiocb->aio_wincb.info : io.Information;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
non_atomic:
|
non_atomic:
|
||||||
/* Text mode stays slow and non-atomic. */
|
/* Text mode stays slow and non-atomic. */
|
||||||
int res;
|
|
||||||
off_t curpos = lseek (0, SEEK_CUR);
|
off_t curpos = lseek (0, SEEK_CUR);
|
||||||
if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
|
if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
|
||||||
res = curpos;
|
res = curpos;
|
||||||
@ -1667,7 +1705,17 @@ non_atomic:
|
|||||||
if (lseek (curpos, SEEK_SET) < 0)
|
if (lseek (curpos, SEEK_SET) < 0)
|
||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
debug_printf ("%d = pwrite(%p, %ld, %D)\n", res, buf, count, offset);
|
|
||||||
|
/* If this was a disallowed async request, simulate its conclusion */
|
||||||
|
if (aio)
|
||||||
|
{
|
||||||
|
aiocb->aio_rbytes = res;
|
||||||
|
aiocb->aio_errno = res == -1 ? get_errno () : 0;
|
||||||
|
SetEvent ((HANDLE) aiocb->aio_wincb.event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
debug_printf ("%d = pwrite(%p, %ld, %D, %p)\n", res, buf, count, offset, aio);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user