[PATCH final 2/3] POSIX Asynchronous I/O support: fhandler files
Mark Geisert
mark@maxrnd.com
Tue Jul 24 05:32:00 GMT 2018
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.)
---
winsup/cygwin/fhandler.cc | 4 +-
winsup/cygwin/fhandler.h | 11 +--
winsup/cygwin/fhandler_disk_file.cc | 100 ++++++++++++++++++++--------
winsup/cygwin/fhandler_tty.cc | 2 +-
4 files changed, 83 insertions(+), 34 deletions(-)
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 45ae1ad97..ded12cc44 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -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;
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index 88653b6e9..b946dddf4 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -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 (); }
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index fc87d91c1..b58b8442a 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -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 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))
+ 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;
}
diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
index 0b8185d90..7fe46ebef 100644
--- a/winsup/cygwin/fhandler_tty.cc
+++ b/winsup/cygwin/fhandler_tty.cc
@@ -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;
}
--
2.17.0
More information about the Cygwin-patches
mailing list