From e8cef249cc1278d248a2e2081683ad4bcc9465ac Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 4 Oct 2014 17:30:24 -0600 Subject: [PATCH] Initial implementation of aio_write() --- include/aio.h | 2 +- include/fcntl.h | 2 +- libc/Kconfig | 2 +- libc/aio/Make.defs | 2 +- libc/aio/aio_read.c | 4 +- libc/aio/aio_write.c | 299 ++++++++++++++++++++++++++++++++++++++++++ libc/aio/lio_listio.c | 2 +- 7 files changed, 306 insertions(+), 7 deletions(-) create mode 100644 libc/aio/aio_write.c diff --git a/include/aio.h b/include/aio.h index 32e9d1b290..449ce79594 100644 --- a/include/aio.h +++ b/include/aio.h @@ -135,7 +135,7 @@ struct aiocb struct work_s aio_work; /* Used to defer I/O to the work thread */ pid_t aio_pid; /* ID of client to be notify at completion */ - ssize_t aio_result; /* Support aio_error() and aio_return() */ + volatile ssize_t aio_result; /* Support for aio_error() and aio_return() */ }; /**************************************************************************** diff --git a/include/fcntl.h b/include/fcntl.h index 7671c0aca0..6bec04f0ac 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -69,7 +69,7 @@ /* Unsupported, but required open flags */ #define O_RSYNC 0 /* Synchronize input on read */ -#define O_ACCMODE 0 /* Required by POSIX */ +#define O_ACCMODE O_RDWR /* Mask for access mode */ #define O_NOCTTY 0 /* Required by POSIX */ #define O_TEXT 0 /* Open the file in text (translated) mode. */ diff --git a/libc/Kconfig b/libc/Kconfig index e425a48d54..32eb7464c1 100644 --- a/libc/Kconfig +++ b/libc/Kconfig @@ -460,7 +460,7 @@ if SCHED_LPWORK config SCHED_LPWORKPRIORITY int "Low priority worker thread priority" - default 50 + default 100 ---help--- The execution priority of the lopwer priority worker thread. Default: 192 diff --git a/libc/aio/Make.defs b/libc/aio/Make.defs index 0ad5bbb475..ee7e35916b 100644 --- a/libc/aio/Make.defs +++ b/libc/aio/Make.defs @@ -37,7 +37,7 @@ ifeq ($(CONFIG_LIBC_AIO),y) # Add the asynchronous I/O C files to the build -CSRCS += aio_read.c +CSRCS += aio_read.c aio_write.c ifneq ($(CONFIG_PTHREAD_DISABLE),y) CSRCS += lio_listio.c diff --git a/libc/aio/aio_read.c b/libc/aio/aio_read.c index 5ae81ff8fb..49d5823bfd 100644 --- a/libc/aio/aio_read.c +++ b/libc/aio/aio_read.c @@ -159,7 +159,7 @@ static void aio_read_worker(FAR void *arg) * operation, the value of the file offset for the file is unspecified. * * The aiocbp->aio_lio_opcode field will be ignored by aio_read(). - * + * * The aiocbp argument points to an aiocb structure. If the buffer pointed * to by aiocbp->aio_buf or the control block pointed to by aiocbp becomes * an illegal address prior to asynchronous I/O completion, then the @@ -168,7 +168,7 @@ static void aio_read_worker(FAR void *arg) * Simultaneous asynchronous operations using the same aiocbp produce * undefined results. * - * For any system action that changes the process memory space while an + * For any system action that changes the process memory space while an * synchronous I/O is outstanding to the address range being changed, the * result of that action is undefined. * diff --git a/libc/aio/aio_write.c b/libc/aio/aio_write.c new file mode 100644 index 0000000000..b8826afb94 --- /dev/null +++ b/libc/aio/aio_write.c @@ -0,0 +1,299 @@ +/**************************************************************************** + * libc/aio/aio_write.c + * + * Copyright (C) 2014 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include "lib_internal.h" +#include "aio/aio.h" + +#ifndef CONFIG_LIBC_AIO + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +/**************************************************************************** + * Public Variables + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: aio_write_worker + * + * Description: + * This function executes on the worker thread and performs the + * asynchronous I/O operation. + * + * Input Parameters: + * arg - Worker argument. In this case, a pointer to an instance of + * struct aiocb cast to void *. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void aio_write_worker(FAR void *arg) +{ + FAR struct aiocb *aiocbp = (FAR struct aiocb *)arg; + DEBASSERT(arg); + ssize_t nwritten; + int oflags; + + /* Call fcntl(F_GETFL) to get the file open mode. + * + * REVISIT: Consider moving aio_write into the kernel. Notice that in a + * system using system calls, up to three system calls may be required: + * (1) fcntl, (2) write or pwrite, and possibly (3) sigueue(). If aio_write + * were a system call, then only one would be required. + */ + + oflags = fcntl((aiocbp->aio_fildes, F_GETFL, ...) + if (oflags < 0) + { + int errcode = get_errno(); + fdbg("ERROR: fcntl failed: %d\n", errode); + aicbp->result = -errcode; + } + else + { + /* Perform the write using: + * + * aio_fildes - File descriptor + * aio_buf - Location of buffer + * aio_nbytes - Length of transfer + * aio_offset - File offset + */ + + /* Check if O_APPEND is set in the file open flags */ + + if ((oflags & O_APPEND) != 0) + { + /* Append to the current file position */ + + nwritten = write(aiocbp->aio_fildes, aiocbp->aio_buf, + aiocbp->aio_nbytes); + } + else + { + nwritten = pwrite(aiocbp->aio_fildes, aiocbp->aio_buf, + aiocbp->aio_nbytes, aiocbp->aio_offset); + } + + /* Set the result of the write */ + + if (nwritten < 0) + { + int errcode = get_errno(); + fdbg("ERROR: write/pwrite failed: %d\n", errode); + DEBUGASSERT(errcode > 0); + aicbp->result = -errcode; + } + else + { + aicbp->result = nwritten; + } + } + + /* Signal the client */ + + if (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL) + { + int ret; +#ifdef CONFIG_CAN_PASS_STRUCTS + ret = sigqueue(aiocbp->aio_pid, aiocbp->aio_sigevent.sigev_signo, + aiocbp->aio_sigevent.sigev_value); +#else + ret = sigqueue(aiocbp->aio_pid, aiocbp->aio_sigevent.sigev_sign, + aiocbp->aio_sigevent.sigev_value.sival_ptr); +#endif + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: aio_write + * + * Description: + * The aio_write() function writes aiocbp->aio_nbytes to the file + * associated with aiocbp->aio_fildes from the buffer pointed to by + * aiocbp->aio_buf. The function call will return when the write request + * has been initiated or queued to the file or device (even when the data + * cannot be delivered immediately). + * + * The aiocbp value may be used as an argument to aio_error() and + * aio_return() in order to determine the error status and return status, + * respectively, of the asynchronous operation while it is proceeding. + * + * The aiocbp argument points to an aiocb structure. If the buffer pointed + * to by aiocbp->aio_buf or the control block pointed to by aiocbp becomes + * an illegal address prior to asynchronous I/O completion, then the + * behavior is undefined. + * + * If O_APPEND is not set for the file descriptor aio_fildes, then the + * requested operation will take place at the absolute position in the file + * as given by aio_offset, as if lseek() were called immediately prior to the + * operation with an offset equal to aio_offset and a whence equal to SEEK_SET. + * If O_APPEND is set for the file descriptor, write operations append to the + * file in the same order as the calls were made. After a successful call to + * enqueue an asynchronous I/O operation, the value of the file offset for the + * file is unspecified. + * + * The aiocbp->aio_lio_opcode field will be ignored by aio_write(). + * + * Simultaneous asynchronous operations using the same aiocbp produce + * undefined results. + * + * For any system action that changes the process memory space while an + * synchronous I/O is outstanding to the address range being changed, the + * result of that action is undefined. + * + * Input Parameters: + * aiocbp - A pointer to an instance of struct aiocb + * + * Returned Value: + * + * The aio_write() function will return the value zero if the I/O operation + * is successfully queued; otherwise, the function will return the value + * -1 and set errno to indicate the error. The aio_write() function will + * ail if: + * + * EAGAIN - The requested asynchronous I/O operation was not queued due to + * system resource limitations. + * + * Each of the following conditions may be detected synchronously at the + * time of the call to aio_write(), or asynchronously. If any of the + * conditions below are detected synchronously, the aio_write() function + * will return -1 and set errno to the corresponding value. If any of the + * conditions below are detected asynchronously, the return status of the + * asynchronous operation is set to -1, and the error status of the + * asynchronous operation is set to the corresponding value. + * + * EBADF - The aiocbp->aio_fildes argument is not a valid file descriptor + * open for writing. + * EINVAL - The file offset value implied by aiocbp->aio_offset would be + * invalid, aiocbp->aio_reqprio is not a valid value, or + * aiocbp->aio_nbytes is an invalid value. + * + * In the case that the aio_write() successfully queues the I/O operation + * but the operation is subsequently cancelled or encounters an error, the + * return status of the asynchronous operation is one of the values + * normally returned by the write() function call. In addition, the error + * status of the asynchronous operation is set to one of the error + * statuses normally set by the write() function call, or one of the + * following values: + * + * EBADF - The aiocbp->aio_fildes argument is not a valid file descriptor + * open for writing. + * EINVAL - The file offset value implied by aiocbp->aio_offset would be + * invalid. + * ECANCELED - The requested I/O was cancelled before the I/O completed + * due to an explicit aio_cancel() request. + * + * The following condition may be detected synchronously or asynchronously: + * + * EFBIG - The file is a regular file, aiobcp->aio_nbytes is greater + * than 0, and the starting offset in aiobcp->aio_offset is at or + * beyond the offset maximum in the open file description associated + * with aiocbp->aio_fildes. + * + * POSIX Compliance: + * - The standard requires that if prioritized I/O is supported for this + * file, then the asynchronous operation will be submitted at a priority + * equal to a base scheduling priority minus aiocbp->aio_reqprio. If + * Thwrite Execution Scheduling is not supported, then the base scheduling + * priority is that of the calling thread. + * + * This implementation uses the NuttX work queues that run at a fixed, + * configured priority. + * + * - Most errors required in the standard are not detected at this point. + * There are no pre-queuing checks for the validity of the operation. + * + ****************************************************************************/ + +int aio_write(FAR struct aiocb *aiocbp); +{ + int ret; + + DEBUGASSERT(aiocbp); + + /* The result -EBUSY means that the transfer has not yet completed */ + + aiocbp->aio_result = -EBUSY; + + /* Save the ID of the calling, client thread */ + + aiocbp->aio_pid = getpid(); + + /* Defer the work to the worker thread */ + + ret = work_queue(AIO_QUEUE, &aiocbp->aio_work, aio_write_worker, aiocbp, 0); + if (ret < 0) + { + aio->aio_result = ret; + set_errno(ret); + return ERROR; + } + + return OK; +} + +#endif /* CONFIG_LIBC_AIO */ diff --git a/libc/aio/lio_listio.c b/libc/aio/lio_listio.c index 2a817c8aa5..c5f6e424cc 100644 --- a/libc/aio/lio_listio.c +++ b/libc/aio/lio_listio.c @@ -164,7 +164,7 @@ static pthread_addr_t lio_thread(pthread_addr_t arg) * * If the buffer pointed to by 'list' or the aiocb structures pointed to * by the elements of the array 'list' become illegal addresses before all - * asynchronous I/O completed and, if necessary, the notification is + * asynchronous I/O completed and, if necessary, the notification is * sent, then the behavior is undefined. If the buffers pointed to by the * aio_buf member of the aiocb structure pointed to by the elements of * the array 'list' become illegal addresses prior to the asynchronous