HARNESS_SRCS:=main.c
# io_queue.c
-CFLAGS+=-Wall -Werror -I../src -g -O2 -DPAGE_SIZE=$(shell getconf PAGESIZE)
+CFLAGS+=-Wall -Werror -I../src -g -O2
#-lpthread -lrt
+# gcc-11 does not like the test case in 3.t that
+# passes an invalid pointer (-1) to the kernel, so
+# tell the compiler we do not need a warning here
+cases/3.p: CFLAGS+=-Wno-stringop-overflow
+
+# Change this on the build line to run tests against the installed libraries:
+# make LIBAIO=-laio partcheck
+LIBAIO?=../src/libaio.a
+
all: $(PROGS)
$(PROGS): %.p: %.t $(HARNESS_SRCS)
- $(CC) $(CFLAGS) -DTEST_NAME=\"$<\" -o $@ main.c ../src/libaio.a -lpthread
+ $(CC) $(CFLAGS) -DTEST_NAME=\"$<\" -o $@ main.c $(LIBAIO) -lpthread
clean:
rm -f $(PROGS) *.o runtests.out rofile wofile rwfile
#define SYS_eventfd 318
#elif defined(__alpha__)
#define SYS_eventfd 478
-#elif defined(__aarch64__)
-/* arm64 does not implement eventfd, only eventfd2 */
+#elif defined(__aarch64__) || defined(__loongarch__) || defined(__riscv)
+/* these recent architectures do not implement eventfd, only eventfd2 */
#define USE_EVENTFD2
#ifndef SYS_eventfd2
#define SYS_eventfd2 19
-#endif /* __aarch64__ */
+#endif /* __aarch64__ || __riscv */
#else
#error define SYS_eventfd for your arch!
#endif
void run_test(int max_ios, int getevents_type)
{
- int fd, ret;
+ int fd, ret, flags;
long i, to_submit;
struct iocb **iocb_sub;
io_context_t io_ctx;
events = calloc(max_ios, sizeof(*events));
unlink(filename);
- fd = open(filename, O_CREAT | O_RDWR | O_DIRECT, 0644);
+ fd = open(filename, O_CREAT | O_RDWR, 0644);
assert(fd >= 0);
+ /*
+ * Use O_DIRECT if it's available. If it's not, the test code
+ * will still operate correctly, just potentially slower.
+ */
+ flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_DIRECT);
+
ret = ftruncate(fd, max_ios * io_size);
assert(!ret);
#define THREADS_NUM 100
+static size_t page_size;
+
void
aio_worker(void *ptr)
{
- int i, j, fd;
- char buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+ int i, j, fd, ret;
+ char *buffer = NULL;
+
+ ret = posix_memalign((void **)&buffer, page_size, page_size);
+ assert(ret == 0);
+ assert(buffer != NULL);
fd = open(FILENAME, O_DIRECT|O_RDONLY);
+ if (fd < 0 && errno == EINVAL)
+ exit(3); /* skip this test, O_DIRECT is unavailable */
assert(fd >= 0);
for (i = 0; i < 1000; i++) {
struct iocb *cbs[1];
assert(!io_queue_init(1, &ctx));
- io_prep_pread(&cb, fd, buffer, PAGE_SIZE, 0);
+ io_prep_pread(&cb, fd, buffer, page_size, 0);
cbs[0] = &cb;
- memset(buffer, '0', PAGE_SIZE);
+ memset(buffer, '0', page_size);
assert(io_submit(ctx, 1, &cbs[0]) == 1);
// wait random time (0-500ms) ?
io_destroy(ctx);
- memset(buffer, DESTROY_PATTERN, PAGE_SIZE);
+ memset(buffer, DESTROY_PATTERN, page_size);
// wait random for (0-500ms) ?
// check it is still DESTROY_PATTERN
- for (j = 0; j < PAGE_SIZE; j++) {
+ for (j = 0; j < page_size; j++) {
if (buffer[j] != DESTROY_PATTERN) {
fprintf(stderr,
"Buffer has unexpected character: %c\n",
}
}
+ free(buffer);
close(fd);
}
test_main(void)
{
int i, fd, ret;
- char buffer[PAGE_SIZE];
+ char *buffer = NULL;
pthread_t threads[THREADS_NUM];
+ page_size = sysconf(_SC_PAGESIZE);
+ assert(page_size >= 1);
+
+ ret = posix_memalign((void **)&buffer, page_size, page_size);
+ assert(ret == 0);
+ assert(buffer != NULL);
+
fd = open(FILENAME, O_CREAT|O_TRUNC|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
assert(fd != -1);
- memset(buffer, FILEPATTERN, PAGE_SIZE);
- ret = write(fd, buffer, PAGE_SIZE);
- assert(ret == PAGE_SIZE);
+ memset(buffer, FILEPATTERN, page_size);
+ ret = write(fd, buffer, page_size);
+ assert(ret == page_size);
close(fd);
for (i = 0; i < THREADS_NUM; i++) {
int
open_temp_file(void)
{
- int fd;
+ int fd, flags;
char template[sizeof(TEMPLATE)];
- strncpy(template, TEMPLATE, sizeof(TEMPLATE));
- fd = mkostemp(template, O_DIRECT);
+ strncpy(template, TEMPLATE, sizeof(template));
+ fd = mkstemp(template);
if (fd < 0) {
perror("mkstemp");
exit(1);
}
+ /*
+ * O_DIRECT is desirable, but not required for this test.
+ */
+ flags = fcntl(F_GETFL, 0);
+ fcntl(F_SETFL, flags | O_DIRECT);
+
unlink(template);
return fd;
}
int fd;
char temp_file[sizeof(TEMPLATE)];
- strncpy(temp_file, TEMPLATE, sizeof(TEMPLATE));
+ strncpy(temp_file, TEMPLATE, sizeof(temp_file));
fd = mkstemp(temp_file);
if (fd < 0) {
perror("mkstemp");
*/
flags = fcntl(fd, F_GETFL);
ret = fcntl(fd, F_SETFL, flags | O_DIRECT);
- if (ret != 0) {
+ if (ret < 0) {
+ /* SKIP this test if O_DIRECT is not available on this fs */
+ if (errno == EINVAL)
+ return 3;
perror("fcntl");
return 1;
}
ret = io_submit(ctx, 1, &iocbp);
/*
- * io_submit will return -EINVAL if RWF_NOWAIT is not supported.
+ * io_submit will return -EINVAL if RWF_NOWAIT is not supported by
+ * the kernel, and EOPNOTSUPP if it's not supported by the fs.
*/
if (ret != 1) {
- if (ret == -EINVAL) {
- fprintf(stderr, "RWF_NOWAIT not supported by kernel.\n");
- /* just return success */
- return 0;
+ if (ret == -EINVAL || ret == -ENOTSUP) {
+ fprintf(stderr, "RWF_NOWAIT not supported by %s.\n",
+ ret == -EINVAL ? "kernel" : "file system");
+ /* skip this test */
+ return 3;
}
errno = -ret;
perror("io_submit");
ret = io_setup(1, &ctx);
if (ret) {
- printf("child: io_setup failed\n");
+ printf("child: io_setup failed: %s\n", strerror(-ret));
return 1;
}
io_prep_poll(&iocb, pipe1[0], POLLIN);
ret = io_submit(ctx, 1, iocbs);
if (ret != 1) {
- printf("child: io_submit failed\n");
+ /* if poll isn't supported, skip the test */
+ if (ret == -EINVAL)
+ return 3;
+ printf("child: io_submit failed: %s\n", strerror(-ret));
return 1;
}
ret = io_pgetevents(ctx, 1, 1, &ev, &to, &sigmask);
} while (ret == 0);
+ /* SKIP if the syscall has not been implemented. */
+ if (ret == -ENOSYS)
+ return 3;
+
if (ret != -EINTR) {
- printf("child: io_pgetevents did not set errno to EINTR\n");
+ printf("child: io_pgetevents did not set errno to "
+ "EINTR: %s\n", strerror(-ret));
return 1;
}
ret = io_setup(1, &ctx);
if (ret) {
- printf("parent: io_setup failed\n");
+ printf("parent: io_setup failed: %s\n", strerror(-ret));
return 1;
}
ret = io_submit(ctx, 1, iocbs);
if (ret != 1) {
- printf("parent: io_submit failed\n");
+ /* if poll isn't supported, skip the test */
+ if (ret == -EINVAL)
+ return 3;
+ printf("parent: io_submit failed with %d: %s\n",
+ ret, strerror(-ret));
return 1;
}
kill(p, SIGUSR1);
ret = io_pgetevents(ctx, 1, 1, &ev, NULL, &sigmask);
+ /* SKIP if the syscall has not been implemented. */
+ if (ret == -ENOSYS)
+ return 3;
if (ret < 0) {
- printf("parent: io_pgetevents failed\n");
+ printf("parent: io_pgetevents failed: %s\n",
+ strerror(-ret));
return 1;
}
if (ret != 1) {
return 0;
}
}
+/*
+ * Local variables:
+ * mode: c
+ * c-basic-offset: 8
+ * End:
+ */
--- /dev/null
+// SPDX-License-Identifier: LGPL-2.1+
+/*
+ * Copyright 2022 Google LLC
+ */
+
+/*
+ * Verify that aio poll doesn't miss any events. This is a regression test for
+ * kernel commit 363bee27e258 ("aio: keep poll requests on waitqueue until
+ * completed").
+ *
+ * This test repeatedly does the following operations in parallel:
+ *
+ * Thread 1: Aio-poll the read end of a pipe, then wait for it to complete.
+ * Thread 2: Splice a byte to the pipe.
+ * Thread 3: Read from the pipe, then splice another byte to it.
+ *
+ * The pipe will never be empty at the end, so the poll should always complete.
+ * With the bug, that didn't always happen, as the second splice sometimes
+ * didn't cause a wakeup due to the waitqueue entry being temporarily removed,
+ * as per the following buggy sequence of events:
+ *
+ * 1. Thread 1 adds the poll waitqueue entry.
+ * 2. Thread 2 does the first splice. This calls the poll wakeup function,
+ * which deletes the waitqueue entry [BUG!], then schedules the async
+ * completion work.
+ * 3. Thread 3 reads from the pipe.
+ * 4. Async work sees that the pipe isn't ready.
+ * 5. Thread 3 splices some data to the pipe, but doesn't call the poll
+ * wakeup function because the waitqueue is currently empty.
+ * 6. Async work re-adds the waitqueue entry, as the pipe wasn't ready.
+ *
+ * The reason we use splice() rather than write() is because in order for step
+ * (2) to not complete the poll inline, the kernel must not pass an event mask
+ * to the wakeup function. This is the case for splice() to a pipe, but not
+ * write() to a pipe (at least in the kernel versions with the bug).
+ */
+#include <poll.h>
+#include <pthread.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <sys/wait.h>
+
+static int tmpfd;
+static int pipefds[2];
+static pthread_barrier_t barrier;
+static bool exiting;
+
+static void fail(const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ vfprintf(stderr, format, va);
+ putc('\n', stderr);
+ va_end(va);
+ exit(1);
+}
+
+static void fail_errno(const char *format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ vfprintf(stderr, format, va);
+ fprintf(stderr, ": %s", strerror(errno));
+ putc('\n', stderr);
+ va_end(va);
+ exit(1);
+}
+
+/* Thread 2 */
+static void *thrproc2(void *arg)
+{
+ for (;;) {
+ off_t offset = 0;
+
+ pthread_barrier_wait(&barrier);
+ if (exiting)
+ break;
+
+ /* Splice a byte to the pipe. */
+ if (splice(tmpfd, &offset, pipefds[1], NULL, 1, 0) != 1)
+ fail_errno("splice failed in thread 2");
+
+ pthread_barrier_wait(&barrier);
+ }
+ return NULL;
+}
+
+/* Thread 3 */
+static void *thrproc3(void *arg)
+{
+ for (;;) {
+ char c;
+ off_t offset = 0;
+
+ pthread_barrier_wait(&barrier);
+ if (exiting)
+ break;
+
+ /* Read a byte from the pipe. */
+ if (read(pipefds[0], &c, 1) != 1)
+ fail_errno("read failed in thread 3");
+
+ /* Splice a byte to the pipe. */
+ if (splice(tmpfd, &offset, pipefds[1], NULL, 1, 0) != 1)
+ fail_errno("splice failed in thread 3");
+
+ pthread_barrier_wait(&barrier);
+ }
+ return NULL;
+}
+
+static int child_process(void)
+{
+ int ret;
+ io_context_t ctx = NULL;
+ pthread_t t2, t3;
+ int i;
+ struct iocb iocb;
+ struct iocb *iocbs[] = { &iocb };
+ struct io_event event;
+ struct timespec timeout = { .tv_sec = 5 };
+ char c;
+
+ ret = io_setup(1, &ctx);
+ if (ret != 0) {
+ errno = -ret;
+ fail_errno("io_setup failed");
+ }
+
+ if (pipe(pipefds) != 0)
+ fail_errno("pipe failed");
+
+ errno = pthread_barrier_init(&barrier, NULL, 3);
+ if (errno)
+ fail_errno("pthread_barrier_init failed");
+
+ errno = pthread_create(&t2, NULL, thrproc2, NULL);
+ if (errno)
+ fail_errno("pthread_create failed");
+
+ errno = pthread_create(&t3, NULL, thrproc3, NULL);
+ if (errno)
+ fail_errno("pthread_create failed");
+
+ for (i = 0; i < 5000; i++) {
+ /* Thread 1 */
+
+ /* Submit a poll request. */
+ io_prep_poll(&iocb, pipefds[0], POLLIN);
+ ret = io_submit(ctx, 1, iocbs);
+ if (ret != 1) {
+ /* If aio poll isn't supported, skip the test. */
+ errno = -ret;
+ if (errno == EINVAL) {
+ printf("aio poll is not supported\n");
+ return 3;
+ }
+ fail_errno("io_submit failed");
+ }
+
+ /* Tell the other threads to continue. */
+ pthread_barrier_wait(&barrier);
+
+ /*
+ * Wait for the poll to complete. Wait at most 5 seconds, in
+ * case we hit the bug so the poll wouldn't otherwise complete.
+ */
+ ret = io_getevents(ctx, 1, 1, &event, &timeout);
+ if (ret < 0) {
+ errno = -ret;
+ fail_errno("io_getevents failed");
+ }
+ if (ret == 0) {
+ /*
+ * The poll eventually timed out rather than giving us
+ * an event, so we've detected the bug.
+ */
+ fail("FAIL: poll missed an event!");
+ }
+
+ /* Wait for the other threads to finish their iteration. */
+ pthread_barrier_wait(&barrier);
+
+ /* The pipe has 1 byte; read it to get back to initial state. */
+ if (read(pipefds[0], &c, 1) != 1)
+ fail_errno("read failed in thread 1");
+ }
+ exiting = true;
+ pthread_barrier_wait(&barrier);
+ errno = pthread_join(t2, NULL);
+ if (errno)
+ fail_errno("pthread_join failed");
+ errno = pthread_join(t3, NULL);
+ if (errno)
+ fail_errno("pthread_join failed");
+ return 0;
+}
+
+int test_main(void)
+{
+ char tmpfile_name[] = "/tmp/aio.XXXXXX";
+ int ret;
+ int ncpus;
+ int i;
+ int overall_status = 0;
+ int status;
+
+ /* Create a 1-byte temporary file. */
+ tmpfd = mkstemp(tmpfile_name);
+ if (tmpfd < 0) {
+ fprintf(stderr, "failed to create temporary file: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ if (pwrite(tmpfd, "X", 1, 0) != 1) {
+ fprintf(stderr, "failed to write to temporary file: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ /*
+ * Run the test in multiple processes to increase the chance of hitting
+ * the race condition.
+ */
+ ret = sysconf(_SC_NPROCESSORS_CONF);
+ if (ret < 1) {
+ fprintf(stderr, "failed to get number of CPUs: %s\n",
+ strerror(errno));
+ return 1;
+ }
+ ncpus = ret;
+ for (i = 0; i < ncpus; i++) {
+ ret = fork();
+ if (ret < 0) {
+ fprintf(stderr, "fork failed: %s\n", strerror(errno));
+ return 1;
+ }
+ if (ret == 0)
+ exit(child_process());
+ }
+ for (i = 0; i < ncpus; i++) {
+ if (wait(&status) < 0) {
+ fprintf(stderr, "wait failed: %s\n", strerror(errno));
+ return 1;
+ }
+ if (!WIFEXITED(status))
+ overall_status = 1;
+ else if (overall_status == 0)
+ overall_status = WEXITSTATUS(status);
+ }
+ unlink(tmpfile_name);
+ return overall_status;
+}
buf = mmap(0, page_size, PROT_WRITE, MAP_SHARED, rwfd, 0);
assert(buf != (char *)-1);
- status |= attempt_rw(rwfd, buf, SIZE, 0, READ, SIZE);
-
/* Whether PROT_WRITE is readable is arch-dependent. So compare
- * against read result. */
- res = read(rwfd, buf, SIZE);
+ * against write() result (to make the kernel read from buf). */
+ res = write(rwfd, buf, SIZE);
if (res < 0)
res = -errno;
+ status |= attempt_rw(rwfd, buf, SIZE, 0, READ, SIZE);
status |= attempt_rw(rwfd, buf, SIZE, 0, WRITE, res);
return status;
int main(void)
{
int res;
+ const char *test_result;
#if defined(SETUP)
SETUP;
#endif
res = test_main();
- printf("test %s completed %s.\n", test_name,
- res ? "FAILED" : "PASSED"
- );
+ switch(res) {
+ case 0:
+ test_result = "PASSED";
+ break;
+ case 3:
+ test_result = "SKIPPED";
+ break;
+ default:
+ test_result = "FAILED";
+ res = 1;
+ break;
+ }
+
+ printf("test %s completed %s.\n", test_name, test_result);
fflush(stdout);
- return res ? 1 : 0;
+ return res;
}
passes=0
fails=0
+skips=0
echo "Test run starting at" `date`
echo "Starting $this_test"
$this_test 2>&1
res=$?
- if [ $res -eq 0 ] ; then str="" ; passes=$[passes + 1] ; else str=" -- FAILED" ; fails=$[fails + 1] ; fi
+ if [ $res -eq 0 ]; then
+ str="";
+ passes=$((passes + 1));
+ elif [ $res -eq 3 ]; then
+ str=" -- SKIPPED";
+ skips=$((skips + 1));
+ else
+ str=" -- FAILED"
+ fails=$((fails + 1));
+ fi
echo "Completed $this_test with $res$str".
done
-echo "Pass: $passes Fail: $fails"
+echo "Pass: $passes Fail: $fails Skip: $skips"
echo "Test run complete at" `date`
+
+exit $fails
Name: libaio
-Version: 0.3.112
+Version: 0.3.113
Release: 1
Summary: Linux-native asynchronous I/O access library
License: LGPL
Source: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-root
# Fix ExclusiveArch as we implement this functionality on more architectures
-ExclusiveArch: i386 x86_64 ia64 s390 s390x ppc ppc64 ppc64pseries ppc64iseries alpha alphaev6 %{arm}
+ExclusiveArch: i386 x86_64 ia64 s390 s390x ppc ppc64 ppc64pseries ppc64iseries alpha alphaev6 %{arm} loongarch64
%description
The Linux-native asynchronous I/O facility ("async I/O", or "aio") has a
%attr(0644,root,root) %{_libdir}/libaio.a
%changelog
+* Mon Mar 28 2022 Jeff Moyer <jmoyer@redhat.com> - 0.3.113-1
+- Fix padding in vector and sockaddr structures on 32 bit (Brett Holman)
+- Add a test case for missed poll events (Eric Biggers)
+- Add loongarch support (Yehui Ren)
+- man page cleanup and fixes (Guillem Jover)
+- assorted test harness fixess (Guillem Jover, Jeff Moyer)
+
* Mon Oct 22 2018 Jeff Moyer <jmoyer@redhat.com> - 0.3.112-1
- Add async poll support (Christoph Hellwig)
- Use canonical DESTDIR= environment variable (Thomas Petazzoni)
-.TH io 3 2002-09-12 "Linux 2.4" Linux IO"
+.TH io 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io \- Asynchronous IO
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.sp
.br
-.B #include <libio.h>
+.B #include <libaio.h>
.sp
.fi
.SH DESCRIPTION
-The libaio library defines a new set of I/O operations which can
+The
+.B libaio
+library defines a new set of I/O operations which can
significantly reduce the time an application spends waiting at I/O. The
new functions allow a program to initiate one or more I/O operations and
then immediately resume normal work while the I/O operations are
executed in parallel.
These functions are part of the library with realtime functions named
-.IR "libaio"
-. They are not actually part of the
-.IR "libc"
+.BR libaio .
+They are not actually part of the
+.B libc
binary.
The implementation of these functions can be done using support in the
kernel.
All IO operations operate on files which were opened previously. There
might be arbitrarily many operations running for one file. The
asynchronous I/O operations are controlled using a data structure named
-.IR "struct iocb"
+.B struct iocb
It is defined in
-.IR "libio.h"
+.I libaio.h
as follows.
.nf
.fi
.TP
-.IR "int aio_fildes"
+.BI int " aio_fildes"
This element specifies the file descriptor to be used for the
operation. It must be a legal descriptor, otherwise the operation will
fail.
The device on which the file is opened must allow the seek operation.
I.e., it is not possible to use any of the IO operations on devices
like terminals where an
-.IR "lseek"
+.BR lseek (2)
call would lead to an error.
.TP
-.IR "long u.c.offset"
+.BI long " u.c.offset"
This element specifies the offset in the file at which the operation (input
or output) is performed. Since the operations are carried out in arbitrary
order and more than one operation for one file descriptor can be
started, one cannot expect a current read/write position of the file
descriptor.
.TP
-.IR "void *buf"
+.BI "void *" buf
This is a pointer to the buffer with the data to be written or the place
where the read data is stored.
.TP
-.IR "long u.c.nbytes"
+.BI long " u.c.nbytes"
This element specifies the length of the buffer pointed to by
-.IR "io_buf"
-.
+.IR io_buf .
.TP
-.IR "int aio_reqprio"
+.BI int " aio_reqprio"
Is not currently used.
.TP
.B "IO_CMD_PREAD"
Start a read operation. Read from the file at position
-.IR "u.c.offset"
+.I u.c.offset
and store the next
-.IR "u.c.nbytes"
+.I u.c.nbytes
bytes in the
buffer pointed to by
-.IR "buf"
-.
+.IR buf .
.TP
.B "IO_CMD_PWRITE"
Start a write operation. Write
-.IR "u.c.nbytes"
+.I u.c.nbytes
bytes starting at
-.IR "buf"
+.I buf
into the file starting at position
-.IR "u.c.offset"
-.
+.IR u.c.offset .
.TP
.B "IO_CMD_NOP"
Do nothing for this control block. This value is useful sometimes when
an array of
-.IR "struct iocb"
+.B struct iocb
values contains holes, i.e., some of the
values must not be handled although the whole array is presented to the
-.IR "io_submit"
+.BR io_submit (3)
function.
.TP
.B "IO_CMD_FSYNC"
-.TP
+.TQ
.B "IO_CMD_POLL"
This is experimental.
.SH EXAMPLE
static void io_error(const char *func, int rc)
{
if (rc == -ENOSYS)
- fprintf(stderr, "AIO not in this kernel\n");
+ fprintf(stderr, "AIO not in this kernel\\n");
else if (rc < 0 && -rc < sys_nerr)
- fprintf(stderr, "%s: %s\n", func, sys_errlist[-rc]);
+ fprintf(stderr, "%s: %s\\n", func, sys_errlist[-rc]);
else
- fprintf(stderr, "%s: error %d\n", func, rc);
+ fprintf(stderr, "%s: error %d\\n", func, rc);
if (dstfd > 0)
close(dstfd);
io_error("aio write", res2);
}
if (res != iocb->u.c.nbytes) {
- fprintf(stderr, "write missed bytes expect %d got %d\n", iocb->u.c.nbytes, res2);
+ fprintf(stderr, "write missed bytes expect %d got %d\\n", iocb->u.c.nbytes, res2);
exit(1);
}
--tocopy;
if (res2 != 0)
io_error("aio read", res2);
if (res != iosize) {
- fprintf(stderr, "read missing bytes expect %d got %d\n", iocb->u.c.nbytes, res);
+ fprintf(stderr, "read missing bytes expect %d got %d\\n", iocb->u.c.nbytes, res);
exit(1);
}
char *buf = (char *) malloc(iosize);
if (NULL == buf || NULL == io) {
- fprintf(stderr, "out of memory\n");
+ fprintf(stderr, "out of memory\\n");
exit(1);
}
*/
.fi
.SH "SEE ALSO"
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-.TH io_cancel 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.TH io_cancel 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_cancel \- Cancel io requests
.SH SYNOPSIS
.B #include <libaio.h>
.sp
.br
-.BI "int io_cancel(io_context_t ctx, struct iocb *iocb)"
+.BI "int io_cancel(io_context_t " ctx ", struct iocb *" iocb ");"
.br
.sp
struct iocb {
};
.fi
.SH DESCRIPTION
-Attempts to cancel an iocb previously passed to io_submit. If
-the operation is successfully cancelled, the resulting event is
+Attempts to cancel an
+.I iocb
+previously passed to
+.BR io_submit (3).
+If the operation is successfully cancelled, the resulting event is
copied into the memory pointed to by result without being placed
into the completion queue.
.PP
writes data in files in a situation where new incoming data would have
to be written in a file which will be updated by an enqueued request.
.SH "RETURN VALUES"
-0 is returned on success , otherwise returns Errno.
+\fI0\fP is returned on success, otherwise returns \fIerrno\fP.
.SH ERRORS
.TP
.B EFAULT
If any of the data structures pointed to are invalid.
.TP
.B EINVAL
-If aio_context specified by ctx_id is
-invalid.
+If
+.I aio_context
+specified by
+.I ctx
+is invalid.
.TP
.B EAGAIN
-If the iocb specified was not
-cancelled.
+If the
+.I iocb
+specified was not cancelled.
.TP
.B ENOSYS
-if not implemented.
+If not implemented.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-./" static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
-./" {
-./" io_prep_fsync(iocb, fd);
-./" io_set_callback(iocb, cb);
-./" return io_submit(ctx, 1, &iocb);
-./" }
-.TH io_fsync 3 2002-09-12 "Linux 2.4" Linux AIO"
+.\" static inline int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)
+.\" {
+.\" io_prep_fsync(iocb, fd);
+.\" io_set_callback(iocb, cb);
+.\" return io_submit(ctx, 1, &iocb);
+.\" }
+.TH io_fsync 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_fsync \- Synchronize a file's complete in-core state with that on disk
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.sp
.B #include <libaio.h>
.sp
.br
-.BI "int io_fsync(io_context_t ctx, struct iocb *iocb, io_callback_t cb, int fd)"
+.BI "int io_fsync(io_context_t " ctx ", struct iocb *" iocb ", io_callback_t " cb ", int " fd ");"
.sp
struct iocb {
void *data;
Calling this function forces all I/O operations operating queued at the
time of the function call operating on the file descriptor
.IR "iocb->io_fildes"
-into the synchronized I/O completion state . The
-.IR "io_fsync"
+into the synchronized I/O completion state. The
+.BR io_fsync ()
function returns
immediately but the notification through the method described in
.IR "io_callback"
means that requests for this very same file descriptor which are queued
after the synchronization request are not affected.
.SH "RETURN VALUES"
-Returns 0, otherwise returns errno.
+Returns
+.BR 0 ,
+otherwise returns
+.IR errno .
.SH ERRORS
.TP
.B EFAULT
.TP
.B EINVAL
.I ctx
-refers to an unitialized aio context, the iocb pointed to by
+refers to an uninitialized aio context, the iocb pointed to by
.I iocbs
contains an improperly initialized iocb,
.TP
.B EINVAL
The file specified in the iocb does not support the given io operation.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_getevents(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_getevents (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-./"/* io_getevents:
-./" * Attempts to read at least min_nr events and up to nr events from
-./" * the completion queue for the aio_context specified by ctx_id. May
-./" * fail with -EINVAL if ctx_id is invalid, if min_nr is out of range,
-./" * if nr is out of range, if when is out of range. May fail with
-./" * -EFAULT if any of the memory specified to is invalid. May return
-./" * 0 or < min_nr if no events are available and the timeout specified
-./" * by when has elapsed, where when == NULL specifies an infinite
-./" * timeout. Note that the timeout pointed to by when is relative and
-./" * will be updated if not NULL and the operation blocks. Will fail
-./" * with -ENOSYS if not implemented.
-./" */
-./"asmlinkage long sys_io_getevents(io_context_t ctx_id,
-./" long min_nr,
-./" long nr,
-./" struct io_event *events,
-./" struct timespec *timeout)
-./"
-.TH io_getevents 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.\"/* io_getevents:
+.\" * Attempts to read at least min_nr events and up to nr events from
+.\" * the completion queue for the aio_context specified by ctx. May
+.\" * fail with -EINVAL if ctx is invalid, if min_nr is out of range,
+.\" * if nr is out of range, if when is out of range. May fail with
+.\" * -EFAULT if any of the memory specified to is invalid. May return
+.\" * 0 or < min_nr if no events are available and the timeout specified
+.\" * by when has elapsed, where when == NULL specifies an infinite
+.\" * timeout. Note that the timeout pointed to by when is relative and
+.\" * will be updated if not NULL and the operation blocks. Will fail
+.\" * with -ENOSYS if not implemented.
+.\" */
+.\"asmlinkage long sys_io_getevents(io_context_t ctx,
+.\" long min_nr,
+.\" long nr,
+.\" struct io_event *events,
+.\" struct timespec *timeout)
+.\"
+.TH io_getevents 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_getevents, aio_pgetevents \- Read resulting events from io requests
.SH SYNOPSIS
unsigned PADDED(res2, __pad4);
};
.sp
-.BI "int io_getevents(io_context_t " ctx ", long " nr ", struct io_event *" events "[], struct timespec *" timeout ");"
-.BI "int io_pgetevents(io_context_t " ctx ", long " nr ", struct io_event *" events "[], struct timespec *" timeout ", sigset_t *" sigmask ");"
+.BI "int io_getevents(io_context_t " ctx ", long " nr ", struct io_event *" events "[], struct timespec *" timeout ");"
+.BI "int io_pgetevents(io_context_t " ctx ", long " nr ", struct io_event *" events "[], struct timespec *" timeout ", sigset_t *" sigmask ");"
.fi
.SH DESCRIPTION
-Attempts to read up to nr events from
-the completion queue for the aio_context specified by ctx.
+Attempts to read up to
+.I nr
+events from the completion queue for the aio_context specified by
+.IR ctx .
.SH "RETURN VALUES"
May return
-0 if no events are available and the timeout specified
-by when has elapsed, where when == NULL specifies an infinite
+.B 0
+if no events are available and the timeout specified
+by when has elapsed, where
+.I when
+== NULL specifies an infinite
timeout. Note that the timeout pointed to by when is relative and
-will be updated if not NULL and the operation blocks. Will fail
-with ENOSYS if not implemented.
+will be updated if not NULL and the operation blocks. Will fail with
+.B ENOSYS
+if not implemented.
.SS io_pgetevents()
The relationship between
.BR io_getevents ()
.BR select (2)
and
.BR pselect (2):
-similar
+similar to
.BR pselect (2),
.BR pgetevents ()
allows an application to safely wait until either an aio completion
-events happens or until a signal is caught.
+event happens or until a signal is caught.
.PP
The following
.BR io_pgetevents ()
call:
-call:
.PP
.in +4n
.EX
performed (and thus
.BR io_pgetevents ()
behaves the same as
-.BR io_getevents()
-) .
+.BR io_getevents() ).
.SH ERRORS
.TP
.B EINVAL
-if ctx_id is invalid, if min_nr is out of range,
-if nr is out of range, if when is out of range.
+If
+.I ctx
+is invalid, if
+.I min_nr
+is out of range, if
+.I nr
+is out of range, if
+.I when
+is out of range.
.TP
.B EFAULT
-if any of the memory specified to is invalid.
+If any of the memory specified to is invalid.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3),
-.BR pselect(2)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3),
+.BR pselect (2).
-./" static inline void io_prep_fsync(struct iocb *iocb, int fd)
-./" {
-./" memset(iocb, 0, sizeof(*iocb));
-./" iocb->aio_fildes = fd;
-./" iocb->aio_lio_opcode = IO_CMD_FSYNC;
-./" iocb->aio_reqprio = 0;
-./" }
-.TH io_prep_fsync 3 2002-09-12 "Linux 2.4" Linux AIO"
+.\" static inline void io_prep_fsync(struct iocb *iocb, int fd)
+.\" {
+.\" memset(iocb, 0, sizeof(*iocb));
+.\" iocb->aio_fildes = fd;
+.\" iocb->aio_lio_opcode = IO_CMD_FSYNC;
+.\" iocb->aio_reqprio = 0;
+.\" }
+.TH io_prep_fsync 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_prep_fsync \- Synchronize a file's complete in-core state with that on disk
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.br
.B #include <libaio.h>
.br
.sp
-.BI "static inline void io_prep_fsync(struct iocb *iocb, int fd)"
+.BI "static inline void io_prep_fsync(struct iocb *" iocb ", int " fd ");"
.sp
struct iocb {
void *data;
.sp
.fi
.SH DESCRIPTION
-This is an inline convenience function for setting up an iocbv for a FSYNC request.
-.br
+This is an inline convenience function for setting up an
+.I iocbv
+for a
+.B FSYNC
+request.
+.
+.PP
The file for which
-.TP
+.nf
.IR "iocb->aio_fildes = fd"
-is a descriptor is set up with
-the command
-.TP
-.IR "iocb->aio_lio_opcode = IO_CMD_FSYNC:
+.fi
+is a descriptor is set up with the command
+.nf
+.IR "iocb->aio_lio_opcode = IO_CMD_FSYNC"
+.fi
.
.PP
-The io_prep_fsync() function shall set up an IO_CMD_FSYNC operation
-to asynchronously force all I/O
+The
+.BR io_prep_fsync ()
+function shall set up an
+.B IO_CMD_FSYNC
+operation to asynchronously force all I/O
operations associated with the file indicated by the file
-descriptor aio_fildes member of the iocb structure referenced by
+descriptor
+.I aio_fildes
+member of the
+.I iocb
+structure referenced by
the iocb argument and queued at the time of the call to
-io_submit() to the synchronized I/O completion state. The function
+.BR io_submit ()
+to the synchronized I/O completion state. The function
call shall return when the synchronization request has been
initiated or queued to the file or device (even when the data
cannot be synchronized immediately).
All currently queued I/O operations shall be completed as if by a call
-to fsync(); that is, as defined for synchronized I/O file
+to
+.BR fsync (2);
+that is, as defined for synchronized I/O file
integrity completion. If the
-operation queued by io_prep_fsync() fails, then, as for fsync(),
+operation queued by
+.BR io_prep_fsync ()
+fails, then, as for
+.BR fsync (2),
outstanding I/O operations are not guaranteed to have
been completed.
-If io_prep_fsync() succeeds, then it is only the I/O that was queued
-at the time of the call to io_submit() that is guaranteed to be
+If
+.BR io_prep_fsync ()
+succeeds, then it is only the I/O that was queued
+at the time of the call to
+.BR io_submit (3)
+that is guaranteed to be
forced to the relevant completion state. The completion of
subsequent I/O on the file descriptor is not guaranteed to be
completed in a synchronized fashion.
.PP
-This function returns immediately . To schedule the operation, the
+This function returns immediately. To schedule the operation, the
function
-.IR io_submit
+.BR io_submit (3)
must be called.
.PP
-Simultaneous asynchronous operations using the same iocb produce
-undefined results.
+Simultaneous asynchronous operations using the same
+.I iocb
+produce undefined results.
.SH "RETURN VALUES"
-None
+None.
.SH ERRORS
-None
+None.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-./" static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
-./" {
-./" memset(iocb, 0, sizeof(*iocb));
-./" iocb->aio_fildes = fd;
-./" iocb->aio_lio_opcode = IO_CMD_PREAD;
-./" iocb->aio_reqprio = 0;
-./" iocb->u.c.buf = buf;
-./" iocb->u.c.nbytes = count;
-./" iocb->u.c.offset = offset;
-./" }
-.TH io_prep_pread 3 2002-09-12 "Linux 2.4" Linux AIO"
+.\" static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
+.\" {
+.\" memset(iocb, 0, sizeof(*iocb));
+.\" iocb->aio_fildes = fd;
+.\" iocb->aio_lio_opcode = IO_CMD_PREAD;
+.\" iocb->aio_reqprio = 0;
+.\" iocb->u.c.buf = buf;
+.\" iocb->u.c.nbytes = count;
+.\" iocb->u.c.offset = offset;
+.\" }
+.TH io_prep_pread 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_prep_pread \- Set up asynchronous read
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.sp
.B #include <libaio.h>
.br
.sp
-.BI "inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
-"
+.BI "inline void io_prep_pread(struct iocb *" iocb ", int " fd ", void *" buf ", size_t " count ", long long " offset ");"
+.
.sp
struct iocb {
void *data;
};
.fi
.SH DESCRIPTION
-.IR io_prep_pread
+.BR io_prep_pread ()
is an inline convenience function designed to facilitate the initialization of
the iocb for an asynchronous read operation.
The first
-.TP
-.IR "iocb->u.c.nbytes = count"
+.I iocb->u.c.nbytes = count
bytes of the file for which
-.TP
-.IR "iocb->aio_fildes = fd"
+.I iocb->aio_fildes = fd
is a descriptor are written to the buffer
starting at
-.TP
-.IR "iocb->u.c.buf = buf"
-.
-.br
+.IR "iocb->u.c.buf = buf" .
Reading starts at the absolute position
-.TP
-.IR "ioc->u.c.offset = offset"
+.I ioc->u.c.offset = offset
in the file.
.PP
-This function returns immediately . To schedule the operation, the
+This function returns immediately. To schedule the operation, the
function
-.IR io_submit
+.BR io_submit (3)
must be called.
.PP
-Simultaneous asynchronous operations using the same iocb produce
+Simultaneous asynchronous operations using the same \fIiocb\fP produce
undefined results.
.SH "RETURN VALUES"
-None
+None.
.SH ERRORS
-None
+None.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-./" static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
-./" {
-./" memset(iocb, 0, sizeof(*iocb));
-./" iocb->aio_fildes = fd;
-./" iocb->aio_lio_opcode = IO_CMD_PWRITE;
-./" iocb->aio_reqprio = 0;
-./" iocb->u.c.buf = buf;
-./" iocb->u.c.nbytes = count;
-./" iocb->u.c.offset = offset;
-./" }
-.TH io_prep_pwrite 3 2002-09-12 "Linux 2.4" Linux AIO"
+.\" static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
+.\" {
+.\" memset(iocb, 0, sizeof(*iocb));
+.\" iocb->aio_fildes = fd;
+.\" iocb->aio_lio_opcode = IO_CMD_PWRITE;
+.\" iocb->aio_reqprio = 0;
+.\" iocb->u.c.buf = buf;
+.\" iocb->u.c.nbytes = count;
+.\" iocb->u.c.offset = offset;
+.\" }
+.TH io_prep_pwrite 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_prep_pwrite \- Set up iocb for asynchronous writes
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.br
.B #include <libaio.h>
.br
.sp
-.BI "inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset)
-"
+.BI "inline void io_prep_pwrite(struct iocb *" iocb ", int " fd ", void *" buf ", size_t " count ", long long " offset ");"
+.
.sp
struct iocb {
void *data;
};
.fi
.SH DESCRIPTION
-io_prep_write is a convenicence function for setting up parallel writes.
+.BR io_prep_write ()
+is a convenience function for setting up parallel writes.
The first
-.TP
.IR "iocb->u.c.nbytes = count"
bytes of the file for which
-.TP
.IR "iocb->aio_fildes = fd"
is a descriptor are written from the buffer
starting at
-.TP
-.IR "iocb->u.c.buf = buf"
-.
-.br
+.IR "iocb->u.c.buf = buf" .
Writing starts at the absolute position
-.TP
.IR "ioc->u.c.offset = offset"
in the file.
.PP
-This function returns immediately . To schedule the operation, the
+This function returns immediately. To schedule the operation, the
function
-.IR io_submit
+.BR io_submit (3)
must be called.
.PP
Simultaneous asynchronous operations using the same iocb produce
undefined results.
.SH "RETURN VALUES"
-None
+None.
.SH ERRORS
-None
+None.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-.TH io_queue_init 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.TH io_queue_init 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_queue_init \- Initialize asynchronous io state machine
.B #include <libaio.h>
.br
.sp
-.BI "int io_queue_init(int maxevents, io_context_t *ctx );"
+.BI "int io_queue_init(int " maxevents ", io_context_t *" ctx ");"
.sp
.fi
.SH DESCRIPTION
-.B io_queue_init
-Attempts to create an aio context capable of receiving at least
-.IR maxevents
+.BR io_queue_init ()
+attempts to create an aio context capable of receiving at least
+.I maxevents
events.
-.IR ctx
+.I ctx
must point to an aio context that already exists and must be initialized
to
-.IR 0
+.B 0
before the call.
-If the operation is successful, *cxtp is filled with the resulting handle.
+If the operation is successful,
+.I *cxtp
+is filled with the resulting handle.
.SH "RETURN VALUES"
On success,
-.B io_queue_init
-returns 0. Otherwise, -error is return, where
-error is one of the Exxx values defined in the Errors section.
+.BR io_queue_init ()
+returns
+.BR 0 .
+Otherwise, -error is return, where
+error is one of the Exxx values defined in the
+.B ERRORS
+section.
.SH ERRORS
.TP
.B EFAULT
.TP
.B EINVAL
.I maxevents
-is <= 0 or
+is <=
+.B 0
+or
.IR ctx
-is an invalid memory locattion.
+is an invalid memory location.
.TP
.B ENOSYS
-Not implemented
+Not implemented.
.TP
.B EAGAIN
.IR "maxevents > max_aio_reqs"
-where max_aio_reqs is a tunable value.
+where
+.I max_aio_reqs
+is a tunable value.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-.TH io_queue_release 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.TH io_queue_release 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_queue_release \- Release the context associated with the userspace handle
.SH SYNOPSIS
.B #include <libaio.h>
.br
.sp
-.BI "int io_queue_release(io_context_t ctx)"
+.BI "int io_queue_release(io_context_t " ctx ");"
.sp
.SH DESCRIPTION
.B io_queue_release
-destroys the context associated with the userspace handle. May cancel any outstanding
+destroys the context associated with the userspace handle. May cancel any outstanding
AIOs and block on completion.
-
-.B cts.
+.
.SH "RETURN VALUES"
On success,
-.B io_queue_release
-returns 0. Otherwise, -error is return, where
+.BR io_queue_release ()
+returns
+.BR 0 .
+Otherwise, -error is return, where
error is one of the Exxx values defined in the Errors section.
.SH ERRORS
.TP
.B EINVAL
.I ctx
-refers to an unitialized aio context, the iocb pointed to by
+refers to an uninitialized aio context, the
+.I iocb
+pointed to by
.I iocbs
-contains an improperly initialized iocb,
+contains an improperly initialized
+.IR iocb .
.TP
.B ENOSYS
-Not implemented
+Not implemented.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_run(3),
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_run (3),
.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
-
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-.TH io_queue_run 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.TH io_queue_run 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_queue_run \- Handle completed io requests
.SH SYNOPSIS
.B #include <libaio.h>
.br
.sp
-.BI "int io_queue_run(io_context_t ctx );"
+.BI "int io_queue_run(io_context_t " ctx ");"
.sp
.fi
.SH DESCRIPTION
-.B io_queue_run
-Attempts to read all the events events from
-the completion queue for the aio_context specified by ctx_id.
+.BR io_queue_run ()
+attempts to read all the events from
+the completion queue for the aio_context specified by
+.IR ctx .
.SH "RETURN VALUES"
May return
-0 if no events are available.
-Will fail with -ENOSYS if not implemented.
+.B 0
+if no events are available.
+Will fail with -\fBENOSYS\fP if not implemented.
.SH ERRORS
.TP
.B EFAULT
.TP
.B EINVAL
.I ctx
-refers to an unitialized aio context, the iocb pointed to by
+refers to an uninitialized aio context, the
+.I iocb
+pointed to by
.I iocbs
-contains an improperly initialized iocb,
+contains an improperly initialized iocb.
.TP
.B ENOSYS
-Not implemented
+Not implemented.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-.TH io_queue_wait 2 2002-09-03 "Linux 2.4" "Linux AIO"
+.TH io_queue_wait 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_queue_wait \- Wait for io requests to complete
.SH SYNOPSIS
.B #include <libaio.h>
.br
.sp
-.BI "int io_queue_wait(io_context_t ctx, const struct timespec *timeout);"
+.BI "int io_queue_wait(io_context_t " ctx ", const struct timespec *" timeout ");"
.fi
.SH DESCRIPTION
-Attempts to read an event from
-the completion queue for the aio_context specified by ctx_id.
+.BR io_queue_wait ()
+attempts to read an event from
+the completion queue for the aio_context specified by
+.IR ctx .
.SH "RETURN VALUES"
May return
-0 if no events are available and the timeout specified
+.B 0
+if no events are available and the timeout specified
by when has elapsed, where when == NULL specifies an infinite
-timeout. Note that the timeout pointed to by when is relative and
+\fItimeout\fP. Note that the \fItimeout\fP pointed to by when is relative and
will be updated if not NULL and the operation blocks. Will fail
-with -ENOSYS if not implemented.
+with -\fBENOSYS\fP if not implemented.
.SH "RETURN VALUES"
On success,
-.B io_queue_wait
-returns 0. Otherwise, -error is return, where
+.BR io_queue_wait ()
+returns
+.BR 0 .
+Otherwise, -error is return, where
error is one of the Exxx values defined in the Errors section.
.SH ERRORS
.TP
.TP
.B EINVAL
.I ctx
-refers to an unitialized aio context, the iocb pointed to by
+refers to an uninitialized aio context, the
+.I iocb
+pointed to by
.I iocbs
-contains an improperly initialized iocb,
+contains an improperly initialized iocb.
.TP
.B ENOSYS
-Not implemented
+Not implemented.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_set_callback(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_set_callback (3),
+.BR io_submit (3),
+.BR errno (3).
-./"\ 3static inline void io_set_callback(struct iocb *iocb, io_callback_t cb)
-.TH io_set_callback 3 2002-09-12 "Linux 2.4" Linux AIO"
+.\"static inline void io_set_callback(struct iocb *iocb, io_callback_t cb)
+.TH io_set_callback 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_set_callback \- Set up io completion callback function
-.SH SYNOPSYS
+.SH SYNOPSIS
.nf
.B #include <errno.h>
.br
.B #include <libaio.h>
.br
.sp
-.BI "static inline void io_set_callback(struct iocb *iocb, io_callback_t cb)"
+.BI "static inline void io_set_callback(struct iocb *" iocb ", io_callback_t " cb ");"
.sp
struct iocb {
void *data;
.fi
.SH DESCRIPTION
The callback is not done if the caller uses raw events from
-io_getevents, only with the library helpers
+.BR io_getevents (3),
+only with the library helpers.
.SH "RETURN VALUES"
+None.
.SH ERRORS
+None.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_submit(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_submit (3),
+.BR errno (3).
-./"/* sys_io_submit:
-./" * Queue the nr iocbs pointed to by iocbpp for processing. Returns
-./" * the number of iocbs queued. May return -EINVAL if the aio_context
-./" * specified by ctx_id is invalid, if nr is < 0, if the iocb at
-./" * *iocbpp[0] is not properly initialized, if the operation specified
-./" * is invalid for the file descriptor in the iocb. May fail with
-./" * -EFAULT if any of the data structures point to invalid data. May
-./" * fail with -EBADF if the file descriptor specified in the first
-./" * iocb is invalid. May fail with -EAGAIN if insufficient resources
-./" * are available to queue any iocbs. Will return 0 if nr is 0. Will
-./" * fail with -ENOSYS if not implemented.
-./" */
-.TH io_submit 2 2002-09-02 "Linux 2.4" "Linux AIO"
+.\"/* sys_io_submit:
+.\" * Queue the nr iocbs pointed to by iocbpp for processing. Returns
+.\" * the number of iocbs queued. May return -EINVAL if the aio_context
+.\" * specified by ctx is invalid, if nr is < 0, if the iocb at
+.\" * *iocbpp[0] is not properly initialized, if the operation specified
+.\" * is invalid for the file descriptor in the iocb. May fail with
+.\" * -EFAULT if any of the data structures point to invalid data. May
+.\" * fail with -EBADF if the file descriptor specified in the first
+.\" * iocb is invalid. May fail with -EAGAIN if insufficient resources
+.\" * are available to queue any iocbs. Will return 0 if nr is 0. Will
+.\" * fail with -ENOSYS if not implemented.
+.\" */
+.TH io_submit 3 2019-07-23 "Linux" "Linux AIO"
.SH NAME
io_submit \- Submit io requests
.SH SYNOPSIS
};
.fi
.SH DESCRIPTION
-.B io_submit
+.BR io_submit ()
submits
.I nr
iocbs for processing for a given io context ctx.
The
-.IR "io_submit"
+.BR io_submit ()
function can be used to enqueue an arbitrary
number of read and write requests at one time. The requests can all be
meant for the same file, all for different files or every solution in
between.
-.IR "io_submit"
+.BR io_submit ()
gets the
-.IR "nr"
-requests from the array pointed to
-by
-.IR "iocbs"
-. The operation to be performed is determined by the
+.I nr
+requests from the array pointed to by
+.IR "iocbs" .
+The operation to be performed is determined by the
.IR "aio_lio_opcode"
member in each element of
-.IR "iocbs"
-. If this
-field is
+.IR "iocbs" .
+If this field is
.B "IO_CMD_PREAD"
-a read operation is enqueued, similar to a call
-of
+a read operation is enqueued, similar to a call of
.IR "io_prep_pread"
for this element of the array (except that the way
the termination is signalled is different, as we will see below). If
.IR "iocbs"
is simply ignored. This
``operation'' is useful in situations where one has a fixed array of
-.IR "struct iocb"
+.B struct iocb
elements from which only a few need to be handled at
a time. Another situation is where the
-.IR "io_submit"
+.BR io_submit (3)
call was
canceled before all requests are processed and the remaining requests have to be reissued.
.IR "iocbs"
must have values suitable for the operation as described in
the documentation for
-.IR "io_prep_pread"
+.BR io_prep_pread (3)
and
-.IR "io_prep_pwrite"
+.BR io_prep_pwrite (3)
above.
The function returns immediately after
having enqueued all the requests.
On success,
-.B io_submit
+.BR io_submit ()
returns the number of iocbs submitted successfully. Otherwise, -error is return, where
error is one of the Exxx values defined in the Errors section.
.PP
.TP
.B EINVAL
.I ctx
-refers to an unitialized aio context, the iocb pointed to by
+refers to an uninitialized aio context, the iocb pointed to by
.I iocbs
contains an improperly initialized iocb,
.TP
.B EBADF
-The iocb contains a file descriptor that does not exist.
+The
+.I iocb
+contains a file descriptor that does not exist.
.TP
.B EINVAL
-The file specified in the iocb does not support the given io operation.
+The file specified in the
+.I iocb
+does not support the given io operation.
.SH "SEE ALSO"
-.BR io(3),
-.BR io_cancel(3),
-.BR io_fsync(3),
-.BR io_getevents(3),
-.BR io_prep_fsync(3),
-.BR io_prep_pread(3),
-.BR io_prep_pwrite(3),
-.BR io_queue_init(3),
-.BR io_queue_release(3),
-.BR io_queue_run(3),
-.BR io_queue_wait(3),
-.BR io_set_callback(3),
-.BR errno(3)
+.BR io (3),
+.BR io_cancel (3),
+.BR io_fsync (3),
+.BR io_getevents (3),
+.BR io_prep_fsync (3),
+.BR io_prep_pread (3),
+.BR io_prep_pwrite (3),
+.BR io_queue_init (3),
+.BR io_queue_release (3),
+.BR io_queue_run (3),
+.BR io_queue_wait (3),
+.BR io_set_callback (3),
+.BR errno (3).
soname=libaio.so.1
minor=0
-micro=1
+micro=2
libname=$(soname).$(minor).$(micro)
all_targets += libaio.a
$(RANLIB) libaio.a
$(libname): $(libaio_sobjs) libaio.map
+ $(CC) $(CFLAGS) -c struct_offsets.c
$(CC) $(SO_CFLAGS) -Wl,--version-script=libaio.map -Wl,-soname=$(soname) -o $@ $(libaio_sobjs) $(LINK_FLAGS)
install: $(all_targets)
/* ABI change. Provide backwards compatibility for this one. */
SYMVER(compat0_1_io_getevents, io_getevents, 0.1);
-int compat0_1_io_getevents(io_context_t ctx_id, long nr,
+int compat0_1_io_getevents(io_context_t ctx, long nr,
struct io_event *events,
const struct timespec *const_timeout)
{
struct timespec timeout;
if (const_timeout)
timeout = *const_timeout;
- return io_getevents(ctx_id, 1, nr, events,
+ return io_getevents(ctx, 1, nr, events,
const_timeout ? &timeout : NULL);
}
/* little endian, 32 bits */
#if defined(__i386__) || (defined(__arm__) && !defined(__ARMEB__)) || \
defined(__sh__) || defined(__bfin__) || defined(__MIPSEL__) || \
- defined(__cris__) || (defined(__riscv) && __riscv_xlen == 32) || \
+ defined(__cris__) || defined(__loongarch32) || \
+ (defined(__riscv) && __riscv_xlen == 32) || \
(defined(__GNUC__) && defined(__BYTE_ORDER__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_LONG__ == 4)
#define PADDED(x, y) x; unsigned y
/* little endian, 64 bits */
#elif defined(__ia64__) || defined(__x86_64__) || defined(__alpha__) || \
(defined(__aarch64__) && defined(__AARCH64EL__)) || \
+ defined(__loongarch64) || \
(defined(__riscv) && __riscv_xlen == 64) || \
(defined(__GNUC__) && defined(__BYTE_ORDER__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_LONG__ == 8)
}; /* result code is the set of result flags or -'ve errno */
struct io_iocb_sockaddr {
- struct sockaddr *addr;
- int len;
+ PADDEDptr(struct sockaddr *addr, __pad1);
+ PADDEDul(len, __pad2);
}; /* result code is the length of the sockaddr, or -'ve errno */
struct io_iocb_common {
}; /* result code is the amount read or -'ve errno */
struct io_iocb_vector {
- const struct iovec *vec;
- int nr;
+ PADDEDptr(const struct iovec *vec, __pad1);
+ PADDEDul(nr, __pad2);
long long offset;
}; /* result code is the amount read or -'ve errno */
extern int io_destroy(io_context_t ctx);
extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]);
extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt);
-extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
-extern int io_pgetevents(io_context_t ctx_id, long min_nr, long nr,
+extern int io_getevents(io_context_t ctx, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
+extern int io_pgetevents(io_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout,
sigset_t *sigmask);
--- /dev/null
+/*
+ * Ensure that data structure offsets in the iocb.u union match.
+ * Note that this code does not end up in the compiled object files.
+ * Its sole purpose is to abort the build if the structure padding
+ * is incorrect.
+ */
+#include <stddef.h>
+#include <assert.h>
+#include <libaio.h>
+
+void
+offset_check(void)
+{
+ static_assert(offsetof(struct iocb, u.v.nr) ==
+ offsetof(struct iocb, u.c.nbytes),
+ "Error: iocb.u.v.nr does not match the offset of iocb.u.c.nbytes.");
+ static_assert(offsetof(struct iocb, u.v.offset) ==
+ offsetof(struct iocb, u.c.offset),
+ "Error: iocb.u.v.offset does not match the offset of iocb.u.c.offset");
+ static_assert(offsetof(struct iocb, u.saddr.len) ==
+ offsetof(struct iocb, u.c.nbytes),
+ "Error: iocb.u.saddr.len does not match the offset of iocb.u.c.nbytes");
+}
#include "syscall-arm.h"
#elif defined(__sparc__)
#include "syscall-sparc.h"
-#elif defined(__aarch64__) || defined(__riscv)
+#elif defined(__aarch64__) || defined(__loongarch__) || defined(__riscv)
#include "syscall-generic.h"
#else
#warning "using system call numbers from sys/syscall.h"
extern int vsys_io_submit(io_context_t ctx, long nr, struct iocb *iocbs[]);
extern int vsys_io_cancel(io_context_t ctx, struct iocb *iocb);
extern int vsys_io_wait(io_context_t ctx, struct iocb *iocb, const struct timespec *when);
-extern int vsys_io_getevents(io_context_t ctx_id, long nr, struct io_event *events, const struct timespec *timeout);
+extern int vsys_io_getevents(io_context_t ctx, long nr, struct io_event *events, const struct timespec *timeout);