diff --git a/cpukit/include/aio.h b/cpukit/include/aio.h index 14a0ff0859..7b80f3af2a 100644 --- a/cpukit/include/aio.h +++ b/cpukit/include/aio.h @@ -139,13 +139,16 @@ struct aiocb { * @param[in,out] aiocbp is a pointer to the asynchronous I/O control block * * @retval 0 The request has been successfuly enqueued. - * @retval -1 The request has not been enqueued due to an error. The error is indicated in errno: - * - EBADF FD not opened for read - * - EINVAL invalid aio_reqprio or aio_offset or aio_nbytes - * - EAGAIN not enough memory - * - EINVAL the starting position of the file is past the maximum offset + * @retval -1 The request has not been enqueued due to an error. + * The error is indicated in errno: + * - EBADF FD not opened for read. + * - EINVAL invalid aio_reqprio or aio_offset or aio_nbytes. + * - EAGAIN not enough memory. + * - EAGAIN the addition of a new request to the queue would + * violate the RTEMS_AIO_MAX limit. + * - EINVAL the starting position of the file is past the maximum offset. * for this file. - * - EINVAL aiocbp is a NULL pointer + * - EINVAL aiocbp is a NULL pointer. * - EINVAL aiocbp->sigevent is not valid. */ int aio_read( @@ -160,11 +163,14 @@ int aio_read( * @param[in,out] aiocbp is a pointer to the asynchronous I/O control block * * @retval 0 The request has been successfuly enqueued. - * @retval -1 The request has not been enqueued due to an error. The error is indicated in errno: - * - EBADF FD not opened for write - * - EINVAL invalid aio_reqprio or aio_offset or aio_nbytes - * - EAGAIN not enough memory - * - EINVAL aiocbp is a NULL pointer + * @retval -1 The request has not been enqueued due to an error. + * The error is indicated in errno: + * - EBADF FD not opened for write. + * - EINVAL invalid aio_reqprio or aio_offset or aio_nbytes. + * - EAGAIN not enough memory. + * - EAGAIN the addition of a new request to the queue would + * violate the RTEMS_AIO_MAX limit. + * - EINVAL aiocbp is a NULL pointer. * - EINVAL aiocbp->sigevent is not valid. */ int aio_write( @@ -172,9 +178,29 @@ int aio_write( ); /** - * @brief List Directed I/O - NOT IMPLEMENTED + * @brief List Directed I/O * * 6.7.4 List Directed I/O, P1003.1b-1993, p. 158 + * + * @param[in] mode can be LIO_WAIT or LIO_NOWAIT + * @param[in,out] list is a pointer to the array of aiocb + * @param[in] nent is the number of element in list + * @param[in] sig if mode is LIO_NOWAIT, specifies how to notify list completion. + * + * @retval 0 the call to lio_listio() has completed successfuly. + * @retval -1 The call did not complete successfully. + * The error is indicated in errno: + * - EAGAIN the call failed due to resources limitations. + * - EAGAIN the number of entries indicated by nent value would cause + * the RTEMS_AIO_MAX limit to be excedeed. + * - EINVAL list is a NULL pointer. + * - EINVAL mode is not a valid value. + * - EINVAL the value of nent is not valid or higher than AIO_LISTIO_MAX. + * - EINVAL list is a NULL pointer. + * - EINVAL the sigevent struct pointed by sig is not valid. + * - EINTR the wait for list completion during a LIO_WAIT operation was + * interrupted by an external event. + * - EIO One or more of the individual I/O operations failed. */ int lio_listio( int mode, @@ -266,6 +292,8 @@ int aio_suspend( * @retval -1 An error occured. errno indicated the error: * - EAGAIN The requested asynchronous operation was not queued * due to temporary resource limitations. + * - EAGAIN the addition of a new request to the queue would + * violate the RTEMS_AIO_MAX limit. * - EBADF The aio_fildes member of the aiocb structure referenced * by the aiocbp argument is not a valid file descriptor. * - EINVAL A value of op other than O_SYNC or O_DSYNC was specified. diff --git a/cpukit/include/rtems/posix/aio_misc.h b/cpukit/include/rtems/posix/aio_misc.h index f1c7073e1a..0769e4ff67 100644 --- a/cpukit/include/rtems/posix/aio_misc.h +++ b/cpukit/include/rtems/posix/aio_misc.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,7 @@ extern "C" { #define AIO_OP_WRITE 1 /** Needed by aio_fsync() */ -#define AIO_OP_SYNC 2 +#define AIO_OP_SYNC 2 /** Needed by aio_fsync() */ #define AIO_OP_DSYNC 3 @@ -81,6 +82,49 @@ extern "C" { /** The aio operation return value has not been retrieved */ #define AIO_NOTRETURNED 1 +/** Constants to identify list completion notification */ + +/** No notification required */ +#define AIO_LIO_NO_NOTIFY 0 + +/** Notification via sigevent */ +#define AIO_LIO_SIGEV 1 + +/** Notification via event delivery */ +#define AIO_LIO_EVENT 2 + +/** + * @brief holds a pointer to a sigevent struct or a thread id + * + */ +typedef union +{ + /** @brief pointer to the sigevent for notification */ + struct sigevent *sigp; + + /** @brief id of the thread that called lio_listio() */ + int task_id; + +} lio_notification_union; + +/** + * @brief Control block for every list enqueued with lio_listio() + */ +typedef struct +{ + pthread_mutex_t mutex; + + /** @brief number of requests left to complete the list */ + int requests_left; + + /** @brief type of notification */ + int notification_type; + + /** @brief event to do at list completion*/ + lio_notification_union lio_notification; + +} listcb; + /** * @brief The request being processed */ @@ -98,6 +142,9 @@ typedef struct /** @brief Used for notification */ pthread_t caller_thread; + /** @brief pointer to list control block */ + listcb *listcbp; + /** @brief Aio control block */ struct aiocb *aiocbp; @@ -152,6 +199,9 @@ typedef struct /** @brief The number of idle threads */ int idle_threads; + /** @brief The number of queued requests*/ + atomic_int queued_requests; + } rtems_aio_queue; extern rtems_aio_queue aio_request_queue; @@ -162,8 +212,12 @@ extern rtems_aio_queue aio_request_queue; #define AIO_MAX_THREADS 5 #endif -#ifndef AIO_MAX_QUEUE_SIZE -#define AIO_MAX_QUEUE_SIZE 30 +#ifndef AIO_LISTIO_MAX +#define AIO_LISTIO_MAX 20 +#endif + +#ifndef RTEMS_AIO_MAX +#define RTEMS_AIO_MAX 100 #endif /** @@ -233,6 +287,39 @@ int rtems_aio_remove_req( */ int rtems_aio_check_sigevent( struct sigevent *sigp ); +/** + * @brief initializes a read rtems_aio_request + * + * @param aiocb pointer to the aiocb describing the request + * @retval NULL the aiocb passed was invalid, errno indicates the error: + * - + * @return rtems_aio_request* a pointer to the newly created request. + */ +rtems_aio_request *init_write_req( struct aiocb* aiocbp ); + +/** + * @brief initializes a write rtems_aio_request + * + * @param aiocb pointer to the aiocb describing the request + * @retval NULL the aiocb passed was invalid, errno indicates the error: + * - + * @return rtems_aio_request* a pointer to the newly created request. + */ +rtems_aio_request *init_read_req( struct aiocb* aiocbp ); + +/** + * @brief updates listcb after op completion + * + * @param listcbp + */ +void rtems_aio_completed_list_op( listcb *listcbp ); + +/** + * @brief generates event at list completion to end wait in lio_listio(). + * + */ +void lio_notify_end_wait( union sigval attr ); + #ifdef RTEMS_DEBUG #include diff --git a/cpukit/include/rtems/rtems/event.h b/cpukit/include/rtems/rtems/event.h index 81aa57585f..794c13012a 100644 --- a/cpukit/include/rtems/rtems/event.h +++ b/cpukit/include/rtems/rtems/event.h @@ -536,6 +536,12 @@ rtems_status_code rtems_event_system_send( */ #define RTEMS_EVENT_SYSTEM_SERVER RTEMS_EVENT_30 +/** + * @brief This event set constant represents the reserved system event for + * aio list completion, used when lio_listio is called using LIO_WAIT. + */ +#define RTEMS_EVENT_SYSTEM_AIO_LIST RTEMS_EVENT_28 + /* Generated from spec:/rtems/event/if/system-server-resume */ /** diff --git a/cpukit/posix/src/aio_cancel.c b/cpukit/posix/src/aio_cancel.c index b682e516cd..5971aaadb9 100644 --- a/cpukit/posix/src/aio_cancel.c +++ b/cpukit/posix/src/aio_cancel.c @@ -10,6 +10,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). diff --git a/cpukit/posix/src/aio_error.c b/cpukit/posix/src/aio_error.c index 8b4fd658b0..2030b9c67a 100644 --- a/cpukit/posix/src/aio_error.c +++ b/cpukit/posix/src/aio_error.c @@ -10,6 +10,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). diff --git a/cpukit/posix/src/aio_fsync.c b/cpukit/posix/src/aio_fsync.c index b268368b44..013515a734 100644 --- a/cpukit/posix/src/aio_fsync.c +++ b/cpukit/posix/src/aio_fsync.c @@ -10,6 +10,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011, 2024. * On-Line Applications Research Corporation (OAR). @@ -64,6 +65,11 @@ int aio_fsync( rtems_aio_request *req; int mode; + + if ( 1 + atomic_load( &aio_request_queue.queued_requests ) > RTEMS_AIO_MAX ) { + rtems_set_errno_and_return_minus_one( EAGAIN ); + } + if ( aiocbp == NULL ) rtems_set_errno_and_return_minus_one( EINVAL ); @@ -94,6 +100,7 @@ int aio_fsync( */ req->aiocbp = aiocbp; req->op_type = AIO_OP_SYNC; + req->listcbp = NULL; return rtems_aio_enqueue( req ); } diff --git a/cpukit/posix/src/aio_misc.c b/cpukit/posix/src/aio_misc.c index 62a68de322..b637e1dc1e 100644 --- a/cpukit/posix/src/aio_misc.c +++ b/cpukit/posix/src/aio_misc.c @@ -12,6 +12,7 @@ /* * Copyright 2010-2011, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). @@ -46,6 +47,7 @@ #include #include #include +#include /** * @brief Thread processing AIO requests. @@ -143,11 +145,133 @@ int rtems_aio_init( void ) aio_request_queue.active_threads = 0; aio_request_queue.idle_threads = 0; + atomic_init( &aio_request_queue.queued_requests, 0 ); aio_request_queue.initialized = AIO_QUEUE_INITIALIZED; return result; } +rtems_aio_request *init_write_req( struct aiocb* aiocbp ) +{ + rtems_aio_request *req; + int mode; + + if ( aiocbp == NULL ) { + errno = EINVAL; + return NULL; + } + + mode = fcntl( aiocbp->aio_fildes, F_GETFL ); + if ( + ( mode&O_ACCMODE ) != O_WRONLY && + ( mode&O_ACCMODE ) != O_RDWR + ) { + errno = EBADF; + return NULL; + } + + if ( aiocbp->aio_reqprio < 0 || aiocbp->aio_reqprio > AIO_PRIO_DELTA_MAX ) { + errno = EINVAL; + return NULL; + } + + if ( aiocbp->aio_offset < 0 ) { + errno = EINVAL; + return NULL; + } + + if ( rtems_aio_check_sigevent( &aiocbp->aio_sigevent ) == 0 ) { + errno = EINVAL; + return NULL; + } + + req = malloc( sizeof( rtems_aio_request ) ); + if ( req == NULL ) { + errno = EAGAIN; + return NULL; + } + + req->aiocbp = aiocbp; + req->op_type = AIO_OP_WRITE; + req->listcbp = NULL; + + return req; +} + +rtems_aio_request *init_read_req( struct aiocb* aiocbp ) +{ + rtems_aio_request *req; + int mode; + + if ( aiocbp == NULL ) { + errno = EINVAL; + return NULL; + } + + mode = fcntl( aiocbp->aio_fildes, F_GETFL ); + if ( + ( mode&O_ACCMODE ) != O_RDONLY && + ( mode&O_ACCMODE ) != O_RDWR + ) { + errno = EBADF; + return NULL; + } + + if ( aiocbp->aio_reqprio < 0 || aiocbp->aio_reqprio > AIO_PRIO_DELTA_MAX ) { + errno = EINVAL; + return NULL; + } + + if ( aiocbp->aio_offset < 0 ) { + errno = EINVAL; + return NULL; + } + + if ( rtems_aio_check_sigevent( &aiocbp->aio_sigevent ) == 0 ) { + errno = EINVAL; + return NULL; + } + + req = malloc( sizeof( rtems_aio_request ) ); + if ( req == NULL ) { + errno = EAGAIN; + return NULL; + } + + req->aiocbp = aiocbp; + req->op_type = AIO_OP_READ; + req->listcbp = NULL; + + return req; +} + +void rtems_aio_completed_list_op( listcb *listcbp ) +{ + if (listcbp == NULL) + return; + + pthread_mutex_lock( &listcbp->mutex ); + + if( --listcbp->requests_left == 0 ){ + switch ( listcbp->notification_type ) { + case AIO_LIO_NO_NOTIFY: + break; + case AIO_LIO_SIGEV: + rtems_aio_notify( listcbp->lio_notification.sigp ); + break; + case AIO_LIO_EVENT: + rtems_event_system_send( + listcbp->lio_notification.task_id, + RTEMS_EVENT_SYSTEM_AIO_LIST + ); + break; + } + free( listcbp ); + } + + pthread_mutex_unlock( &listcbp->mutex ); +} + rtems_aio_request_chain *rtems_aio_search_fd( rtems_chain_control *chain, int fildes, @@ -249,6 +373,8 @@ void rtems_aio_remove_fd( rtems_aio_request_chain *r_chain ) rtems_chain_extract( &req->next_prio ); req->aiocbp->error_code = ECANCELED; req->aiocbp->return_value = -1; + atomic_fetch_sub( &aio_request_queue.queued_requests, 1 ); + rtems_aio_completed_list_op( req->listcbp ); free( req ); } } @@ -274,6 +400,8 @@ int rtems_aio_remove_req( rtems_chain_control *chain, struct aiocb *aiocbp ) 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 ); } @@ -308,6 +436,7 @@ int rtems_aio_enqueue( rtems_aio_request *req ) req->aiocbp->error_code = EINPROGRESS; req->aiocbp->return_value = 0; req->aiocbp->return_status = AIO_NOTRETURNED; + atomic_fetch_add( &aio_request_queue.queued_requests, 1 ); if ( aio_request_queue.idle_threads == 0 && @@ -510,8 +639,12 @@ static void *rtems_aio_handle( void *arg ) req = (rtems_aio_request *) node; /* See _POSIX_PRIORITIZE_IO and _POSIX_PRIORITY_SCHEDULING - discussion in rtems_aio_enqueue () */ - pthread_getschedparam( pthread_self(), &policy, ¶m ); + discussion in rtems_aio_enqueue() */ + pthread_getschedparam( + pthread_self(), + &policy, + ¶m + ); param.sched_priority = req->priority; pthread_setschedparam( pthread_self(), req->policy, ¶m ); @@ -522,7 +655,15 @@ static void *rtems_aio_handle( void *arg ) /* perform the requested operation*/ rtems_aio_handle_helper( req ); - /* notification needed for lio after final op is complete */ + /* update queued_requests */ + atomic_fetch_sub( &aio_request_queue.queued_requests, 1 ); + + /* notification for request completion */ + rtems_aio_notify( &req->aiocbp->aio_sigevent ); + + /* notification for list completion */ + rtems_aio_completed_list_op( req->listcbp ); + req->listcbp = NULL; } else { /* If the fd chain is empty we unlock the fd chain and we lock @@ -646,8 +787,6 @@ static void rtems_aio_handle_helper( rtems_aio_request *req ) result = -1; } - rtems_aio_notify( &req->aiocbp->aio_sigevent ); - if ( result < 0 ) { req->aiocbp->return_value = -1; req->aiocbp->error_code = errno; @@ -657,3 +796,10 @@ static void rtems_aio_handle_helper( rtems_aio_request *req ) } } +void lio_notify_end_wait( union sigval attr ){ + rtems_id id = attr.sival_int; + rtems_event_set event_in = RTEMS_EVENT_SYSTEM_AIO_LIST; + + rtems_event_system_send( id, event_in ); +} + diff --git a/cpukit/posix/src/aio_read.c b/cpukit/posix/src/aio_read.c index 70bf469999..dda4c54c13 100644 --- a/cpukit/posix/src/aio_read.c +++ b/cpukit/posix/src/aio_read.c @@ -10,6 +10,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). @@ -51,36 +52,17 @@ int aio_read( struct aiocb *aiocbp ) { rtems_aio_request *req; - int mode; - if ( aiocbp == NULL ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - mode = fcntl( aiocbp->aio_fildes, F_GETFL ); - if ( - !( - (( mode&O_ACCMODE ) == O_RDONLY ) || - (( mode&O_ACCMODE ) == O_RDWR ) - ) - ) - rtems_set_errno_and_return_minus_one( EBADF ); - - if ( aiocbp->aio_reqprio < 0 || aiocbp->aio_reqprio > AIO_PRIO_DELTA_MAX ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - if ( aiocbp->aio_offset < 0 ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - if ( rtems_aio_check_sigevent( &aiocbp->aio_sigevent ) == 0 ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - req = malloc( sizeof( rtems_aio_request ) ); - if ( req == NULL ) + if ( 1 + atomic_load( &aio_request_queue.queued_requests ) > RTEMS_AIO_MAX ) { rtems_set_errno_and_return_minus_one( EAGAIN ); + } - req->aiocbp = aiocbp; - req->op_type = AIO_OP_READ; + req = init_read_req( aiocbp ); - return rtems_aio_enqueue( req ); + if ( req != NULL ) { + return rtems_aio_enqueue( req ); + } else { + return -1; + } } diff --git a/cpukit/posix/src/aio_return.c b/cpukit/posix/src/aio_return.c index a2b2f28485..9aefd891e1 100644 --- a/cpukit/posix/src/aio_return.c +++ b/cpukit/posix/src/aio_return.c @@ -10,6 +10,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). diff --git a/cpukit/posix/src/aio_write.c b/cpukit/posix/src/aio_write.c index 5492e61367..3cdebf44b3 100644 --- a/cpukit/posix/src/aio_write.c +++ b/cpukit/posix/src/aio_write.c @@ -9,7 +9,8 @@ */ /* - * Copyright 2010, Alin Rus + * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,36 +49,17 @@ int aio_write( struct aiocb *aiocbp ) { rtems_aio_request *req; - int mode; - if ( aiocbp == NULL ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - mode = fcntl( aiocbp->aio_fildes, F_GETFL ); - if ( - !( - ( ( mode&O_ACCMODE ) == O_WRONLY ) || - ( ( mode&O_ACCMODE ) == O_RDWR ) - ) - ) - rtems_set_errno_and_return_minus_one( EBADF ); - - if ( aiocbp->aio_reqprio < 0 || aiocbp->aio_reqprio > AIO_PRIO_DELTA_MAX ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - if ( aiocbp->aio_offset < 0 ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - if ( rtems_aio_check_sigevent( &aiocbp->aio_sigevent ) == 0 ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - req = malloc( sizeof( rtems_aio_request ) ); - if ( req == NULL ) + if ( 1 + atomic_load( &aio_request_queue.queued_requests ) > RTEMS_AIO_MAX ) { rtems_set_errno_and_return_minus_one( EAGAIN ); + } - req->aiocbp = aiocbp; - req->op_type = AIO_OP_WRITE; + req = init_write_req( aiocbp ); - return rtems_aio_enqueue( req ); + if ( req != NULL ) { + return rtems_aio_enqueue( req ); + } else { + return -1; + } } diff --git a/cpukit/posix/src/lio_listio.c b/cpukit/posix/src/lio_listio.c index a4d5b4e700..416b559a05 100644 --- a/cpukit/posix/src/lio_listio.c +++ b/cpukit/posix/src/lio_listio.c @@ -42,16 +42,167 @@ #include #include - +#include +#include +#include +#include +#include #include #include int lio_listio( - int mode RTEMS_UNUSED, - struct aiocb *__restrict const list[__restrict] RTEMS_UNUSED, - int nent RTEMS_UNUSED, - struct sigevent *__restrict sig RTEMS_UNUSED + int mode, + struct aiocb *__restrict const list[__restrict], + int nent, + struct sigevent *__restrict sig ) { - rtems_set_errno_and_return_minus_one( ENOSYS ); + int result, error; + listcb *listcbp; + rtems_aio_request *req; + + /* Errors on parameters */ + if ( list == NULL ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( mode != LIO_WAIT && mode != LIO_NOWAIT ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( nent < 1 || nent > AIO_LISTIO_MAX ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + if ( nent + atomic_load( &aio_request_queue.queued_requests ) > RTEMS_AIO_MAX ) { + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + /* Initialize list control block */ + listcbp = malloc( sizeof( listcb ) ); + if ( listcbp == NULL ) { + rtems_set_errno_and_return_minus_one( EAGAIN ); + } + + result = pthread_mutex_init( &listcbp->mutex, NULL ); + if ( result != 0 ) { + free( listcbp ); + rtems_set_errno_and_return_minus_one( EAGAIN ); + } + + listcbp->requests_left = 1; + + /* Set up notification for list completion (wait or no wait) */ + if ( mode == LIO_WAIT ) { + listcbp->notification_type = AIO_LIO_EVENT; + listcbp->lio_notification.task_id = rtems_task_self(); + + } else if ( mode == LIO_NOWAIT ) { + + if ( sig == NULL ) { + listcbp->notification_type = AIO_LIO_NO_NOTIFY; + } else { + if ( rtems_aio_check_sigevent( sig ) == 0 ) { + free( listcbp ); + rtems_set_errno_and_return_minus_one( EINVAL ); + } + + listcbp->notification_type = AIO_LIO_SIGEV; + listcbp->lio_notification.sigp = sig; + } + } + + /* Initialize and enqueue each request */ + error = 0; + + for( int i = 0; i < nent; i++ ) { + if ( list[i] == NULL ) { + continue; + } + + switch ( list[i]->aio_lio_opcode ) { + case LIO_READ: + req = init_read_req( list[i] ); + if ( req == NULL ) { + error = 1; + list[i]->return_value = -1; + list[i]->error_code = errno; + list[i]->return_status = AIO_NOTRETURNED; + break; + } + + req->listcbp = listcbp; + result = rtems_aio_enqueue( req ); + if ( result != 0 ) { + error = 1; + list[i]->return_value = -1; + list[i]->error_code = EAGAIN; + list[i]->return_status = AIO_NOTRETURNED; + break; + } + + listcbp->requests_left++; + break; + + case LIO_WRITE: + req = init_write_req( list[i] ); + if ( req == NULL ) { + error = 1; + list[i]->error_code = errno; + list[i]->return_value = -1; + list[i]->return_status = AIO_NOTRETURNED; + break; + } + + req->listcbp = listcbp; + result = rtems_aio_enqueue( req ); + if ( result != 0 ) { + error = 1; + list[i]->return_value = -1; + list[i]->error_code = EAGAIN; + list[i]->return_status = AIO_NOTRETURNED; + break; + } + + listcbp->requests_left++; + break; + } + } + rtems_aio_completed_list_op( listcbp ); + + if ( mode == LIO_NOWAIT ) { + if ( error == 1 ) { + rtems_set_errno_and_return_minus_one( EIO ); + } + } else if ( mode == LIO_WAIT ) { + rtems_event_set event_out; + rtems_event_system_receive( + RTEMS_EVENT_SYSTEM_AIO_LIST, + RTEMS_DEFAULT_OPTIONS, + RTEMS_NO_TIMEOUT, + &event_out + ); + + for ( int i = 0; i < nent; i++ ) { + if ( list[i] != NULL ) { + if ( + list[i]->aio_lio_opcode == LIO_READ || + list[i]->aio_lio_opcode == LIO_WRITE + ) { + switch ( list[i]->error_code ) { + case 0: + break; + case EINPROGRESS: + rtems_set_errno_and_return_minus_one( EINTR ); + break; + default: + rtems_set_errno_and_return_minus_one( EIO ); + } + } + } + } + } + + return 0; } + diff --git a/spec/build/testsuites/psxtests/grp.yml b/spec/build/testsuites/psxtests/grp.yml index fe69ce1b6d..e08b1b8c91 100644 --- a/spec/build/testsuites/psxtests/grp.yml +++ b/spec/build/testsuites/psxtests/grp.yml @@ -63,6 +63,8 @@ links: uid: psxaio03 - role: build-dependency uid: psxaio04 +- role: build-dependency + uid: psxaio05 - role: build-dependency uid: psxalarm01 - role: build-dependency diff --git a/spec/build/testsuites/psxtests/psxaio05.yml b/spec/build/testsuites/psxtests/psxaio05.yml new file mode 100644 index 0000000000..746a112f50 --- /dev/null +++ b/spec/build/testsuites/psxtests/psxaio05.yml @@ -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 +cppflags: [] +cxxflags: [] +enabled-by: +- RTEMS_POSIX_API +features: c cprogram +includes: [] +ldflags: [] +links: [] +source: +- testsuites/psxtests/psxaio05/init.c +stlib: [] +target: testsuites/psxtests/psxaio05.exe +type: build +use-after: [] +use-before: [] diff --git a/testsuites/psxtests/psxaio01/init.c b/testsuites/psxtests/psxaio01/init.c index 3a67bc6ac6..ec6736eaa2 100644 --- a/testsuites/psxtests/psxaio01/init.c +++ b/testsuites/psxtests/psxaio01/init.c @@ -2,6 +2,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -46,10 +47,10 @@ const char rtems_test_name[] = "PSXAIO 1"; #define WRONG_FD 404 /* forward declarations to avoid warnings */ -struct aiocb *create_aiocb( int fd ); -void free_aiocb( struct aiocb *aiocbp ); +static struct aiocb *create_aiocb( int fd ); +static void free_aiocb( struct aiocb *aiocbp ); -struct aiocb *create_aiocb( int fd ) +static struct aiocb *create_aiocb( int fd ) { struct aiocb *aiocbp; @@ -64,7 +65,7 @@ struct aiocb *create_aiocb( int fd ) return aiocbp; } -void free_aiocb( struct aiocb *aiocbp ) +static void free_aiocb( struct aiocb *aiocbp ) { free( (void*) aiocbp->aio_buf ); free( aiocbp ); diff --git a/testsuites/psxtests/psxaio02/init.c b/testsuites/psxtests/psxaio02/init.c index d5ac824874..95ab7432c4 100644 --- a/testsuites/psxtests/psxaio02/init.c +++ b/testsuites/psxtests/psxaio02/init.c @@ -2,6 +2,7 @@ /* * Copyright 2010, Alin Rus + * Copyright 2024, Alessandro Nardin * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -44,14 +45,14 @@ const char rtems_test_name[] = "PSXAIO 2"; /* forward declarations to avoid warnings */ -struct aiocb *create_aiocb( int fd ); -void free_aiocb( struct aiocb *aiocbp ); +static struct aiocb *create_aiocb( int fd ); +static void free_aiocb( struct aiocb *aiocbp ); #define BUFSIZE 32 #define FD_COUNT 10 #define WRONG_FD 666 -struct aiocb *create_aiocb( int fd ) +static struct aiocb *create_aiocb( int fd ) { struct aiocb *aiocbp; @@ -66,7 +67,7 @@ struct aiocb *create_aiocb( int fd ) return aiocbp; } -void free_aiocb( struct aiocb *aiocbp ) +static void free_aiocb( struct aiocb *aiocbp ) { free( (void*) aiocbp->aio_buf ); free( aiocbp ); @@ -94,8 +95,6 @@ void *POSIX_Init( void *argument ) rtems_test_assert( !status ); TEST_BEGIN(); - - puts( "Init: Open files" ); for( i=0; iaio_buf ); free( aiocbp ); diff --git a/testsuites/psxtests/psxaio04/init.c b/testsuites/psxtests/psxaio04/init.c index 80b1293ef0..63dd9c1e56 100644 --- a/testsuites/psxtests/psxaio04/init.c +++ b/testsuites/psxtests/psxaio04/init.c @@ -47,11 +47,11 @@ const char rtems_test_name[] = "PSXAIO 4"; #define WRONG_FD 404 /* forward declarations to avoid warnings */ -struct aiocb *create_aiocb( int fd ); -void free_aiocb( struct aiocb *aiocbp ); -void notify( union sigval sig ); +static struct aiocb *create_aiocb( int fd ); +static void free_aiocb( struct aiocb *aiocbp ); +static void notify( union sigval sig ); -struct aiocb *create_aiocb( int fd ) +static struct aiocb *create_aiocb( int fd ) { struct aiocb *aiocbp; @@ -66,13 +66,13 @@ struct aiocb *create_aiocb( int fd ) return aiocbp; } -void free_aiocb( struct aiocb *aiocbp ) +static void free_aiocb( struct aiocb *aiocbp ) { free( (void*) aiocbp->aio_buf ); free( aiocbp ); } -void notify( union sigval sig ) +static void notify( union sigval sig ) { kill( getpid(), sig.sival_int ); } @@ -144,6 +144,7 @@ void *POSIX_Init( void *argument ) TEST_END(); + free_aiocb( aiocbp ); close( fd ); rtems_test_exit( 0 ); diff --git a/testsuites/psxtests/psxaio05/init.c b/testsuites/psxtests/psxaio05/init.c new file mode 100644 index 0000000000..5146c397d1 --- /dev/null +++ b/testsuites/psxtests/psxaio05/init.c @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright 2024, Alessandro Nardin + * + * 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. + */ + +#include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define CONFIGURE_INIT +#include "system.h" +#include +#include "tmacros.h" +#include +#include +#include +#include +#include +#include +#include + +const char rtems_test_name[] = "PSXAIO 5"; + +#define BUFSIZE 512 +#define WRONG_FD 404 +#define BAD_MODE 38576 + +/* forward declarations to avoid warnings */ +static struct aiocb *create_aiocb( int fd ); +static void free_aiocb( struct aiocb *aiocbp ); +static void test_einval( struct aiocb** aiocbp ); +static void test_eio( struct aiocb** aiocbp ); +static void test_no_wait( struct aiocb** aiocbp ); +static void test_wait( 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 ); +} + +static void test_einval( struct aiocb** aiocbp ) +{ + int status; + + status = lio_listio( LIO_WAIT, NULL, 1, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EINVAL ); + errno = 0; + + status = lio_listio( BAD_MODE, aiocbp, 1, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EINVAL ); + errno = 0; + + status = lio_listio( LIO_WAIT, aiocbp, -9, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EINVAL ); + errno = 0; + + status = lio_listio( LIO_WAIT, aiocbp, 547, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EINVAL ); + errno = 0; +} + +static void test_eio( struct aiocb** aiocbp ) +{ + int status; + + status = lio_listio( LIO_NOWAIT, &aiocbp[4], 1, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EIO ); + errno = 0; + + status = lio_listio( LIO_WAIT, &aiocbp[4], 1, NULL); + rtems_test_assert( status == -1 ); + rtems_test_assert( errno == EIO ); + errno = 0; +} + +static void test_no_wait( struct aiocb** aiocbp ) +{ + int status, received_signal, sig; + struct sigevent sigev; + sigset_t sig_set; + + sig = SIGUSR1; + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = sig; + sigev.sigev_value.sival_ptr = NULL; + + status = sigemptyset( &sig_set ); + rtems_test_assert( status == 0 ); + + status = sigaddset( &sig_set, sig ); + rtems_test_assert( status == 0 ); + + status = sigprocmask( SIG_BLOCK, &sig_set, NULL ); + rtems_test_assert( status == 0 ); + + status = lio_listio( LIO_NOWAIT, aiocbp, 4, &sigev); + rtems_test_assert( status == 0 ); + + status = sigwait( &sig_set, &received_signal ); + rtems_test_assert( status == 0 ); + rtems_test_assert( received_signal == sig ); + + status = sigprocmask( SIG_UNBLOCK, &sig_set, NULL ); + rtems_test_assert( status == 0 ); +} + +static void test_wait( struct aiocb** aiocbp ) +{ + int status; + + status = lio_listio( LIO_WAIT, aiocbp, 4, NULL); + rtems_test_assert( status == 0 ); +} + +void *POSIX_Init( void *argument ) +{ + struct aiocb *aiocbp[] = { NULL, NULL, NULL, NULL, NULL }; + int fd, result; + + 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(); + + for (int i = 0; i<4; i++ ) { + aiocbp[i] = create_aiocb( fd ); + } + aiocbp[4] = create_aiocb( WRONG_FD ); + + test_einval( aiocbp ); + + test_eio( aiocbp ); + + test_no_wait( aiocbp ); + + test_wait( aiocbp ); + + TEST_END(); + + for (int i = 0; i<5; i++ ) { + free_aiocb(aiocbp[i]); + } + + close( fd ); + rtems_test_exit( 0 ); + + return NULL; +} \ No newline at end of file diff --git a/testsuites/psxtests/psxaio05/psxaio05.scn b/testsuites/psxtests/psxaio05/psxaio05.scn new file mode 100644 index 0000000000..530e0f1e0e --- /dev/null +++ b/testsuites/psxtests/psxaio05/psxaio05.scn @@ -0,0 +1,2 @@ +*** BEGIN OF TEST PSXAIO 5 *** +*** END OF TEST PSXAIO 5 *** diff --git a/testsuites/psxtests/psxaio05/system.h b/testsuites/psxtests/psxaio05/system.h new file mode 100644 index 0000000000..2b2036bc91 --- /dev/null +++ b/testsuites/psxtests/psxaio05/system.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright 2024, Alessandro Nardin + * + * 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 +#include +#include +#include + +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 + +/* global variables */ +TEST_EXTERN pthread_t Init_id; + +/* end of include file */