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:
Mark Geisert 2018-07-23 22:31:58 -07:00 committed by Corinna Vinschen
parent a9ffa71a15
commit 87253cbe38
4 changed files with 83 additions and 34 deletions

View File

@ -1097,14 +1097,14 @@ fhandler_base::lseek (off_t offset, int whence)
}
ssize_t __reg3
fhandler_base::pread (void *, size_t, off_t)
fhandler_base::pread (void *, size_t, off_t, void *)
{
set_errno (ESPIPE);
return -1;
}
ssize_t __reg3
fhandler_base::pwrite (void *, size_t, off_t)
fhandler_base::pwrite (void *, size_t, off_t, void *)
{
set_errno (ESPIPE);
return -1;

View File

@ -380,8 +380,8 @@ public:
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 writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
virtual ssize_t __reg3 pread (void *, size_t, off_t);
virtual ssize_t __reg3 pwrite (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, void *aio = NULL);
virtual off_t lseek (off_t offset, int whence);
virtual int 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
{
HANDLE prw_handle;
bool prw_handle_isasync;
int __reg3 readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname);
int prw_open (bool);
int prw_open (bool, void *);
public:
fhandler_disk_file ();
@ -1473,8 +1474,8 @@ class fhandler_disk_file: public fhandler_base
void rewinddir (DIR *);
int closedir (DIR *);
ssize_t __reg3 pread (void *, size_t, off_t);
ssize_t __reg3 pwrite (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, void *aio = NULL);
fhandler_disk_file (void *) {}
dev_t get_dev () { return pc.fs_serial_number (); }

View File

@ -24,6 +24,7 @@ details. */
#include "tls_pbuf.h"
#include "devices.h"
#include "ldap.h"
#include <aio.h>
#define _COMPILING_NEWLIB
#include <dirent.h>
@ -1511,39 +1512,48 @@ fhandler_base::open_fs (int flags, mode_t mode)
parameter to the latter. */
int
fhandler_disk_file::prw_open (bool write)
fhandler_disk_file::prw_open (bool write, void *aio)
{
NTSTATUS status;
IO_STATUS_BLOCK io;
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 */
ACCESS_MASK access = get_access ();
status = NtOpenFile (&prw_handle, access,
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 we get an access denied, chmod has been called. Try again
with just the required rights to perform the called function. */
access &= write ? ~GENERIC_READ : ~GENERIC_WRITE;
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)",
status, prw_handle, access, pc.get_nt_native_path (),
FILE_SHARE_VALID_FLAGS, get_options ());
FILE_SHARE_VALID_FLAGS, options);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return -1;
}
/* record prw_handle's asyncness for subsequent pread/pwrite operations */
prw_handle_isasync = !!aio;
return 0;
}
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;
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;
IO_STATUS_BLOCK io;
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;
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
status = NtReadFile (prw_handle, evt, NULL, NULL, pio, buf, count,
&off, NULL);
if (status == STATUS_END_OF_FILE)
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))
{
case MMAP_NORESERVE_COMMITED:
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io,
status = NtReadFile (prw_handle, evt, NULL, NULL, pio,
buf, count, &off, NULL);
if (NT_SUCCESS (status))
{
res = io.Information;
res = aio ? (ssize_t) aiocb->aio_wincb.info
: io.Information;
goto out;
}
break;
@ -1602,7 +1619,10 @@ fhandler_disk_file::pread (void *buf, size_t count, off_t offset)
return -1;
}
else
res = io.Information;
{
res = aio ? (ssize_t) aiocb->aio_wincb.info : io.Information;
goto out;
}
}
else
{
@ -1620,15 +1640,26 @@ non_atomic:
else
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:
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;
}
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)
{
set_errno (EBADF);
@ -1642,32 +1673,49 @@ fhandler_disk_file::pwrite (void *buf, size_t count, off_t offset)
NTSTATUS status;
IO_STATUS_BLOCK io;
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;
status = NtWriteFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
status = NtWriteFile (prw_handle, evt, NULL, NULL, pio, buf, count,
&off, NULL);
if (!NT_SUCCESS (status))
{
__seterrno_from_nt_status (status);
return -1;
}
return io.Information;
res = aio ? (ssize_t) aiocb->aio_wincb.info : io.Information;
goto out;
}
non_atomic:
/* Text mode stays slow and non-atomic. */
int res;
off_t curpos = lseek (0, SEEK_CUR);
if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
res = curpos;
else
{
res = (ssize_t) write (buf, count);
if (lseek (curpos, SEEK_SET) < 0)
res = -1;
non_atomic:
/* Text mode stays slow and non-atomic. */
off_t curpos = lseek (0, SEEK_CUR);
if (curpos < 0 || lseek (offset, SEEK_SET) < 0)
res = curpos;
else
{
res = (ssize_t) write (buf, count);
if (lseek (curpos, SEEK_SET) < 0)
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);
}
}
debug_printf ("%d = pwrite(%p, %ld, %D)\n", res, buf, count, offset);
out:
debug_printf ("%d = pwrite(%p, %ld, %D, %p)\n", res, buf, count, offset, aio);
return res;
}

View File

@ -859,7 +859,7 @@ fhandler_pty_slave::read (void *ptr, size_t& len)
break;
}
out:
termios_printf ("%d=read(%p, %lu)", totalread, ptr, len);
termios_printf ("%d = read(%p, %lu)", totalread, ptr, len);
len = (size_t) totalread;
}