diff --git a/fs/aio/Kconfig b/fs/aio/Kconfig index d4089bc83f..b11e6c49fd 100644 --- a/fs/aio/Kconfig +++ b/fs/aio/Kconfig @@ -12,4 +12,23 @@ config FS_AIO interfaces declared in include/aio.h. if FS_AIO + +config FS_NAIOC + int "Pre-allocated AIO containers" + default 8 + ---help--- + The AIO containers hold an AIO control block and appends information + needed by the logic running within the RTOS. These structures are + pre-allocated, the number pre-allocated controlled by this setting. + + This setting controls the number of asynchronous I/O operations that + can be queued at one time. When this count is exhausted, the caller + of aio_read(), aio_write(), or aio_fsync() will be forced to wait + for an available container. That wait is minimized because each + container is released prior to starting the next I/O. + + The AIO logic includes priority inheritance logic to prevent + priority inversion problems: The priority of the low-priority work + queue will be boosted, if necessary, to level of the waiting thread. + endif diff --git a/fs/aio/Make.defs b/fs/aio/Make.defs index 194b70cf22..b9855bcb45 100644 --- a/fs/aio/Make.defs +++ b/fs/aio/Make.defs @@ -1,5 +1,5 @@ ############################################################################ -# libc/fs/Make.defs +# fs/aio/Make.defs # # Copyright (C) 2014 Gregory Nutt. All rights reserved. # Author: Gregory Nutt @@ -37,7 +37,8 @@ ifeq ($(CONFIG_FS_AIO),y) # Add the asynchronous I/O C files to the build -CSRCS += aio_cancel.c aio_fsync.c aio_read.c aio_signal.c aio_write.c +CSRCS += aio_cancel.c aio_fsync.c aio_initialize.c aio_read.c aio_signal.c +CSRCS += aio_write.c # Add the asynchronous I/O directory to the build diff --git a/fs/aio/aio.h b/fs/aio/aio.h index a7a1791716..0716b09bcf 100644 --- a/fs/aio/aio.h +++ b/fs/aio/aio.h @@ -42,19 +42,42 @@ #include +#include #include +#include + #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Configuration ************************************************************/ + +/* Number of pre-allocated AIO Control block containers */ + +#ifndef CONFIG_FS_NAIOC +# define CONFIG_FS_NAIOC 8 +#endif /**************************************************************************** * Public Types ****************************************************************************/ +/* This structure contains one AIO control block and appends information + * needed by the logic running on the worker thread. These structures are + * pre-allocated, the number pre-allocated controlled by CONFIG_FS_NAIOC. + */ + +struct aio_container_s +{ + dq_entry_t aioc_link; /* Supports a doubly linked list */ + FAR struct aiocb *aioc_aiocbp; /* The contained AIO control block */ + struct work_s aioc_work; /* Used to defer I/O to the work thread */ + pid_t aioc_pid; /* ID of the waiting task */ + uint8_t aioc_prio; /* Priority of the waiting task */ +}; /**************************************************************************** - * Public Variables + * Public Data ****************************************************************************/ #undef EXTERN @@ -66,10 +89,122 @@ extern "C" #define EXTERN extern #endif +/* This is a list of pending asynchronous I/O. The user must hold the + * lock on this list in order to access the list. + */ + +EXTERN dq_queue_t g_aio_pending; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: aio_initialize + * + * Description: + * Perform one-time initialization of the asynchronous I/O sub-system + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aio_initialize(void); + +/**************************************************************************** + * Name: aio_lock/aio_unlock + * + * Description: + * Take/give the lock on the pending asynchronous I/O list + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aio_lock(void); +void aio_unlock(void); + +/**************************************************************************** + * Name: aioc_alloc + * + * Description: + * Allocate a new AIO container by taking the next, pre-allocated + * container from the free list. This function will wait until + * aioc_free() is called in the event that there is no free container + * available in the free list. + * + * Input Parameters: + * None + * + * Returned Value: + * A reference to the allocated AIO container. This allocation never + * fails because the logic will wait in the event that there is no free + * container. + * + ****************************************************************************/ + +FAR struct aio_container_s *aioc_lock(void); + +/**************************************************************************** + * Name: aioc_free + * + * Description: + * Free an AIO container by returning it to the free list and, perhaps, + * awakening any threads waiting for that resource + * + * Input Parameters: + * aioc - The AIO container to be free + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aioc_free(FAR struct aio_container_s *aioc); + +/**************************************************************************** + * Name: aio_contain + * + * Description: + * Create and initialize a container for the provided AIO control block + * + * Input Parameters: + * aiocbp - The AIO control block pointer + * + * Returned Value: + * A reference to the new AIO control block container. This function + * will not fail but will wait if necessary for the resources to perform + * this operation. + * + ****************************************************************************/ + +FAR struct aio_container_s *aio_contain(FAR struct aiocb *aiocbp); + +/**************************************************************************** + * Name: aioc_decant + * + * Description: + * Remove the AIO control block from the container and free all resources + * used by the container. + * + * Input Parameters: + * aioc - Pointer to the AIO control block container + * + * Returned Value: + * A pointer to the no-longer contained AIO control block. + * + ****************************************************************************/ + +FAR struct aiocb *aioc_decant(FAR struct aio_container_s *aioc); + /**************************************************************************** * Name: aio_signal * @@ -77,6 +212,7 @@ extern "C" * Signal the client that an I/O has completed. * * Input Parameters: + * pid - ID of the task to signal * aiocbp - Pointer to the asynchronous I/O state structure that includes * information about how to signal the client * @@ -86,6 +222,6 @@ extern "C" * ****************************************************************************/ -int aio_signal(FAR struct aiocb *aiocbp); +int aio_signal(pid_t pid, FAR struct aiocb *aiocbp); #endif /* __FS_AIO_AIO_H */ diff --git a/fs/aio/aio_initialize.c b/fs/aio/aio_initialize.c new file mode 100755 index 0000000000..2686a80ed5 --- /dev/null +++ b/fs/aio/aio_initialize.c @@ -0,0 +1,238 @@ +/**************************************************************************** + * fs/aio/aio_initialize.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 "aio/aio.h" + +#ifdef CONFIG_FS_AIO + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is an array of pre-allocated AIO containers */ + +static struct aio_container_s g_aioc_alloc[CONFIG_FS_NAIOC]; + +/* This is a list of free AIO containers */ + +static dq_queue_t g_aioc_free; + +/* This counting semaphore tracks the number of free AIO containers */ + +static sem_t g_aioc_freesem; + +/* This binary semaphore supports exclusive access to the list of pending + * asynchronous I/O. + */ + +static sem_t g_aio_exclsem; + +/**************************************************************************** + * Public Data + ****************************************************************************/ +/* This is a list of pending asynchronous I/O. The user must hold the + * lock on this list in order to access the list. + */ + +dq_queue_t g_aio_pending; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: aio_initialize + * + * Description: + * Perform one-time initialization of the asynchronous I/O sub-system + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aio_initialize(void) +{ + int i; + + /* Initialize counting semaphores */ + + (void)sem_init(&g_aioc_freesem, 0, 0); + (void)sem_init(&g_aio_exclsem, 0, 1); + + /* Initialize the container queues */ + + dq_init(&g_aioc_free); + dq_init(&g_aio_pending); + + /* Add all of the pre-allocated AIO containers to the free list */ + + for (i = 0; i < CONFIG_FS_NAIOC; i++) + { + /* "Free" the entry, adding it to the free list and bumping up the + * semaphore count. + */ + + aioc_free(&g_aioc_alloc[i]); + } +} + +/**************************************************************************** + * Name: aio_lock/aio_unlock + * + * Description: + * Take/give the lock on the pending asynchronous I/O list + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aio_lock(void) +{ + while (sem_wait(&g_aio_exclsem) < 0) + { + DEBUGASSERT(get_errno() == EINTR); + } +} + +void aio_unlock(void) +{ + sem_post(&g_aio_exclsem); +} + +/**************************************************************************** + * Name: aioc_alloc + * + * Description: + * Allocate a new AIO container by taking the next, pre-allocated + * container from the free list. This function will wait until + * aioc_free() is called in the event that there is no free container + * available in the free list. + * + * Input Parameters: + * None + * + * Returned Value: + * A reference to the allocated AIO container. This allocation never + * fails because the logic will wait in the event that there is no free + * container. + * + ****************************************************************************/ + +FAR struct aio_container_s *aioc_lock(void) +{ + FAR struct aio_container_s *aioc; + + /* Take a semaphore, thus guaranteeing that we have an AIO container + * set aside for us. + */ + + while (sem_wait(&g_aioc_freesem) < 0) + { + DEBUGASSERT(get_errno() == EINTR); + } + + /* Get our AIO container */ + + aio_lock(); + aioc = (FAR struct aio_container_s *)dq_remfirst(&g_aioc_free); + aio_unlock(); + + DEBUGASSERT(aioc); + return aioc; +} + +/**************************************************************************** + * Name: aioc_free + * + * Description: + * Free an AIO container by returning it to the free list and, perhaps, + * awakening any threads waiting for that resource + * + * Input Parameters: + * aioc - The AIO container to be free + * + * Returned Value: + * None + * + ****************************************************************************/ + +void aioc_free(FAR struct aio_container_s *aioc) +{ + DEBUGASSERT(aioc); + + /* Return the container to the free list */ + + aio_lock(); + dq_addlast(&aioc->aioc_link, &g_aioc_free); + aio_unlock(); + + /* The post the counting semaphore, announcing the availability of the + * free AIO container. + */ + + sem_post(&g_aioc_freesem); +} + +#endif /* CONFIG_FS_AIO */ diff --git a/fs/aio/aioc_contain.c b/fs/aio/aioc_contain.c new file mode 100644 index 0000000000..e608a86598 --- /dev/null +++ b/fs/aio/aioc_contain.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * libc/aio/aio_contain.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 "aio/aio.h" + +#ifdef CONFIG_FS_AIO + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +/**************************************************************************** + * Name: aio_contain + * + * Description: + * Create and initialize a container for the provided AIO control block + * + * Input Parameters: + * aiocbp - The AIO control block pointer + * + * Returned Value: + * A reference to the new AIO control block container. This function + * will not fail but will wait if necessary for the resources to perform + * this operation. + * + ****************************************************************************/ + +FAR struct aio_container_s *aio_contain(FAR struct aiocb *aiocbp) +{ + FAR struct aio_container_s *aioc; + struct sched_param param; + + /* Allocate the AIO control block container, waiting for one to become + * available if necessary. This should never fail. + */ + + aioc = aioc_alloc(); + DEBUGASSERT(aioc); + + /* Initialize the container */ + + memset(aioc, 0, sizeof(struct aio_container_s)); + aioc->aioc_aiocbp = aiocbp; + aioc->aioc_pid = getpid(); + + DEBUGVERIFY(sched_getparam (aioc->aioc_pid, ¶m)); + aioc->aioc_prio = param.sched_priority; + + /* Add the container to the pending transfer list. */ + + aio_lock(); + dq_addlast(&aioc->aioc_link, &g_aio_pending); + aio_unlock(); + return aioc; +} + +/**************************************************************************** + * Name: aioc_decant + * + * Description: + * Remove the AIO control block from the container and free all resources + * used by the container. + * + * Input Parameters: + * aioc - Pointer to the AIO control block container + * + * Returned Value: + * A pointer to the no-longer contained AIO control block. + * + ****************************************************************************/ + +FAR struct aiocb *aioc_decant(FAR struct aio_container_s *aioc) +{ + FAR struct aiocb *aiocbp; + + DEBUGASSERT(aioc); + + /* Remove the container to the pending transfer list. */ + + aio_lock(); + dq_rem(&aioc->aioc_link, &g_aio_pending); + aio_unlock(); + + /* De-cant the AIO control block and return the container to the free list */ + + aiocbp = aioc->acioc_aiocbp; + aioc_free(aioc); + return aiocbp; +} + +#endif /* CONFIG_FS_AIO */ diff --git a/include/aio.h b/include/aio.h index 55e2ffa58f..3fd37e0f27 100644 --- a/include/aio.h +++ b/include/aio.h @@ -133,8 +133,6 @@ struct aiocb * application code should never reference these elements. */ - 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 */ volatile ssize_t aio_result; /* Support for aio_error() and aio_return() */ FAR void *aio_priv; /* Used by signal handlers */ };