posix/aio: Implemented aio_suspend()

Implemented aio_suspend().
Added test to verify functionality.
This commit is contained in:
alessandronardin
2024-10-18 10:44:20 +02:00
committed by Joel Sherrill
parent bffc250688
commit 9876b5949f
11 changed files with 497 additions and 29 deletions

View File

@@ -269,9 +269,21 @@ int aio_cancel(
);
/**
* @brief Wait for Asynchronous I/O Request - NOT IMPLEMENTED
* @brief Wait for Asynchronous I/O Request
*
* 6.7.7 Wait for Asynchronous I/O Request, P1003.1b-1993, p. 164
*
* @param list Is a pointer to the array of aiocbs.
* @param nent Is the number of aiocbs in the array.
* @param timeout Specifies the timeout time.
*
* @retval 0 One of the operation specified in list completed.
* @retval EINVAL Invalid nent value.
* @retval EAGAIN Could not suspend due to resource limitation.
* @retval ENOMEM Could not suspend due to memory limitation.
* @retval EAGAIN No asynchronous I/O indicated in the list referenced by list
completed in the time interval indicated by timeout.
* @retval EINTR An event interrupted the aio_suspend() function.
*/
int aio_suspend(
const struct aiocb * const list[],

View File

@@ -93,6 +93,11 @@ extern "C" {
/** Notification via event delivery */
#define AIO_LIO_EVENT 2
/* Constants needed by aio_suspend() */
/** Signal generated for suspend call */
#define AIO_SIGNALED 1
/**
* @brief holds a pointer to a sigevent struct or a thread id
*
@@ -125,6 +130,24 @@ typedef struct
} listcb;
/**
* @brief Control block for every list involved in a aio_suspend() call.
*/
typedef struct
{
pthread_mutex_t mutex;
/** @brief number of requests left to complete the list */
int requests_left;
/** @brief id of the thread that called aio_suspend() */
int task_id;
/** @brief controls if the notification already happend */
int notified;
} rtems_aio_suspendcb;
/**
* @brief The request being processed
*/
@@ -145,6 +168,9 @@ typedef struct
/** @brief pointer to list control block */
listcb *listcbp;
/** @brief pointer to suspend control block */
rtems_aio_suspendcb *suspendcbp;
/** @brief Aio control block */
struct aiocb *aiocbp;
@@ -311,10 +337,29 @@ rtems_aio_request *init_read_req( struct aiocb* aiocbp );
/**
* @brief updates listcb after op completion
*
* @param listcbp
* @param listcbp a pointer to the list control block.
*/
void rtems_aio_completed_list_op( listcb *listcbp );
/**
* @brief updates suspendcb after related op completion
*
* @param suspendcbp a pointer to the suspend control block.
*/
void rtems_aio_update_suspendcbp( rtems_aio_suspendcb *suspendcbp );
/**
* @brief Search a request in an fd chain.
*
* @param aiocbp
* @retval NULL The request identified by aiocbp is not present in fd_chain.
* @return A pointer to the rtems_aio_request referenced by aiocbp.
*/
rtems_aio_request * rtems_aio_search_in_chain(
const struct aiocb* aiocbp,
rtems_chain_control *fd_chain
);
#ifdef RTEMS_DEBUG
#include <assert.h>

View File

@@ -435,6 +435,23 @@ extern "C" {
*/
typedef uint32_t rtems_event_set;
/* Generated from spec:/rtems/event/if/system-aio-suspension-terminated */
/**
* @brief This event set constant represents the reserved system event that is
* internally used by aio_suspend to notify of suspension termination.
*
* @par Constraints
* @parblock
* The following constraints apply to this constant:
*
* * The constant is not included in the pre-qualified feature set of RTEMS.
* Applications which are restricted to only use interfaces of the
* pre-qualified feature set of RTEMS shall not use the constant.
* @endparblock
*/
#define RTEMS_EVENT_SYSTEM_AIO_SUSPENSION_TERMINATED RTEMS_EVENT_27
/* Generated from spec:/rtems/event/if/system-lio-list-completed */
/**

View File

@@ -276,12 +276,50 @@ void rtems_aio_completed_list_op( listcb *listcbp )
break;
}
pthread_mutex_unlock( &listcbp->mutex );
pthread_mutex_destroy( &listcbp->mutex );
free( listcbp );
} else {
pthread_mutex_unlock( &listcbp->mutex );
}
}
void rtems_aio_update_suspendcbp( rtems_aio_suspendcb *suspendcbp )
{
int send_event = 0;
int finished = 0;
rtems_id id;
if ( suspendcbp == NULL )
return;
pthread_mutex_lock( &suspendcbp->mutex );
id = suspendcbp->task_id;
if ( --suspendcbp->requests_left == 0 ) {
finished = 1;
}
if ( suspendcbp->notified == !AIO_SIGNALED ) {
send_event = 1;
suspendcbp->notified = AIO_SIGNALED;
}
pthread_mutex_unlock( &suspendcbp->mutex );
if ( send_event ) {
rtems_event_system_send(
id,
RTEMS_EVENT_SYSTEM_AIO_SUSPENSION_TERMINATED
);
}
if( finished ) {
pthread_mutex_destroy( &suspendcbp->mutex );
free( suspendcbp );
}
}
rtems_aio_request_chain *rtems_aio_search_fd(
rtems_chain_control *chain,
int fildes,
@@ -393,28 +431,22 @@ int rtems_aio_remove_req( rtems_chain_control *chain, struct aiocb *aiocbp )
{
if ( rtems_chain_is_empty( chain ) )
return AIO_ALLDONE;
rtems_chain_node *node = rtems_chain_first( chain );
rtems_aio_request *current;
current = (rtems_aio_request *) node;
while ( !rtems_chain_is_tail( chain, node ) && current->aiocbp != aiocbp ) {
node = rtems_chain_next( node );
current = (rtems_aio_request *) node;
}
if ( rtems_chain_is_tail( chain, node ) )
rtems_aio_request *request = rtems_aio_search_in_chain( aiocbp, chain );
if ( request == NULL ) {
return AIO_NOTCANCELED;
else {
rtems_chain_extract( node );
current->aiocbp->error_code = ECANCELED;
current->aiocbp->return_value = -1;
rtems_aio_completed_list_op( current->listcbp );
atomic_fetch_sub( &aio_request_queue.queued_requests, 1 );
free( current );
}
rtems_chain_node *node = (rtems_chain_node *) request;
rtems_chain_extract( node );
request->aiocbp->error_code = ECANCELED;
request->aiocbp->return_value = -1;
rtems_aio_completed_list_op( request->listcbp );
rtems_aio_update_suspendcbp( request->suspendcbp );
atomic_fetch_sub( &aio_request_queue.queued_requests, 1 );
free( request );
return AIO_CANCELED;
}
@@ -665,7 +697,12 @@ static void *rtems_aio_handle( void *arg )
/* notification for list completion */
rtems_aio_completed_list_op( req->listcbp );
/* notification for aio_suspend() */
rtems_aio_update_suspendcbp( req->suspendcbp );
req->listcbp = NULL;
req->suspendcbp = NULL;
} else {
/* If the fd chain is empty we unlock the fd chain and we lock
@@ -821,3 +858,25 @@ static void rtems_aio_handle_helper( rtems_aio_request *req )
}
}
rtems_aio_request * rtems_aio_search_in_chain(
const struct aiocb* aiocbp,
rtems_chain_control *fd_chain
)
{
rtems_aio_request *current;
rtems_chain_node *node;
node = rtems_chain_first( fd_chain );
current = (rtems_aio_request *) node;
while ( !rtems_chain_is_tail( fd_chain, node ) && current->aiocbp != aiocbp ) {
node = rtems_chain_next( node );
current = (rtems_aio_request *) node;
}
if ( rtems_chain_is_tail( fd_chain, node ) ) {
return NULL;
}
return current;
}

View File

@@ -9,6 +9,8 @@
*/
/*
* Copyright 2024, Alessandro Nardin <ale.daluch@gmail.com>
*
* COPYRIGHT (c) 1989-2007.
* On-Line Applications Research Corporation (OAR).
*
@@ -40,16 +42,140 @@
#include <aio.h>
#include <errno.h>
#include <pthread.h>
#include <rtems/posix/aio_misc.h>
#include <stdlib.h>
#include <rtems/score/basedefs.h>
#include <rtems/seterr.h>
#include <rtems/timespec.h>
int aio_suspend(
const struct aiocb * const list[] RTEMS_UNUSED,
int nent RTEMS_UNUSED,
const struct timespec *timeout RTEMS_UNUSED
const struct aiocb * const list[],
int nent,
const struct timespec *timeout
)
{
rtems_set_errno_and_return_minus_one( ENOSYS );
rtems_chain_control *idle_req_chain = &aio_request_queue.idle_req;
rtems_chain_control *work_req_chain = &aio_request_queue.work_req;
rtems_aio_suspendcb *suspendcbp;
rtems_aio_request_chain *r_chain;
rtems_aio_request *request;
rtems_event_set event_out;
int result, op_num, i;
/* Controls over invalid parameters */
if ( list == NULL ){
rtems_set_errno_and_return_minus_one( EINVAL );
}
if ( nent <= 0 ) {
rtems_set_errno_and_return_minus_one( EINVAL );
}
/* Initialize suspendcb */
suspendcbp = malloc( sizeof( rtems_aio_suspendcb ) );
if ( suspendcbp == NULL ) {
rtems_set_errno_and_return_minus_one( ENOMEM );
}
result = pthread_mutex_init( &suspendcbp->mutex, NULL );
if ( result != 0 ) {
free( suspendcbp );
if ( errno == ENOMEM ) {
rtems_set_errno_and_return_minus_one( ENOMEM );
}
rtems_set_errno_and_return_minus_one( EAGAIN );
}
pthread_mutex_lock( &suspendcbp->mutex );
suspendcbp->requests_left = 0;
suspendcbp->task_id = rtems_task_self();
suspendcbp->notified = !AIO_SIGNALED;
/* Lock request queue */
pthread_mutex_lock( &aio_request_queue.mutex );
/* Iterate over each request */
for ( i = 0; i < nent; i++ ) {
if ( list[i] == NULL ) {
continue;
}
/* Search fd_chain in work_req_chain */
r_chain = rtems_aio_search_fd( work_req_chain, list[i]->aio_fildes, 0 );
/* If not found search in idle_req_chain */
if ( r_chain == NULL ) {
r_chain = rtems_aio_search_fd( idle_req_chain, list[i]->aio_fildes, 0 );
}
/* If not found continue */
if ( r_chain == NULL ) {
continue;
}
/* Search request in fd_chain */
request = rtems_aio_search_in_chain( list[i], &r_chain->perfd );
if ( request != NULL ) {
if ( request->suspendcbp == NULL ) {
request->suspendcbp = suspendcbp;
suspendcbp->requests_left++;
} else {
pthread_mutex_lock( &request->suspendcbp->mutex );
if ( request->suspendcbp->notified == AIO_SIGNALED ) {
pthread_mutex_unlock( &request->suspendcbp->mutex );
rtems_aio_update_suspendcbp( request->suspendcbp );
request->suspendcbp = suspendcbp;
suspendcbp->requests_left++;
} else{
pthread_mutex_unlock( &request->suspendcbp->mutex );
}
}
}
/* Request not present */
}
if ( suspendcbp->requests_left <= 0 ) {
pthread_mutex_unlock( &aio_request_queue.mutex );
pthread_mutex_unlock( &suspendcbp->mutex );
pthread_mutex_destroy( &suspendcbp->mutex );
free( suspendcbp );
return 0;
}
op_num = suspendcbp->requests_left;
/* Unlock request queue and suspendcb */
pthread_mutex_unlock( &aio_request_queue.mutex );
pthread_mutex_unlock( &suspendcbp->mutex );
/* Wait */
result = rtems_event_system_receive(
RTEMS_EVENT_SYSTEM_AIO_SUSPENSION_TERMINATED,
RTEMS_WAIT,
( timeout == NULL )? RTEMS_NO_TIMEOUT : rtems_timespec_to_ticks( timeout ),
&event_out
);
/* Timeout control */
if (result == RTEMS_TIMEOUT) {
rtems_set_errno_and_return_minus_one( EAGAIN );
}
/* Control to ensure at least one operation completed */
for ( i = 0; i < nent; i++) {
if ( list[i] != NULL && list[i]->error_code == EINPROGRESS ) {
op_num --;
}
}
if ( op_num <= 0 ) {
rtems_set_errno_and_return_minus_one( EINTR );
}
return 0;
}

View File

@@ -65,6 +65,8 @@ links:
uid: psxaio04
- role: build-dependency
uid: psxaio05
- role: build-dependency
uid: psxaio06
- role: build-dependency
uid: psxalarm01
- role: build-dependency

View File

@@ -0,0 +1,20 @@
SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
build-type: test-program
cflags: []
copyrights:
- Copyright (C) 2024 Alessandro Nardin <ale.daluch@gmail.com>
cppflags: []
cxxflags: []
enabled-by:
- RTEMS_POSIX_API
features: c cprogram
includes: []
ldflags: []
links: []
source:
- testsuites/psxtests/psxaio06/init.c
stlib: []
target: testsuites/psxtests/psxaio06.exe
type: build
use-after: []
use-before: []

View File

@@ -0,0 +1,127 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright 2024, Alessandro Nardin <ale.daluch@gmail.com>
*
* 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.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#define CONFIGURE_INIT
#include "system.h"
#include <rtems.h>
#include "tmacros.h"
#include <rtems/posix/aio_misc.h>
#include <aio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <fcntl.h>
const char rtems_test_name[] = "PSXAIO 6";
#define BUFSIZE 512
/* forward declarations to avoid warnings */
static struct aiocb *create_aiocb( int fd );
static void free_aiocb( struct aiocb *aiocbp );
static struct aiocb *create_aiocb( int fd )
{
struct aiocb *aiocbp;
aiocbp = malloc( sizeof( struct aiocb ) );
memset( aiocbp, 0, sizeof( struct aiocb ) );
aiocbp->aio_buf = malloc( BUFSIZE * sizeof( char ) );
aiocbp->aio_nbytes = BUFSIZE;
aiocbp->aio_offset = 0;
aiocbp->aio_reqprio = 0;
aiocbp->aio_fildes = fd;
aiocbp->aio_sigevent.sigev_notify = SIGEV_NONE;
aiocbp->aio_lio_opcode = LIO_READ;
return aiocbp;
}
static void free_aiocb( struct aiocb *aiocbp )
{
free( (void*) aiocbp->aio_buf );
free( aiocbp );
}
void *POSIX_Init( void *argument )
{
struct aiocb *aiocbp;
struct timespec timespec;
int fd, result;
timespec.tv_sec = 0;
timespec.tv_nsec = 1;
rtems_aio_init();
result = mkdir( "/tmp", S_IRWXU );
rtems_test_assert( result == 0 );
fd = open(
"/tmp/aio_fildes",
O_RDWR|O_CREAT,
S_IRWXU|S_IRWXG|S_IRWXO
);
rtems_test_assert( fd != -1 );
TEST_BEGIN();
aiocbp = create_aiocb( fd );
const struct aiocb *s_aiocbp = aiocbp;
// EINVAL
result = aio_suspend( NULL, 1, NULL );
rtems_test_assert( result != 0 );
rtems_test_assert( errno == EINVAL );
result = aio_suspend( &s_aiocbp, -1, NULL );
rtems_test_assert( result != 0 );
rtems_test_assert( errno == EINVAL );
//NO ERROR
result = aio_read( aiocbp );
rtems_test_assert( result == 0 );
result = aio_suspend( &s_aiocbp, 1, &timespec );
rtems_test_assert( result == 0 );
result = aio_error( s_aiocbp );
rtems_test_assert( result != EINPROGRESS );
TEST_END();
free_aiocb( aiocbp );
close( fd );
rtems_test_exit( 0 );
return NULL;
}

View File

@@ -0,0 +1,2 @@
*** BEGIN OF TEST PSXAIO 6 ***
*** END OF TEST PSXAIO 6 ***

View File

@@ -0,0 +1,61 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright 2024, Alessandro Nardin <ale.daluch@gmail.com>
*
* 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.
*
* 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.
*/
/* functions */
#include <pmacros.h>
#include <pthread.h>
#include <errno.h>
#include <sched.h>
void *POSIX_Init( void *argument );
/* configuration information */
#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_MAXIMUM_TASKS 20
#define CONFIGURE_MAXIMUM_SEMAPHORES 20
#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES 20
#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 20
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
#define CONFIGURE_MAXIMUM_POSIX_THREADS 10
#define CONFIGURE_MAXIMUM_POSIX_KEYS 10
#define CONFIGURE_POSIX_INIT_THREAD_TABLE
#define CONFIGURE_EXTRA_TASK_STACKS ( 10 * RTEMS_MINIMUM_STACK_SIZE )
#define CONFIGURE_POSIX_INIT_THREAD_STACK_SIZE ( 10 * RTEMS_MINIMUM_STACK_SIZE )
#include <rtems/confdefs.h>
/* global variables */
TEST_EXTERN pthread_t Init_id;
/* end of include file */

View File

@@ -68,9 +68,6 @@ void *POSIX_Init(
check_enosys( sc );
#endif
sc = aio_suspend( NULL, 0, NULL );
check_enosys( sc );
sc = clock_getcpuclockid( 0, NULL );
check_enosys( sc );