/* * COPYRIGHT (c) 1989-2009. * On-Line Applications Research Corporation (OAR). * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id$ */ #define CONFIGURE_INIT #include "system.h" #include #include #include #include #include /* signal facilities */ #include "test_support.h" typedef struct { char msg[ 50 ]; int size; unsigned int priority; }Test_Message_t; Test_Message_t Predefined_Msgs[MAXMSG+1]; Test_Message_t Predefined_Msgs[MAXMSG+1] = { { "12345678", 9, MQ_PRIO_MAX-1 }, /* Max Length Message med */ { "", 1, 1 }, /* NULL Message low */ { "Last", 5, MQ_PRIO_MAX }, /* Queue Full Message hi */ { "No Message", 0, MQ_PRIO_MAX-1 }, /* 0 length Message med */ { "1", 2, 0 }, /* Cause Overflow Behavior */ }; int Priority_Order[MAXMSG+1] = { 2, 0, 3, 1, MAXMSG }; typedef struct { mqd_t mq; Test_Queue_Types index; char *name; int oflag; int maxmsg; int msgsize; int count; } Test_queue_type; Test_queue_type Test_q[ NUMBER_OF_TEST_QUEUES + 1 ] = { { 0, 0, "Qread", ( O_CREAT | O_RDONLY | O_NONBLOCK ), MAXMSG, MSGSIZE, 0 }, { 0, 1, "Qwrite", ( O_CREAT | O_WRONLY | O_NONBLOCK ), MAXMSG, MSGSIZE, 0 }, { 0, 2, "Qnoblock", ( O_CREAT | O_RDWR | O_NONBLOCK ), MAXMSG, MSGSIZE, 0 }, { 0, 3, "Qblock", ( O_CREAT | O_RDWR ) , MAXMSG, MSGSIZE, 0 }, { 0, 4, "Qdefault", ( O_CREAT | O_RDWR ) , 10, 16, 0 }, { 0, 5, "mq6", ( O_CREAT | O_WRONLY | O_NONBLOCK ), MAXMSG, MSGSIZE, 0 }, { 0, 6, "Qblock", ( O_RDWR ) , MAXMSG, MSGSIZE, 0 }, }; #define RW_NAME Test_q[ RW_QUEUE ].name #define DEFAULT_NAME Test_q[ DEFAULT_RW ].name #define RD_NAME Test_q[ RD_QUEUE ].name #define WR_NAME Test_q[ WR_QUEUE ].name #define BLOCKING_NAME Test_q[ BLOCKING ].name #define CLOSED_NAME Test_q[ CLOSED ].name #define RW_ATTR Test_q[ RW_QUEUE ].oflag #define DEFAULT_ATTR Test_q[ DEFAULT_RW ].oflag #define RD_ATTR Test_q[ RD_QUEUE ].oflag #define WR_ATTR Test_q[ WR_QUEUE ].oflag #define BLOCK_ATTR Test_q[ BLOCKING ].oflag #define CLOSED_ATTR Test_q[ CLOSED ].oflag /* * Outputs a header at each test section. */ void Start_Test( char *description ) { printf( "_______________%s\n", description ); } void Validate_attributes( mqd_t mq, int oflag, int msg_count ) { int status; struct mq_attr attr; status = mq_getattr( mq, &attr ); fatal_posix_service_status( status, 0, "mq_getattr valid return status"); if ( mq != Test_q[ DEFAULT_RW ].mq ){ fatal_int_service_status((int)attr.mq_maxmsg, MAXMSG, "maxmsg attribute" ); fatal_int_service_status((int)attr.mq_msgsize,MSGSIZE,"msgsize attribute"); } fatal_int_service_status((int)attr.mq_curmsgs, msg_count, "count attribute" ); fatal_int_service_status((int)attr.mq_flags, oflag, "flag attribute" ); } #define Get_Queue_Name( i ) Test_q[i].name char *Build_Queue_Name( int i ) { static char Queue_Name[PATH_MAX + 2]; sprintf(Queue_Name,"mq%d", i+1 ); return Queue_Name; } void open_test_queues(void) { struct mq_attr attr; int status; Test_queue_type *tq; int que; attr.mq_maxmsg = MAXMSG; attr.mq_msgsize = MSGSIZE; puts( "Init: Open Test Queues" ); for( que = 0; que < NUMBER_OF_TEST_QUEUES+1; que++ ) { tq = &Test_q[ que ]; if ( que == DEFAULT_RW) Test_q[que].mq = mq_open( tq->name, tq->oflag, 0x777, NULL ); else Test_q[que].mq = mq_open( tq->name, tq->oflag, 0x777, &attr ); assert( Test_q[que].mq != (-1) ); } status = mq_close( Test_q[NUMBER_OF_TEST_QUEUES].mq ); fatal_posix_service_status( status, 0, "mq_close duplicate message queue"); status = mq_close( Test_q[CLOSED].mq ); fatal_posix_service_status( status, 0, "mq_close message queue"); status = mq_unlink( CLOSED_NAME ); fatal_posix_service_status( status, 0, "mq_unlink message queue"); } /* * Opens CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES then leaves size queues * opened but closes the rest. */ void validate_mq_open_error_codes(void) { int i; mqd_t n_mq2; struct mq_attr attr; int status; mqd_t open_mq[CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES + 1]; attr.mq_maxmsg = MAXMSG; attr.mq_msgsize = MSGSIZE; Start_Test( "mq_open errors" ); /* * XXX EINVAL - inappropriate name was given for the message queue */ /* * EINVAL - Create with negative maxmsg. */ attr.mq_maxmsg = -1; puts( "Init: mq_open - Create with maxmsg (-1) (EINVAL)" ); n_mq2 = mq_open( "mq2", O_CREAT | O_RDONLY, 0x777, &attr); fatal_posix_service_pointer_minus_one( (void *)n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, EINVAL, "mq_open errno EINVAL"); attr.mq_maxmsg = MAXMSG; /* * EINVAL - Create withnegative msgsize. */ attr.mq_msgsize = -1; puts( "Init: mq_open - Create with msgsize (-1) (EINVAL)" ); n_mq2 = mq_open( "mq2", O_CREAT | O_RDONLY, 0x777, &attr); fatal_posix_service_pointer_minus_one( (void *) n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, EINVAL, "mq_open errno EINVAL"); attr.mq_msgsize = MSGSIZE; /* * ENOENT - Open a non-created file. */ puts( "Init: mq_open - Open new mq without create flag (ENOENT)" ); n_mq2 = mq_open( "mq3", O_EXCL | O_RDONLY, 0x777, NULL); fatal_posix_service_pointer_minus_one( (void *) n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, ENOENT, "mq_open errno ENOENT"); /* * XXX EINTR - call was interrupted by a signal */ /* * ENAMETOOLONG - Give a name greater than PATH_MAX. */ puts( "Init: mq_open - Open with too long of a name (ENAMETOOLONG)" ); n_mq2 = mq_open( Get_Too_Long_Name(), O_CREAT | O_RDONLY, 0x777, NULL ); fatal_posix_service_pointer_minus_one( (void *) n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, ENAMETOOLONG, "mq_open errno ENAMETOOLONG"); /* * XXX - ENAMETOOLONG - Give a name greater than NAME_MAX * Per implementation not possible. */ /* * EEXIST - Create an existing queue. */ puts( "Init: mq_open - Create an Existing mq (EEXIST)" ); open_mq[0] = mq_open( Build_Queue_Name(0), O_CREAT | O_RDWR | O_NONBLOCK, 0x777, NULL ); assert( open_mq[0] != (-1) ); n_mq2 = mq_open( Build_Queue_Name(0), O_CREAT | O_EXCL | O_RDONLY, 0x777, NULL); fatal_posix_service_pointer_minus_one( (void *) n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, EEXIST, "mq_open errno EEXIST"); status = mq_unlink( Build_Queue_Name(0) ); fatal_posix_service_status( status, 0, "mq_unlink message queue"); status = mq_close( open_mq[0]); fatal_posix_service_status( status, 0, "mq_close message queue"); /* * Open maximum number of message queues */ puts( "Init: mq_open - SUCCESSFUL" ); for (i = 0; i < CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES; i++) { open_mq[i] = mq_open( Build_Queue_Name(i), O_CREAT | O_RDWR | O_NONBLOCK, 0x777, NULL ); assert( open_mq[i] != (-1) ); assert( open_mq[i] ); /*XXX - Isn't there a more general check */ /* JRS printf( "mq_open 0x%x %s\n", open_mq[i], Build_Queue_Name(i) ); */ } /* * XXX EACCES - permission to create is denied. */ /* * XXX EACCES - queue exists permissions specified by o_flag are denied. */ /* * XXX EMFILE - Too many message queues in use by the process */ /* * ENFILE - Too many message queues open in the system */ puts( "Init: mq_open - system is out of resources (ENFILE)" ); n_mq2 = mq_open( Build_Queue_Name(i), O_CREAT | O_RDONLY, 0x777, NULL ); fatal_posix_service_pointer_minus_one( (void *) n_mq2, "mq_open error return status" ); fatal_posix_service_status( errno, ENFILE, "mq_open errno ENFILE"); /* * Unlink and Close all queues. */ puts( "Init: mq_close and mq_unlink (mq3...mqn) - SUCCESSFUL" ); for (i = 0; i < CONFIGURE_MAXIMUM_POSIX_MESSAGE_QUEUES; i++) { status = mq_close( open_mq[i]); fatal_posix_service_status( status, 0, "mq_close message queue"); status = mq_unlink( Build_Queue_Name(i) ); if ( status == -1 ) perror( "mq_unlink" ); fatal_posix_service_status( status, 0, "mq_unlink message queue"); /* JRS printf( "mq_close/mq_unlink 0x%x %s\n", open_mq[i], Build_Queue_Name(i) ); */ } } void validate_mq_unlink_error_codes(void) { int status; Start_Test( "mq_unlink errors" ); /* * XXX - EACCES Permission Denied */ /* * ENAMETOOLONG - Give a name greater than PATH_MAX. */ puts( "Init: mq_unlink - mq_unlink with too long of a name (ENAMETOOLONG)" ); status = mq_unlink( Get_Too_Long_Name() ); fatal_posix_service_status( status, -1, "mq_unlink error return status"); fatal_posix_service_status( errno, ENAMETOOLONG, "mq_unlink errno ENAMETOOLONG"); /* * XXX - ENAMETOOLONG - Give a name greater than NAME_MAX * Per implementation not possible. */ /* * ENOENT - Unlink an unopened queue */ puts( "Init: mq_unlink - A Queue not opened (ENOENT)" ); status = mq_unlink( CLOSED_NAME ); fatal_posix_service_status( status, -1, "mq_unlink error return status"); fatal_posix_service_status( errno, ENOENT, "mq_unlink errno ENOENT"); /* * XXX - The following were not listed in the POSIX document as * possible errors. Under other commands the EINVAL is * given for these conditions. */ /* * EINVAL - Unlink a queue with no name */ puts( "Init: mq_unlink (NULL) - EINVAL" ); status = mq_unlink( NULL ); fatal_posix_service_status( status, -1, "mq_unlink error return status"); fatal_posix_service_status( errno, EINVAL, "mq_unlink errno value"); /* * EINVAL - Unlink a queue with a null name */ puts( "Init: mq_unlink (\"\") - EINVAL" ); status = mq_unlink( "" ); fatal_posix_service_status( status, -1, "mq_unlink error return status"); fatal_posix_service_status( errno, EINVAL, "mq_unlink errno value"); } void validate_mq_close_error_codes(void) { int status; Start_Test( "mq_close errors" ); /* * EBADF - Close a queue that is not open. */ puts( "Init: mq_close - unopened queue (EBADF)" ); status = mq_close( Test_q[CLOSED].mq ); fatal_posix_service_status( status, -1, "mq_close error return status"); fatal_posix_service_status( errno, EBADF, "mq_close errno EBADF"); } void validate_mq_getattr_error_codes(void) { struct mq_attr attr; int status; Start_Test( "mq_getattr errors" ); /* * EBADF - Get the attributes from a closed queue. */ puts( "Init: mq_getattr - unopened queue (EBADF)" ); status = mq_getattr( Test_q[CLOSED].mq, &attr ); fatal_posix_service_status( status, -1, "mq_close error return status"); fatal_posix_service_status( errno, EBADF, "mq_close errno EBADF"); /* * XXX - The following are not listed in the POSIX manual but * may occur. */ /* * EINVAL - NULL attributes */ puts( "Init: mq_getattr - NULL attributes (EINVAL)" ); status = mq_getattr( Test_q[RW_QUEUE].mq, NULL ); fatal_posix_service_status( status, -1, "mq_close error return status"); fatal_posix_service_status( errno, EINVAL, "mq_close errno EINVAL"); } void Send_msg_to_que( int que, int msg ) { Test_Message_t *ptr = &Predefined_Msgs[msg]; int status; status = mq_send( Test_q[que].mq, ptr->msg, ptr->size , ptr->priority ); fatal_posix_service_status( status, 0, "mq_send valid return status"); Test_q[que].count++; } void Show_send_msg_to_que( char *task_name, int que, int msg ) { Test_Message_t *ptr = &Predefined_Msgs[msg]; printf( "%s mq_send - to %s msg: %s priority %d\n", task_name, Test_q[que].name, ptr->msg, ptr->priority); Send_msg_to_que( que, msg ); } void verify_queues_full( char *task_name ) { int que; /* * Validate that the queues are full. */ printf( "%s Verify Queues are full\n", task_name ); for( que = RW_QUEUE; que < CLOSED; que++ ) Validate_attributes( Test_q[que].mq, Test_q[que].oflag, Test_q[que].count ); } void verify_queues_empty( char *task_name ) { int que; printf( "%s Verify Queues are empty\n", task_name ); for( que = RW_QUEUE; que < CLOSED; que++ ) Validate_attributes( Test_q[que].mq, Test_q[que].oflag, 0 ); } int fill_message_queues( char *task_name ) { int msg; int que; verify_queues_empty( task_name ); /* * Fill Queue with predefined messages. */ printf( "%s Fill Queues with messages\n", task_name ); for(msg=0; msgmsg ); fatal_int_service_status( status, ptr->size, err_msg ); assert( !strcmp( message, ptr->msg ) ); strcpy( message, "No Message" ); sprintf( err_msg,"%s msg %s size failure", Test_q[ que ].name, ptr->msg ); fatal_int_service_status(priority, ptr->priority, err_msg ); } int empty_message_queues( char *task_name ) { int que; int i; printf( "%s Empty all Queues\n", task_name ); for( que = RW_QUEUE; que < CLOSED; que++ ) { for(i=0; Test_q[que].count != 0; i++ ) Read_msg_from_que( que, Priority_Order[i] ); Validate_attributes( Test_q[ que].mq, Test_q[ que ].oflag, 0 ); } return 0; } /* * Returns the number of messages queued after the test on the * first queue. */ int validate_mq_send_error_codes(void) { int status; int i; char *str; Start_Test( "mq_send errors" ); /* * EBADF - Write to a closed queue. */ puts( "Init: mq_send - Closed message queue (EBADF)" ); status = mq_send( Test_q[CLOSED].mq, "", 1, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EBADF, "mq_send errno EBADF"); /* * EBADF - Write to a read only queue. */ puts( "Init: mq_send - Read only message queue (EBADF)" ); status = mq_send( Test_q[ RD_QUEUE ].mq, "", 1, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EBADF, "mq_send errno EBADF"); /* * XXX - EINTR Signal interrupted the call. * puts( "Init: mq_send - UNSUCCESSFUL (EINTR)" ); status = mq_send( Test_q, "", 0xffff, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, E, "mq_send errno E"); */ /* * EINVAL priority is out of range. */ puts( "Init: mq_send - Priority out of range (EINVAL)" ); status = mq_send( Test_q[ RW_QUEUE ].mq, "", 1, MQ_PRIO_MAX + 1 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EINVAL, "mq_send errno EINVAL"); /* * EMSGSIZE - Message size larger than msg_len * Validates that msgsize is stored correctly. */ puts( "Init: mq_send - Message longer than msg_len (EMSGSIZE)" ); status = mq_send( Test_q[ RW_QUEUE ].mq, "", MSGSIZE+1, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EMSGSIZE, "mq_send errno EMSGSIZE"); i = fill_message_queues( "Init:" ); /* * ENOSYS - send not supported puts( "Init: mq_send - Blocking Queue overflow (ENOSYS)" ); status = mq_send( n_mq1, Predefined_Msgs[i], 0, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EBADF, "mq_send errno EBADF"); status = mq_close( n_mq1 ); fatal_posix_service_status( status, 0, "mq_close message queue"); status = mq_unlink( "read_only" ); fatal_posix_service_status( status, 0, "mq_unlink message queue"); */ /* * EAGAIN - O_NONBLOCK and message queue is full. */ puts( "Init: mq_send - on a FULL non-blocking queue with (EAGAIN)" ); str = Predefined_Msgs[i].msg; status = mq_send(Test_q[RW_QUEUE].mq, str, 0, 0 ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EAGAIN, "mq_send errno EAGAIN"); return i-1; } void validate_mq_receive_error_codes(void) { int status; char message[100]; unsigned int priority; Start_Test( "mq_receive errors" ); /* * EBADF - Not A Valid Message Queue */ puts( "Init: mq_receive - Unopened message queue (EBADF)" ); status = mq_receive( Test_q[CLOSED].mq, message, 100, &priority ); fatal_posix_service_status( status, -1, "mq_ error return status"); fatal_posix_service_status( errno, EBADF, "mq_receive errno EBADF"); /* * EBADF - Queue not opened to read */ puts( "Init: mq_receive - Write only queue (EBADF)" ); status = mq_receive( Test_q[WR_QUEUE].mq, message, 100, &priority ); fatal_posix_service_status( status, -1, "mq_ error return status"); fatal_posix_service_status( errno, EBADF, "mq_receive errno EBADF"); /* * EMSGSIZE - Size is less than the message size attribute */ puts( "Init: mq_receive - Size is less than the message (EMSGSIZE)" ); status = mq_receive( Test_q[RW_QUEUE].mq, message, Predefined_Msgs[0].size-1, &priority ); fatal_posix_service_status( status, -1, "mq_ error return status"); fatal_posix_service_status( errno, EMSGSIZE, "mq_receive errno EMSGSIZE"); /* * EAGAIN - O_NONBLOCK and Queue is empty */ verify_queues_full( "Init:" ); empty_message_queues( "Init:" ); puts( "Init: mq_receive - Queue is empty (EAGAIN)" ); status = mq_receive( Test_q[RW_QUEUE].mq, message, 100, &priority ); fatal_posix_service_status( status, -1, "mq_ error return status"); fatal_posix_service_status( errno, EAGAIN, "mq_receive errno EAGAIN"); /* * XXX - EINTR - Interrupted by a signal */ /* * XXX - EBADMSG - a data corruption problem. */ /* * XXX - ENOSYS - mq_receive not supported */ } void verify_open_functionality(void) { #if 0 mqd_t n_mq; #endif Start_Test( "mq_open functionality" ); /* * Validate a second open returns the same message queue. */ #if 0 puts( "Init: mq_open - Open an existing mq ( same id )" ); n_mq = mq_open( RD_NAME, 0 ); fatal_posix_service_status( assert( n_mq == Test_q[RD_QUEUE].mq ); #endif } void verify_unlink_functionality(void) { mqd_t n_mq; int status; Start_Test( "mq_unlink functionality" ); /* * Unlink the message queue, then verify an open of the same name produces a * different message queue. */ puts( "Init: Unlink and Open without closing SUCCESSFUL" ); status = mq_unlink( DEFAULT_NAME ); fatal_posix_service_status( status, 0, "mq_unlink locked message queue"); n_mq = mq_open( DEFAULT_NAME, DEFAULT_ATTR, 0x777, NULL ); assert( n_mq != (-1) ); assert( n_mq != Test_q[ DEFAULT_RW ].mq ); status = mq_unlink( DEFAULT_NAME ); fatal_posix_service_status( status, 0, "mq_unlink locked message queue"); status = mq_close( Test_q[ DEFAULT_RW ].mq ); fatal_posix_service_status( status, 0, "mq_close message queue"); Test_q[ DEFAULT_RW ].mq = n_mq; } void verify_close_functionality(void) { int i; int status; Start_Test( "Unlink and Close All Files" ); for (i=0; imsg, ptr->size , ptr->priority ); fatal_posix_service_status( status, -1, "mq_send error return status"); fatal_posix_service_status( errno, EBADF, "mq_send errno EBADF"); } void validate_mq_setattr(void) { struct mq_attr attr; struct mq_attr save_attr[ NUMBER_OF_TEST_QUEUES ]; int status; int i; /* * EBADF - Get the attributes from a closed queue. */ puts( "Task1:mq_setattr - unopened queue (EBADF)" ); status = mq_setattr( Test_q[CLOSED].mq, &attr, NULL ); fatal_posix_service_status( status, -1, "mq_setattr error return status"); fatal_posix_service_status( errno, EBADF, "mq_setattr errno EBADF"); /* * XXX - The following are not listed in the POSIX manual but * may occur. */ /* * EINVAL - NULL attributes */ puts( "Task1:mq_setattr - NULL attributes (EINVAL)" ); status = mq_setattr( Test_q[RW_QUEUE].mq, NULL, NULL ); fatal_posix_service_status( status, -1, "mq_setattr error return status"); fatal_posix_service_status( errno, EINVAL, "mq_setattr errno EINVAL"); /* * Verify change queues to blocking, by verifying all queues block * for a timed receive. */ puts( "Init: set_attr all queues to blocking" ); for(i=0; i