Mercurial > ecos
changeset 2468:c827f551d093
* tests/tm_basic.cxx: Rename test to tm_posix.cxx.
* tests/mqueue1.c: Rename test to pmqueue1.c.
* tests/mqueue2.c: Rename test to pmqueue2.c.
* tests/mutex3.c: Rename test to pmutex3.c.
* cdl/posix.cdl: Accommodate the above renaming. Test names must be
globally unique.
| author | jld |
|---|---|
| date | Fri, 28 Mar 2008 09:49:51 +0000 |
| parents | b75acb19f177 |
| children | a62211ae5f94 |
| files | packages/compat/posix/current/ChangeLog packages/compat/posix/current/cdl/posix.cdl packages/compat/posix/current/tests/mqueue1.c packages/compat/posix/current/tests/mqueue2.c packages/compat/posix/current/tests/mutex3.c packages/compat/posix/current/tests/pmqueue1.c packages/compat/posix/current/tests/pmqueue2.c packages/compat/posix/current/tests/pmutex3.c packages/compat/posix/current/tests/tm_basic.cxx packages/compat/posix/current/tests/tm_posix.cxx |
| diffstat | 10 files changed, 3034 insertions(+), 3024 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/compat/posix/current/ChangeLog +++ b/packages/compat/posix/current/ChangeLog @@ -1,3 +1,12 @@ +2008-03-28 John Dallaway <jld@ecoscentric.com> + + * tests/tm_basic.cxx: Rename test to tm_posix.cxx. + * tests/mqueue1.c: Rename test to pmqueue1.c. + * tests/mqueue2.c: Rename test to pmqueue2.c. + * tests/mutex3.c: Rename test to pmutex3.c. + * cdl/posix.cdl: Accommodate the above renaming. Test names must be + globally unique. + 2007-06-12 Richard.Yuan <lemonskin@tom.com> * src/except.cxx (install_handlers): Fixed typo. Bug #1000373
--- a/packages/compat/posix/current/cdl/posix.cdl +++ b/packages/compat/posix/current/cdl/posix.cdl @@ -9,6 +9,7 @@ ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +## Copyright (C) 2008 eCosCentric Limited ## ## eCos is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free @@ -338,8 +339,8 @@ cdl_package CYGPKG_POSIX { calculated { (CYGPKG_POSIX_PTHREAD ? "tests/pthread1 tests/pthread2 tests/pthread3 " : "") . - (CYGPKG_POSIX_PTHREAD_MUTEX ? "tests/mutex3 " : "") . - (CYGPKG_POSIX_MQUEUES ? "tests/mqueue1 tests/mqueue2 " : "") . + (CYGPKG_POSIX_PTHREAD_MUTEX ? "tests/pmutex3 " : "") . + (CYGPKG_POSIX_MQUEUES ? "tests/pmqueue1 tests/pmqueue2 " : "") . (CYGPKG_POSIX_SIGNALS ? "tests/signal1 tests/signal2 tests/signal3 \ tests/sigsetjmp " : "") . ((CYGPKG_POSIX_SIGNALS && @@ -348,7 +349,7 @@ cdl_package CYGPKG_POSIX { ((CYGPKG_POSIX_SIGNALS && CYGPKG_POSIX_TIMERS && CYGPKG_POSIX_PTHREAD && - CYGPKG_POSIX_SEMAPHORES) ? "tests/tm_basic " : "") + CYGPKG_POSIX_SEMAPHORES) ? "tests/tm_posix " : "") } description " This option specifies the set of tests for the POSIX package."
deleted file mode 100644 --- a/packages/compat/posix/current/tests/mqueue1.c +++ /dev/null @@ -1,359 +0,0 @@ -/*======================================================================== -// -// mqueue1.c -// -// POSIX Message queues tests -// -//======================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//======================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): jlarmour -// Contributors: -// Date: 2000-05-18 -// Purpose: This file provides tests for POSIX mqueues -// Description: -// Usage: -// -//####DESCRIPTIONEND#### -// -//====================================================================== -*/ - -/* CONFIGURATION */ - -#include <pkgconf/posix.h> - -#ifndef CYGPKG_POSIX_MQUEUES -# define NA_MSG "Message queues not configured" -#endif - -#ifdef NA_MSG -#include <cyg/infra/testcase.h> // test API -void -cyg_user_start(void) -{ - CYG_TEST_NA( NA_MSG ); -} - -#else - -/* INCLUDES */ - -#include <fcntl.h> // O_* -#include <errno.h> // errno -#include <sys/stat.h> // file modes -#include <mqueue.h> // Mqueue Header -#include <cyg/infra/testcase.h> // test API - -/* FUNCTIONS */ - -static int -my_memcmp(const void *m1, const void *m2, size_t n) -{ - char *s1 = (char *)m1; - char *s2 = (char *)m2; - - while (n--) { - if (*s1 != *s2) - return *s1 - *s2; - s1++; - s2++; - } - return 0; -} // my_memcmp() - -//************************************************************************ - -int -main(void) -{ - mqd_t q1, q2; - char buf[20]; - ssize_t recvlen; - unsigned int prio; - struct mq_attr attr, oattr; - mode_t mode; - int err; - - CYG_TEST_INIT(); - CYG_TEST_INFO( "Starting POSIX message test 1" ); - - q1 = mq_open( "/mq1", O_RDWR ); - CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" ); - CYG_TEST_PASS_FAIL( ENOENT == errno, - "errno correct for non-existent queue" ); - - attr.mq_flags = 0; - attr.mq_maxmsg = 4; - attr.mq_msgsize = 20; - mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all - - q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_WRONLY, mode, &attr ); - CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" ); - - err = mq_getattr( q1, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY != (attr.mq_flags & O_RDONLY)) && - (O_WRONLY == (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (0 == attr.mq_curmsgs ), "getattr attributes correct" ); - - err = mq_send( q1, "Vik is brill", sizeof("Vik is brill"), 10 ); - - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_send" ); - - err = mq_getattr( q1, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY != (attr.mq_flags & O_RDONLY)) && - (O_WRONLY == (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (1 == attr.mq_curmsgs ), - "getattr attributes correct #2" ); - - q2 = mq_open( "/mq1", O_RDONLY|O_CREAT|O_EXCL ); - CYG_TEST_PASS_FAIL( q2 == (mqd_t)-1, - "error for exclusive open of existing queue" ); - CYG_TEST_PASS_FAIL( EEXIST == errno, - "errno correct for exclusive open of existing queue" ); - - q2 = mq_open( "/mq1", O_RDONLY ); - CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "simple mq_open (read only)" ); - - err = mq_getattr( q2, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY == (attr.mq_flags & O_RDONLY)) && - (O_WRONLY != (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (1 == attr.mq_curmsgs ), - "getattr attributes correct #3" ); - - err = mq_close( q2 ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_close" ); - - q2 = mq_open( "/mq1", O_RDONLY ); - CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "mq_open reopen (read only)" ); - - err = mq_getattr( q2, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY == (attr.mq_flags & O_RDONLY)) && - (O_WRONLY != (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (1 == attr.mq_curmsgs ), - "getattr attributes correct #4" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is brill"), - "receive message length" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is brill", - sizeof("Vik is brill")), - "received message data intact" ); - CYG_TEST_PASS_FAIL( 10 == prio, "received at correct priority" ); - - err = mq_getattr( q1, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY != (attr.mq_flags & O_RDONLY)) && - (O_WRONLY == (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (0 == attr.mq_curmsgs ), - "getattr attributes correct #5" ); - - attr.mq_flags |= O_NONBLOCK; - err = mq_setattr( q2, &attr, &oattr ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_setattr O_NONBLOCK" ); - CYG_TEST_PASS_FAIL( (4 == oattr.mq_maxmsg) && - (20 == oattr.mq_msgsize) && - (O_NONBLOCK != (oattr.mq_flags & O_NONBLOCK)) && - (O_RDONLY == (oattr.mq_flags & O_RDONLY)) && - (O_WRONLY != (oattr.mq_flags & O_WRONLY)) && - (O_RDWR != (oattr.mq_flags & O_RDWR)) && - (0 == oattr.mq_curmsgs ), - "old attribute correct" ); - err = mq_getattr( q2, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after O_NONBLOCK" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY == (attr.mq_flags & O_RDONLY)) && - (O_WRONLY != (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (0 == attr.mq_curmsgs ), - "new attribute correct" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, - "mq_receive, empty buffer, non-blocking" ); - CYG_TEST_PASS_FAIL( EAGAIN == errno, - "errno correct for non-blocking" ); - - err = mq_send( q2, "foo", sizeof("foo"), 1 ); - CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send on read-only descriptor" ); - CYG_TEST_PASS_FAIL( EBADF == errno, - "errno correct for mq_send on r/o descriptor" ); - - err = mq_send( q2, "supercalifragilisticexpealidocious", 21, 2 ); - CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send (message too long)" ); - CYG_TEST_PASS_FAIL( EMSGSIZE == errno, - "errno correct for mq_send (message too long)" ); - - err = mq_send( q1, "", sizeof(""), 5 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send \"\"" ); - - err = mq_send( q1, "I love Vik", sizeof("I love Vik"), 7 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send (different priority)" ); - - err = mq_send( q1, "a lot!", sizeof("a lot!"), 7 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send (same priority)" ); - - err = mq_send( q1, "Vik is a babe", sizeof("Vik is a babe"), 6 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send (middle priority)" ); - - err = mq_send( q1, "wibble", sizeof("wibble"), 6 ); - CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send with full queue" ); - CYG_TEST_PASS_FAIL( EAGAIN == errno, - "errno correct for mq_send full queue" ); - - err = mq_getattr( q2, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after sends" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDONLY == (attr.mq_flags & O_RDONLY)) && - (O_WRONLY != (attr.mq_flags & O_WRONLY)) && - (O_RDWR != (attr.mq_flags & O_RDWR)) && - (4 == attr.mq_curmsgs ), - "getattr attributes correct #5" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == sizeof("I love Vik"), - "receive message length (prioritized) #1" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "I love Vik", - sizeof("I love Vik")), - "received message data intact (prioritized) #1" ); - CYG_TEST_PASS_FAIL( 7 == prio, - "received at correct priority (prioritized) #1" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == sizeof("a lot!"), - "receive message length (prioritized) #2" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "a lot!", - sizeof("a lot!")), - "received message data intact (prioritized) #2" ); - CYG_TEST_PASS_FAIL( 7 == prio, - "received at correct priority (prioritized) #2" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is a babe"), - "receive message length (prioritized) #3" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is a babe", - sizeof("Vik is a babe")), - "received message data intact (prioritized) #3" ); - CYG_TEST_PASS_FAIL( 6 == prio, - "received at correct priority (prioritized) #3" ); - - recvlen = mq_receive( q2, buf, 0, &prio ); - CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, - "mq_receive, zero-sized buffer" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == sizeof(""), - "receive message length (prioritized) #4" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "", - sizeof("")), - "received message data intact (prioritized) #4" ); - CYG_TEST_PASS_FAIL( 5 == prio, - "received at correct priority (prioritzed) #4" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, - "mq_receive, empty buffer, non-blocking #2" ); - CYG_TEST_PASS_FAIL( EAGAIN == errno, - "errno correct for non-blocking #2" ); - - err = mq_send( q1, "12345678901234567890", 20, 15 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send (before closing)" ); - - err = mq_unlink( "/foo" ); - CYG_TEST_PASS_FAIL( -1 == err, "mq_unlink (wrong name)" ); - CYG_TEST_PASS_FAIL( ENOENT == errno, - "errno correct for mq_unlink (wrong name)" ); - - err = mq_unlink( "/mq1" ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink (before closing)" ); - - err = mq_close( q1 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_close (send descriptor)" ); - - recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); - CYG_TEST_PASS_FAIL( recvlen == 20, - "receive message length (mid close)" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "12345678901234567890", 20 ), - "received message data intact (mid close)" ); - CYG_TEST_PASS_FAIL( 15 == prio, - "received at correct priority (mid close)" ); - - err = mq_close( q2 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_close (receive descriptor)" ); - - q1 = mq_open( "/mq1", O_RDONLY ); - CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" ); - CYG_TEST_PASS_FAIL( ENOENT == errno, - "errno correct for non-existent queue" ); - - CYG_TEST_EXIT("POSIX message test 1"); - - return 0; -} // main() - -//------------------------------------------------------------------------ - -#endif - -/* EOF mqueue1.c */
deleted file mode 100644 --- a/packages/compat/posix/current/tests/mqueue2.c +++ /dev/null @@ -1,276 +0,0 @@ -/*======================================================================== -// -// mqueue2.c -// -// POSIX Message queues tests - mq_notify -// -//======================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//======================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): jlarmour -// Contributors: -// Date: 2000-05-18 -// Purpose: This file provides tests for POSIX mqueue mq_notify -// Description: -// Usage: -// -//####DESCRIPTIONEND#### -// -//====================================================================== -*/ - -/* CONFIGURATION */ - -#include <pkgconf/posix.h> - -#ifndef CYGPKG_POSIX_MQUEUES -# define NA_MSG "Message queues not configured" -#elif !defined(CYGPKG_POSIX_SIGNALS) -# define NA_MSG "No POSIX signals configured" -#endif - -#ifdef NA_MSG -#include <cyg/infra/testcase.h> // test API -void -cyg_user_start(void) -{ - CYG_TEST_INIT(); - CYG_TEST_NA( NA_MSG ); -} - -#else - -/* INCLUDES */ - -#include <fcntl.h> // O_* -#include <errno.h> // errno -#include <sys/stat.h> // file modes -#include <mqueue.h> // Mqueue Header -#include <cyg/infra/testcase.h> // test API -#include <signal.h> // signals - -/* GLOBALS */ -sig_atomic_t signals=0; -char buf[20]; -unsigned int prio; - - -/* FUNCTIONS */ - -static int -my_memcmp(const void *m1, const void *m2, size_t n) -{ - char *s1 = (char *)m1; - char *s2 = (char *)m2; - - while (n--) { - if (*s1 != *s2) - return *s1 - *s2; - s1++; - s2++; - } - return 0; -} // my_memcmp() - -static char * -my_strcpy(char *s1, const char *s2) -{ - char *s = s1; - while (*s2) { - *s1++ = *s2++; - } - return s; -} // my_strcpy() - -static size_t -my_strlen(const char *s) -{ - const char *start = s; - while (*s) - s++; - return (s - start); -} // my_strcpy() - - - -//************************************************************************ - -static void -sigusr1_handler( int signo, siginfo_t *info, void *context ) -{ - ssize_t recvlen; - char mybuf[20]; - unsigned int myprio; - mqd_t *q = (mqd_t *)info->si_value.sival_ptr; - - CYG_TEST_PASS_FAIL( SIGUSR1 == signo, "correct signal number #1" ); - CYG_TEST_PASS_FAIL( SIGUSR1 == info->si_signo, "correct signal number #2" ); - CYG_TEST_PASS_FAIL( SI_MESGQ == info->si_code, "correct signal code" ); - - signals++; - - // retrieve message and compare with buf - recvlen = mq_receive( *q, mybuf, sizeof(mybuf), &myprio ); - CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), - "receive message length" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), - "received message data intact" ); - CYG_TEST_PASS_FAIL( prio == myprio, - "received at correct priority" ); -} - -//************************************************************************ - -int -main(void) -{ - mqd_t q1; - struct mq_attr attr; - mode_t mode; - int err; - ssize_t recvlen; - char mybuf[20]; - unsigned int myprio; - struct sigevent ev; - struct sigaction act; - - CYG_TEST_INIT(); - CYG_TEST_INFO( "Starting POSIX message test 2" ); - -#if 0 - if ( 0 != pthread_create( &thr, NULL, &thread, NULL ) ) { - CYG_TEST_FAIL_FINISH( "Couldn't create a helper thread" ); - } -#endif - - attr.mq_flags = 0; - attr.mq_maxmsg = 4; - attr.mq_msgsize = 20; - mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all - - q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_RDWR, mode, &attr ); - CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" ); - - err = mq_getattr( q1, &attr ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" ); - CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && - (20 == attr.mq_msgsize) && - (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && - (O_RDWR == (attr.mq_flags & O_RDWR)) && - (0 == attr.mq_curmsgs ), "getattr attributes correct" ); - - - act.sa_sigaction = &sigusr1_handler; - sigfillset( &act.sa_mask ); // enable all signals - act.sa_flags = SA_SIGINFO; - - if ( 0 != sigaction( SIGUSR1, &act, NULL ) ) { - CYG_TEST_FAIL_FINISH( "Couldn't register signal handler" ); - } - - ev.sigev_notify = SIGEV_SIGNAL; - ev.sigev_signo = SIGUSR1; - ev.sigev_value.sival_ptr = (void *)&q1; - - err = mq_notify( q1, &ev ); - CYG_TEST_PASS_FAIL( 0 == err, "simple mq_notify" ); - - my_strcpy( buf, "Vik is the best" ); - prio = 7; - err = mq_send( q1, buf, my_strlen(buf), prio ); - - CYG_TEST_PASS_FAIL( 0 == err, "mq_send #1" ); - - CYG_TEST_PASS_FAIL( 1 == signals, "got notification" ); - - my_strcpy( buf, "Scrummy Vik" ); - prio = 6; - err = mq_send( q1, buf, my_strlen(buf), prio ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" ); - - CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification" ); - - recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio ); - CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), - "receive message length" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), - "received message data intact" ); - CYG_TEST_PASS_FAIL( prio == myprio, - "received at correct priority" ); - - err = mq_notify( q1, &ev ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_notify #2" ); - - err = mq_notify( q1, &ev ); - CYG_TEST_PASS_FAIL( -1 == err, "second mq_notify returns error" ); - CYG_TEST_PASS_FAIL( EBUSY == errno, - "errno correct for second mq_notify error" ); - - err = mq_notify( q1, NULL ); - CYG_TEST_PASS_FAIL( 0 == err, "clear notification" ); - - my_strcpy( buf, "Vik is k3wl" ); - prio = 8; - err = mq_send( q1, buf, my_strlen(buf), prio ); - - CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" ); - - CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification #2" ); - - recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio ); - CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), - "receive message length" ); - CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), - "received message data intact" ); - CYG_TEST_PASS_FAIL( prio == myprio, - "received at correct priority" ); - - err = mq_close( q1 ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_close" ); - - err = mq_unlink( "/mq1" ); - CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink" ); - - CYG_TEST_EXIT("POSIX message test 2"); - - return 0; -} // main() - -//------------------------------------------------------------------------ - -#endif - -/* EOF mqueue2.c */
deleted file mode 100644 --- a/packages/compat/posix/current/tests/mutex3.c +++ /dev/null @@ -1,672 +0,0 @@ -//========================================================================== -// -// mutex3.cxx -// -// Mutex test 3 - priority inheritance -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): hmt -// Contributors: hmt, nickg, jlarmour -// Date: 2000-01-06 -// Description: Tests mutex priority inheritance. This is simply a translation -// of the similarly named kernel test to the POSIX API -//####DESCRIPTIONEND#### - -// ------------------------------------------------------------------------ - -#include <cyg/infra/testcase.h> -#include <pkgconf/posix.h> -#include <pkgconf/system.h> -#ifdef CYGPKG_KERNEL -#include <pkgconf/kernel.h> -#endif - -#ifdef CYGPKG_ISOINFRA -# include <sys/types.h> -# include <pthread.h> -# include <semaphore.h> -# include <time.h> -# include <unistd.h> -#endif - -#if !defined(CYGPKG_POSIX_PTHREAD) -#define NA_MSG "POSIX threads not enabled" - -// ------------------------------------------------------------------------ -// -// These checks should be enough; any other scheduler which has priorities -// should manifest as having no priority inheritance, but otherwise fine, -// so the test should work correctly. - -#elif !defined(_POSIX_THREAD_PRIORITY_SCHEDULING) -#define NA_MSG "No POSIX thread priority scheduling enabled" -#elif !defined(_POSIX_THREAD_PRIO_INHERIT) -#define NA_MSG "No POSIX thread priority inheritance enabled" -#elif !defined(_POSIX_SEMAPHORES) -#define NA_MSG "No POSIX sempaphore support enabled enabled" -#elif !defined(CYGFUN_KERNEL_API_C) -#define NA_MSG "Kernel C API not enabled" -#elif defined(CYGPKG_KERNEL_SMP_SUPPORT) -#define NA_MSG "Test cannot run with SMP support" -#endif - -#ifdef NA_MSG -void -cyg_start(void) -{ - CYG_TEST_INIT(); - CYG_TEST_NA(NA_MSG); -} -#else - -#include <cyg/infra/cyg_ass.h> -#include <cyg/infra/cyg_trac.h> -#include <cyg/infra/diag.h> // diag_printf - -#include <cyg/kernel/kapi.h> // Some extras - -// ------------------------------------------------------------------------ -// Management functions -// -// Stolen from testaux.hxx and copied in here because I want to be able to -// reset the world also. -// ... and subsequently POSIXized out of all similarly with its progenitors. - -#define NTHREADS 7 - -#define STACKSIZE (PTHREAD_STACK_MIN*2) - -static pthread_t thread[NTHREADS] = { 0 }; - -typedef CYG_WORD64 CYG_ALIGNMENT_TYPE; - -static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ - (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) - / sizeof(CYG_ALIGNMENT_TYPE) ]; - -// Semaphores to halt execution of threads -static sem_t hold[NTHREADS]; - -// Flag to tell all threads to exit -static int all_exit; - -// Application thread data is passed here, the thread -// argument is -static CYG_ADDRWORD thread_data[NTHREADS]; - -static volatile int nthreads = 0; - -// Sleep for 1 tick... -static struct timespec sleeptime; - - -static pthread_t new_thread( void *(*entry)(void *), - CYG_ADDRWORD data, - int priority, - int do_resume) -{ - pthread_attr_t attr; - int _nthreads = nthreads++; - - struct sched_param schedparam; - schedparam.sched_priority = priority; - - pthread_attr_init( &attr ); - pthread_attr_setstackaddr( &attr, (void *)((char *)(&stack[_nthreads])+STACKSIZE) ); - pthread_attr_setstacksize( &attr, STACKSIZE ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - pthread_attr_setschedparam( &attr, &schedparam ); - - CYG_ASSERT(_nthreads < NTHREADS, - "Attempt to create more than NTHREADS threads"); - - thread_data[_nthreads] = data; - - sem_init( &hold[_nthreads], 0, do_resume ? 1 : 0 ); - all_exit = 0; - - pthread_create( &thread[_nthreads], - &attr, - entry, - (void *)_nthreads); - - return thread[_nthreads]; -} - - -static void kill_threads( void ) -{ - CYG_ASSERT(nthreads <= NTHREADS, - "More than NTHREADS threads"); - CYG_ASSERT( pthread_equal(pthread_self(),thread[0]), - "kill_threads() not called from thread 0"); - all_exit = 1; - while ( nthreads > 1 ) { - nthreads--; - if ( 0 != thread[nthreads] ) { - sem_post( &hold[nthreads] ); - pthread_cancel( thread[nthreads] ); - pthread_join( thread[nthreads], NULL ); - thread[nthreads] = 0; - sem_destroy( &hold[nthreads] ); - } - } - CYG_ASSERT(nthreads == 1, - "No threads left"); -} - -// ------------------------------------------------------------------------ - -#define DELAYFACTOR 1 // for debugging - -// ------------------------------------------------------------------------ - -pthread_mutex_t mutex; - -// These are for reporting back to the master thread -volatile int got_it = 0; -volatile int t3ran = 0; -volatile int t3ended = 0; -volatile int extras[4] = {0,0,0,0}; - -volatile int go_flag = 0; // but this one controls thread 3 from thread 2 - -// ------------------------------------------------------------------------ -// 0 to 3 of these run generally to interfere with the other processing, -// to cause multiple prio inheritances, and clashes in any orders. - -static void *extra_thread( void *arg ) -{ -#define XINFO( z ) \ - do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 ) - - static char running[] = "Extra thread Xa running"; - static char exiting[] = "Extra thread Xa exiting"; - static char resumed[] = "Extra thread Xa resumed"; - static char locked[] = "Extra thread Xa locked"; - static char unlocked[] = "Extra thread Xa unlocked"; - - int id = (int)arg; - CYG_ADDRWORD data = thread_data[id]; - - CYG_ASSERT( (id >= 4 && id <= 6), "extra_thread invalid id" ); - - // Emulate resume behaviour - sem_wait( &hold[id] ); - if( all_exit ) return 0; - - XINFO( running ); - - sem_wait( &hold[id] ); - - XINFO( resumed ); - - pthread_mutex_lock( &mutex ); - - XINFO( locked ); - - pthread_mutex_unlock( &mutex ); - - XINFO( unlocked ); - - extras[ data ] ++; - - XINFO( exiting ); - - return NULL; -} - -// ------------------------------------------------------------------------ - -static void *t1( void *arg ) -{ - int id = (int)arg; - //CYG_ADDRWORD data = thread_data[id]; - - // Emulate resume behaviour - sem_wait( &hold[id] ); - if( all_exit ) return 0; - - CYG_TEST_INFO( "Thread 1 running" ); - - sem_wait( &hold[id] ); - - pthread_mutex_lock( &mutex ); - - got_it++; - - CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" ); - - pthread_mutex_unlock( &mutex ); - - CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" ); - - // That's all. - - CYG_TEST_INFO( "Thread 1 exit" ); - - return 0; -} - -// ------------------------------------------------------------------------ - -static void *t2( void *arg ) -{ - int i; - int id = (int)arg; - CYG_ADDRWORD data = thread_data[id]; - cyg_tick_count_t now, then; - - // Emulate resume behaviour - sem_wait( &hold[id] ); - if( all_exit ) return 0; - - CYG_TEST_INFO( "Thread 2 running" ); - - CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" ); - CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" ); - - sem_wait( &hold[id] ); - - // depending on our config argument, optionally restart some of the - // extra threads to throw noise into the scheduler: - for ( i = 0; i < 3; i++ ) - if ( (1 << i) & data ) // bits 0-2 control - sem_post( &hold[i+4] ); // made sure extras are thread[4-6] - - // let those threads run - for( i = 0; i < DELAYFACTOR * 10; i++ ) - nanosleep( &sleeptime, NULL ); - - cyg_scheduler_lock(); // do this next lot atomically - - go_flag = 1; // unleash thread 3 - sem_post( &hold[1] ); // resume thread 1 - - // depending on our config argument, optionally restart some of the - // extra threads to throw noise into the scheduler at this later point: - for ( i = 4; i < 7; i++ ) - if ( (1 << i) & data ) // bits 4-6 control - sem_post( &hold[i] ); // made sure extras are thread[4-6] - - cyg_scheduler_unlock(); // let scheduling proceed - - // Need a delay (but not a CPU yield) to allow t3 to awaken and act on - // the go_flag, otherwise we check these details below too soon. - // Actually, waiting for the clock to tick a couple of times would be - // better, so that is what we will do. Must be a busy-wait. - then = cyg_current_time(); - do { - now = cyg_current_time(); - // Wait longer than the delay in t3 waiting on go_flag - } while ( now < (then + 3) ); - -#ifdef _POSIX_THREAD_PRIO_INHERIT - CYG_TEST_INFO( "Checking for mutex priority inheritance" ); - CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); - CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); -#else - CYG_TEST_INFO( "Checking for NO mutex priority inheritance" ); - CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" ); - CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" ); -#endif - - CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" ); - - for( i = 0; i < DELAYFACTOR * 20; i++ ) - nanosleep( &sleeptime, NULL ); // let those threads run - - CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); - CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); - CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" ); - - for ( i = 0; i < 3; i++ ) - if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control - CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" ); - else - CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" ); - - CYG_TEST_PASS( "Thread 2 exiting, AOK" ); - // That's all: restart the control thread. - sem_post( &hold[0] ); - - return 0; -} - -// ------------------------------------------------------------------------ - -static void *t3( void *arg ) -{ - int i; - int id = (int)arg; - //CYG_ADDRWORD data = thread_data[id]; - - // Emulate resume behaviour - sem_wait( &hold[id] ); - if( all_exit ) return 0; - - CYG_TEST_INFO( "Thread 3 running" ); - - pthread_mutex_lock( &mutex ); - - for( i = 0; i < DELAYFACTOR * 5; i++ ) - nanosleep( &sleeptime, NULL ); // let thread 3a run - - sem_post( &hold[2] ); // resume thread 2 - - while ( 0 == go_flag ) - nanosleep( &sleeptime, NULL ); // wait until we are told to go - - t3ran ++; // record the fact - - CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" ); - - pthread_mutex_unlock( &mutex ); - - t3ended ++; // record that we came back - - CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); - - CYG_TEST_INFO( "Thread 3 exit" ); - - return 0; -} - -// ------------------------------------------------------------------------ - -static void *control_thread( void *arg ) -{ - int i,z; - int id = (int)arg; - //CYG_ADDRWORD data = thread_data[id]; - - // Emulate resume behaviour - sem_wait( &hold[id] ); - if( all_exit ) return 0; - - // one tick sleep time - sleeptime.tv_nsec = 10000000; - sleeptime.tv_sec = 0; - - CYG_TEST_INIT(); - CYG_TEST_INFO( "Control Thread running" ); - - // Go through the 27 possibilitied of resuming the extra threads - // 0: not at all - // 1: early in the process - // 2: later on - // which are represented by bits 0-3 and 4-6 resp in the argument to - // thread 2 (none set means no resume at all). - for ( i = 0; i < 27; i++ ) { - static int xx[] = { 0, 1, 16 }; - int j = i % 3; - int k = (i / 3) % 3; - int l = (i / 9) % 3; - - int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ; - - if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) ) - continue; // 13 is 111 base 3, 26 is 222 base 3 - -#ifdef _POSIX_THREAD_PRIO_INHERIT - // If the simple scheme plus relay enhancement, or any other - // *complete* scheme, we can run all three ancillary threads no - // problem, so no special action here. - -#else - // If no priority inheritance at all, running threads 1a and 2a is - // OK, but not thread 3a; it blocks the world. - if ( l ) // Cannot run thread 3a if no - break; // priority inheritance at all. -#endif - - // Reinitialize mutex to provide priority inheritance - { - pthread_mutexattr_t attr; - pthread_mutexattr_init( &attr ); - pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT ); - pthread_mutex_init( &mutex, &attr ); - } - - got_it = 0; - t3ran = 0; - t3ended = 0; - for ( z = 0; z < 4; z++ ) extras[z] = 0; - go_flag = 0; - - new_thread( t1, 0, 15, 1 ); // Slot 1 - new_thread( t2, d, 10, 1 ); // Slot 2 - new_thread( t3, 0, 5, 1 ); // Slot 3 - - new_thread( extra_thread, 1, 17, j ); // Slot 4 - new_thread( extra_thread, 2, 12, k ); // Slot 5 - new_thread( extra_thread, 3, 8, l ); // Slot 6 - - { - static char *a[] = { "inactive", "run early", "run late" }; - diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n", - i, d, a[j], a[k], a[l] ); - } - - sem_wait( &hold[0] ); - - kill_threads(); - pthread_mutex_destroy( &mutex ); - } - CYG_TEST_EXIT( "Control Thread exit" ); - - return 0; -} - -// ------------------------------------------------------------------------ - -static sem_t main_sem; - -externC int -main( int argc, char **argv ) -{ - new_thread( control_thread, 0, 20, 1 ); - - // We have nothing for main to do here, so put it to sleep on - // its own semaphore. We cannot let it just exit since that - // will end the whole program. - - sem_init( &main_sem, 0, 0 ); - - for(;;) sem_wait( &main_sem ); -} - -// ------------------------------------------------------------------------ -// Documentation: enclosed is the design of this test. -// -// It has been carefully constructed so that it does NOT use other kernel -// facilities (aside from delay-task) to test that priority inheritance is -// working, or not, as intended by the configuration. -// -// These notes describe the flow of control in one run of the test with the -// ancillary tasks optionally interspersed. The details of how those extra -// tasks are or are not allowed to run are not described. -// -// -// -// The only change in the test that depends on whether there is inheritance or -// not is the check in thread 2 on "3-ran" and "got it" flags marked **** -// -// -// volatile &c booleans: -// "got it" = FALSE -// "3-ran" = FALSE -// "3-ended" = FALSE -// "extras"[3] = FALSE -// -// thread 1. prio 5, self-suspend. -// -// thread 1a, prio 8, self-suspend. -// -// thread 2. prio 10, self-suspend. -// -// thread 2a, prio 12, self-suspend. -// -// thread 3. prio 15, runs, lock mutex, resume(2) -// -// thread 3a, prio 17, self-suspend. -// -// 2. runs, -// 2. resume(3a) +++OPTIONAL -// 2. resume(2a) +++OPTIONAL -// 2. resume(1a) +++OPTIONAL -// [1a lock-fail] thread 3->prio := 8 -// -// [3. runs maybe, does the looping thing] -// -// 2. sleep a while... -// -// [2a lock-fail] thread 3->prio := 12 -// -// [3. runs maybe, does the looping thing] -// -// [3a lock-fail] thread 3->prio unchanged -// -// [3. runs maybe, does the looping thing] -// -// 2. lock scheduler -// 2. set "go-flag" -// 2. resume(1) -// 2. resume(1a) +++OPTIONAL -// 2. resume(2a) +++OPTIONAL -// 2. resume(3a) +++OPTIONAL -// 2. unlock scheduler -// -// 1. runs, lock mutex - thread 3 has it locked -// -// 2. busy-waits a bit for thread 3 to come out of its delay() loop. -// This must be a *busy*wait so that 3 can only run via the -// inherited raised priority. -// -// [xa. all do the same: lock mutex, ] -// [xa. unlock mutex ] -// [xa. set a flag "extras"[x] to say we are done. ] -// [xa. exit ] -// -// -// -// INHERIT -// ------- -// -// thread 3->prio := 5 -// -// 3. runs, -// 3. set a flag to say "3-ran", -// 3. loop with a sleep(1) until "go-flag" is set. -// 3. check "got it" is false, -// 3. then unlock mutex, -// -// thread 3->prio := 15 -// -// 1. runs, set a flag to say "got it", -// 1. check "3-ended" flag is false -// 1. unlock mutex, -// 1. check "3-ended" flag is still false -// 1. exit. -// -// [1a locks, unlocks, exits] -// -// 2. runs, check "3-ran" and "got it" flags are TRUE **** -// 2. check "3-ended" flag is false -// 2. sleeps for a while so that... -// -// [2a locks, unlocks, exits] -// -// 3. runs, set "3-ended" flag, -// 3. check "3-ran" and "got it" flags -// 3. exit -// -// [3a locks, unlocks, exits] -// -// 2. awakens, checks all flags true, -// 2. check that all "extra" threads that we started have indeed run -// 2. end of test. -// -// -// -// -// NO-INHERIT -// ---------- -// thread 1 is waiting on the mutex -// -// [1a lock-fail] -// -// 2. runs, checks that "3-ran" and "got it" flags are FALSE **** -// 2. check "3-ended" flag is false -// 2. sleeps for a while so that... -// -// [2a. lock-fail] -// -// 3. runs, set a flag to say "3-ran", -// 3. check "got it" is false, -// 3. then unlock mutex, -// -// 1. runs, set a flag to say "got it", -// 1. check "3-ended" flag is false -// 1. unlock mutex, -// 1. check "3-ended" flag is still false -// 1. exit. -// -// [1a locks, unlocks, exits] -// [2a locks, unlocks, exits] -// -// 3. runs, set "3-ended" flag, -// 3. check "3-ran" and "got it" flags -// 3. exit -// -// [3a locks, unlocks, exits] -// -// 2. awakens, checks all flags true, -// 2. check that all "extra" threads that we started have indeed run -// 2. end of test. -// -// -// (the end) -// -// -// ------------------------------------------------------------------------ - -#endif - -// EOF mutex3.cxx
new file mode 100644 --- /dev/null +++ b/packages/compat/posix/current/tests/pmqueue1.c @@ -0,0 +1,359 @@ +/*======================================================================== +// +// pmqueue1.c +// +// POSIX Message queues tests +// +//======================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//======================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: +// Date: 2000-05-18 +// Purpose: This file provides tests for POSIX mqueues +// Description: +// Usage: +// +//####DESCRIPTIONEND#### +// +//====================================================================== +*/ + +/* CONFIGURATION */ + +#include <pkgconf/posix.h> + +#ifndef CYGPKG_POSIX_MQUEUES +# define NA_MSG "Message queues not configured" +#endif + +#ifdef NA_MSG +#include <cyg/infra/testcase.h> // test API +void +cyg_user_start(void) +{ + CYG_TEST_NA( NA_MSG ); +} + +#else + +/* INCLUDES */ + +#include <fcntl.h> // O_* +#include <errno.h> // errno +#include <sys/stat.h> // file modes +#include <mqueue.h> // Mqueue Header +#include <cyg/infra/testcase.h> // test API + +/* FUNCTIONS */ + +static int +my_memcmp(const void *m1, const void *m2, size_t n) +{ + char *s1 = (char *)m1; + char *s2 = (char *)m2; + + while (n--) { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + return 0; +} // my_memcmp() + +//************************************************************************ + +int +main(void) +{ + mqd_t q1, q2; + char buf[20]; + ssize_t recvlen; + unsigned int prio; + struct mq_attr attr, oattr; + mode_t mode; + int err; + + CYG_TEST_INIT(); + CYG_TEST_INFO( "Starting POSIX message test 1" ); + + q1 = mq_open( "/mq1", O_RDWR ); + CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" ); + CYG_TEST_PASS_FAIL( ENOENT == errno, + "errno correct for non-existent queue" ); + + attr.mq_flags = 0; + attr.mq_maxmsg = 4; + attr.mq_msgsize = 20; + mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all + + q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_WRONLY, mode, &attr ); + CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" ); + + err = mq_getattr( q1, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY != (attr.mq_flags & O_RDONLY)) && + (O_WRONLY == (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (0 == attr.mq_curmsgs ), "getattr attributes correct" ); + + err = mq_send( q1, "Vik is brill", sizeof("Vik is brill"), 10 ); + + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_send" ); + + err = mq_getattr( q1, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY != (attr.mq_flags & O_RDONLY)) && + (O_WRONLY == (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (1 == attr.mq_curmsgs ), + "getattr attributes correct #2" ); + + q2 = mq_open( "/mq1", O_RDONLY|O_CREAT|O_EXCL ); + CYG_TEST_PASS_FAIL( q2 == (mqd_t)-1, + "error for exclusive open of existing queue" ); + CYG_TEST_PASS_FAIL( EEXIST == errno, + "errno correct for exclusive open of existing queue" ); + + q2 = mq_open( "/mq1", O_RDONLY ); + CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "simple mq_open (read only)" ); + + err = mq_getattr( q2, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY == (attr.mq_flags & O_RDONLY)) && + (O_WRONLY != (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (1 == attr.mq_curmsgs ), + "getattr attributes correct #3" ); + + err = mq_close( q2 ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_close" ); + + q2 = mq_open( "/mq1", O_RDONLY ); + CYG_TEST_PASS_FAIL( q2 != (mqd_t)-1, "mq_open reopen (read only)" ); + + err = mq_getattr( q2, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr, different mqd_t" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK != (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY == (attr.mq_flags & O_RDONLY)) && + (O_WRONLY != (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (1 == attr.mq_curmsgs ), + "getattr attributes correct #4" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is brill"), + "receive message length" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is brill", + sizeof("Vik is brill")), + "received message data intact" ); + CYG_TEST_PASS_FAIL( 10 == prio, "received at correct priority" ); + + err = mq_getattr( q1, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr after send" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY != (attr.mq_flags & O_RDONLY)) && + (O_WRONLY == (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (0 == attr.mq_curmsgs ), + "getattr attributes correct #5" ); + + attr.mq_flags |= O_NONBLOCK; + err = mq_setattr( q2, &attr, &oattr ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_setattr O_NONBLOCK" ); + CYG_TEST_PASS_FAIL( (4 == oattr.mq_maxmsg) && + (20 == oattr.mq_msgsize) && + (O_NONBLOCK != (oattr.mq_flags & O_NONBLOCK)) && + (O_RDONLY == (oattr.mq_flags & O_RDONLY)) && + (O_WRONLY != (oattr.mq_flags & O_WRONLY)) && + (O_RDWR != (oattr.mq_flags & O_RDWR)) && + (0 == oattr.mq_curmsgs ), + "old attribute correct" ); + err = mq_getattr( q2, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after O_NONBLOCK" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY == (attr.mq_flags & O_RDONLY)) && + (O_WRONLY != (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (0 == attr.mq_curmsgs ), + "new attribute correct" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, + "mq_receive, empty buffer, non-blocking" ); + CYG_TEST_PASS_FAIL( EAGAIN == errno, + "errno correct for non-blocking" ); + + err = mq_send( q2, "foo", sizeof("foo"), 1 ); + CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send on read-only descriptor" ); + CYG_TEST_PASS_FAIL( EBADF == errno, + "errno correct for mq_send on r/o descriptor" ); + + err = mq_send( q2, "supercalifragilisticexpealidocious", 21, 2 ); + CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send (message too long)" ); + CYG_TEST_PASS_FAIL( EMSGSIZE == errno, + "errno correct for mq_send (message too long)" ); + + err = mq_send( q1, "", sizeof(""), 5 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send \"\"" ); + + err = mq_send( q1, "I love Vik", sizeof("I love Vik"), 7 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send (different priority)" ); + + err = mq_send( q1, "a lot!", sizeof("a lot!"), 7 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send (same priority)" ); + + err = mq_send( q1, "Vik is a babe", sizeof("Vik is a babe"), 6 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send (middle priority)" ); + + err = mq_send( q1, "wibble", sizeof("wibble"), 6 ); + CYG_TEST_PASS_FAIL( -1 == err, "error on mq_send with full queue" ); + CYG_TEST_PASS_FAIL( EAGAIN == errno, + "errno correct for mq_send full queue" ); + + err = mq_getattr( q2, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_getattr after sends" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDONLY == (attr.mq_flags & O_RDONLY)) && + (O_WRONLY != (attr.mq_flags & O_WRONLY)) && + (O_RDWR != (attr.mq_flags & O_RDWR)) && + (4 == attr.mq_curmsgs ), + "getattr attributes correct #5" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == sizeof("I love Vik"), + "receive message length (prioritized) #1" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "I love Vik", + sizeof("I love Vik")), + "received message data intact (prioritized) #1" ); + CYG_TEST_PASS_FAIL( 7 == prio, + "received at correct priority (prioritized) #1" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == sizeof("a lot!"), + "receive message length (prioritized) #2" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "a lot!", + sizeof("a lot!")), + "received message data intact (prioritized) #2" ); + CYG_TEST_PASS_FAIL( 7 == prio, + "received at correct priority (prioritized) #2" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == sizeof("Vik is a babe"), + "receive message length (prioritized) #3" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "Vik is a babe", + sizeof("Vik is a babe")), + "received message data intact (prioritized) #3" ); + CYG_TEST_PASS_FAIL( 6 == prio, + "received at correct priority (prioritized) #3" ); + + recvlen = mq_receive( q2, buf, 0, &prio ); + CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, + "mq_receive, zero-sized buffer" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == sizeof(""), + "receive message length (prioritized) #4" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "", + sizeof("")), + "received message data intact (prioritized) #4" ); + CYG_TEST_PASS_FAIL( 5 == prio, + "received at correct priority (prioritzed) #4" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == (ssize_t)-1, + "mq_receive, empty buffer, non-blocking #2" ); + CYG_TEST_PASS_FAIL( EAGAIN == errno, + "errno correct for non-blocking #2" ); + + err = mq_send( q1, "12345678901234567890", 20, 15 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send (before closing)" ); + + err = mq_unlink( "/foo" ); + CYG_TEST_PASS_FAIL( -1 == err, "mq_unlink (wrong name)" ); + CYG_TEST_PASS_FAIL( ENOENT == errno, + "errno correct for mq_unlink (wrong name)" ); + + err = mq_unlink( "/mq1" ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink (before closing)" ); + + err = mq_close( q1 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_close (send descriptor)" ); + + recvlen = mq_receive( q2, buf, sizeof(buf), &prio ); + CYG_TEST_PASS_FAIL( recvlen == 20, + "receive message length (mid close)" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, "12345678901234567890", 20 ), + "received message data intact (mid close)" ); + CYG_TEST_PASS_FAIL( 15 == prio, + "received at correct priority (mid close)" ); + + err = mq_close( q2 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_close (receive descriptor)" ); + + q1 = mq_open( "/mq1", O_RDONLY ); + CYG_TEST_PASS_FAIL( q1 == (mqd_t)-1, "error for non-existent queue" ); + CYG_TEST_PASS_FAIL( ENOENT == errno, + "errno correct for non-existent queue" ); + + CYG_TEST_EXIT("POSIX message test 1"); + + return 0; +} // main() + +//------------------------------------------------------------------------ + +#endif + +/* EOF pmqueue1.c */
new file mode 100644 --- /dev/null +++ b/packages/compat/posix/current/tests/pmqueue2.c @@ -0,0 +1,276 @@ +/*======================================================================== +// +// pmqueue2.c +// +// POSIX Message queues tests - mq_notify +// +//======================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//======================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jlarmour +// Contributors: +// Date: 2000-05-18 +// Purpose: This file provides tests for POSIX mqueue mq_notify +// Description: +// Usage: +// +//####DESCRIPTIONEND#### +// +//====================================================================== +*/ + +/* CONFIGURATION */ + +#include <pkgconf/posix.h> + +#ifndef CYGPKG_POSIX_MQUEUES +# define NA_MSG "Message queues not configured" +#elif !defined(CYGPKG_POSIX_SIGNALS) +# define NA_MSG "No POSIX signals configured" +#endif + +#ifdef NA_MSG +#include <cyg/infra/testcase.h> // test API +void +cyg_user_start(void) +{ + CYG_TEST_INIT(); + CYG_TEST_NA( NA_MSG ); +} + +#else + +/* INCLUDES */ + +#include <fcntl.h> // O_* +#include <errno.h> // errno +#include <sys/stat.h> // file modes +#include <mqueue.h> // Mqueue Header +#include <cyg/infra/testcase.h> // test API +#include <signal.h> // signals + +/* GLOBALS */ +sig_atomic_t signals=0; +char buf[20]; +unsigned int prio; + + +/* FUNCTIONS */ + +static int +my_memcmp(const void *m1, const void *m2, size_t n) +{ + char *s1 = (char *)m1; + char *s2 = (char *)m2; + + while (n--) { + if (*s1 != *s2) + return *s1 - *s2; + s1++; + s2++; + } + return 0; +} // my_memcmp() + +static char * +my_strcpy(char *s1, const char *s2) +{ + char *s = s1; + while (*s2) { + *s1++ = *s2++; + } + return s; +} // my_strcpy() + +static size_t +my_strlen(const char *s) +{ + const char *start = s; + while (*s) + s++; + return (s - start); +} // my_strcpy() + + + +//************************************************************************ + +static void +sigusr1_handler( int signo, siginfo_t *info, void *context ) +{ + ssize_t recvlen; + char mybuf[20]; + unsigned int myprio; + mqd_t *q = (mqd_t *)info->si_value.sival_ptr; + + CYG_TEST_PASS_FAIL( SIGUSR1 == signo, "correct signal number #1" ); + CYG_TEST_PASS_FAIL( SIGUSR1 == info->si_signo, "correct signal number #2" ); + CYG_TEST_PASS_FAIL( SI_MESGQ == info->si_code, "correct signal code" ); + + signals++; + + // retrieve message and compare with buf + recvlen = mq_receive( *q, mybuf, sizeof(mybuf), &myprio ); + CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), + "receive message length" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), + "received message data intact" ); + CYG_TEST_PASS_FAIL( prio == myprio, + "received at correct priority" ); +} + +//************************************************************************ + +int +main(void) +{ + mqd_t q1; + struct mq_attr attr; + mode_t mode; + int err; + ssize_t recvlen; + char mybuf[20]; + unsigned int myprio; + struct sigevent ev; + struct sigaction act; + + CYG_TEST_INIT(); + CYG_TEST_INFO( "Starting POSIX message test 2" ); + +#if 0 + if ( 0 != pthread_create( &thr, NULL, &thread, NULL ) ) { + CYG_TEST_FAIL_FINISH( "Couldn't create a helper thread" ); + } +#endif + + attr.mq_flags = 0; + attr.mq_maxmsg = 4; + attr.mq_msgsize = 20; + mode = S_IRWXU|S_IRWXG|S_IRWXO; // rwx for all + + q1 = mq_open( "/mq1", O_CREAT|O_NONBLOCK|O_RDWR, mode, &attr ); + CYG_TEST_PASS_FAIL( q1 != (mqd_t)-1, "simple mq_open (write only)" ); + + err = mq_getattr( q1, &attr ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_getattr" ); + CYG_TEST_PASS_FAIL( (4 == attr.mq_maxmsg) && + (20 == attr.mq_msgsize) && + (O_NONBLOCK == (attr.mq_flags & O_NONBLOCK)) && + (O_RDWR == (attr.mq_flags & O_RDWR)) && + (0 == attr.mq_curmsgs ), "getattr attributes correct" ); + + + act.sa_sigaction = &sigusr1_handler; + sigfillset( &act.sa_mask ); // enable all signals + act.sa_flags = SA_SIGINFO; + + if ( 0 != sigaction( SIGUSR1, &act, NULL ) ) { + CYG_TEST_FAIL_FINISH( "Couldn't register signal handler" ); + } + + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGUSR1; + ev.sigev_value.sival_ptr = (void *)&q1; + + err = mq_notify( q1, &ev ); + CYG_TEST_PASS_FAIL( 0 == err, "simple mq_notify" ); + + my_strcpy( buf, "Vik is the best" ); + prio = 7; + err = mq_send( q1, buf, my_strlen(buf), prio ); + + CYG_TEST_PASS_FAIL( 0 == err, "mq_send #1" ); + + CYG_TEST_PASS_FAIL( 1 == signals, "got notification" ); + + my_strcpy( buf, "Scrummy Vik" ); + prio = 6; + err = mq_send( q1, buf, my_strlen(buf), prio ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" ); + + CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification" ); + + recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio ); + CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), + "receive message length" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), + "received message data intact" ); + CYG_TEST_PASS_FAIL( prio == myprio, + "received at correct priority" ); + + err = mq_notify( q1, &ev ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_notify #2" ); + + err = mq_notify( q1, &ev ); + CYG_TEST_PASS_FAIL( -1 == err, "second mq_notify returns error" ); + CYG_TEST_PASS_FAIL( EBUSY == errno, + "errno correct for second mq_notify error" ); + + err = mq_notify( q1, NULL ); + CYG_TEST_PASS_FAIL( 0 == err, "clear notification" ); + + my_strcpy( buf, "Vik is k3wl" ); + prio = 8; + err = mq_send( q1, buf, my_strlen(buf), prio ); + + CYG_TEST_PASS_FAIL( 0 == err, "mq_send #2" ); + + CYG_TEST_PASS_FAIL( 1 == signals, "correctly didn't get notification #2" ); + + recvlen = mq_receive( q1, mybuf, sizeof(mybuf), &myprio ); + CYG_TEST_PASS_FAIL( recvlen == my_strlen(buf), + "receive message length" ); + CYG_TEST_PASS_FAIL( 0 == my_memcmp( buf, mybuf, my_strlen(buf)), + "received message data intact" ); + CYG_TEST_PASS_FAIL( prio == myprio, + "received at correct priority" ); + + err = mq_close( q1 ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_close" ); + + err = mq_unlink( "/mq1" ); + CYG_TEST_PASS_FAIL( 0 == err, "mq_unlink" ); + + CYG_TEST_EXIT("POSIX message test 2"); + + return 0; +} // main() + +//------------------------------------------------------------------------ + +#endif + +/* EOF pmqueue2.c */
new file mode 100644 --- /dev/null +++ b/packages/compat/posix/current/tests/pmutex3.c @@ -0,0 +1,672 @@ +//========================================================================== +// +// pmutex3.c +// +// Mutex test 3 - priority inheritance +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt, nickg, jlarmour +// Date: 2000-01-06 +// Description: Tests mutex priority inheritance. This is simply a translation +// of the similarly named kernel test to the POSIX API +//####DESCRIPTIONEND#### + +// ------------------------------------------------------------------------ + +#include <cyg/infra/testcase.h> +#include <pkgconf/posix.h> +#include <pkgconf/system.h> +#ifdef CYGPKG_KERNEL +#include <pkgconf/kernel.h> +#endif + +#ifdef CYGPKG_ISOINFRA +# include <sys/types.h> +# include <pthread.h> +# include <semaphore.h> +# include <time.h> +# include <unistd.h> +#endif + +#if !defined(CYGPKG_POSIX_PTHREAD) +#define NA_MSG "POSIX threads not enabled" + +// ------------------------------------------------------------------------ +// +// These checks should be enough; any other scheduler which has priorities +// should manifest as having no priority inheritance, but otherwise fine, +// so the test should work correctly. + +#elif !defined(_POSIX_THREAD_PRIORITY_SCHEDULING) +#define NA_MSG "No POSIX thread priority scheduling enabled" +#elif !defined(_POSIX_THREAD_PRIO_INHERIT) +#define NA_MSG "No POSIX thread priority inheritance enabled" +#elif !defined(_POSIX_SEMAPHORES) +#define NA_MSG "No POSIX sempaphore support enabled enabled" +#elif !defined(CYGFUN_KERNEL_API_C) +#define NA_MSG "Kernel C API not enabled" +#elif defined(CYGPKG_KERNEL_SMP_SUPPORT) +#define NA_MSG "Test cannot run with SMP support" +#endif + +#ifdef NA_MSG +void +cyg_start(void) +{ + CYG_TEST_INIT(); + CYG_TEST_NA(NA_MSG); +} +#else + +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/cyg_trac.h> +#include <cyg/infra/diag.h> // diag_printf + +#include <cyg/kernel/kapi.h> // Some extras + +// ------------------------------------------------------------------------ +// Management functions +// +// Stolen from testaux.hxx and copied in here because I want to be able to +// reset the world also. +// ... and subsequently POSIXized out of all similarly with its progenitors. + +#define NTHREADS 7 + +#define STACKSIZE (PTHREAD_STACK_MIN*2) + +static pthread_t thread[NTHREADS] = { 0 }; + +typedef CYG_WORD64 CYG_ALIGNMENT_TYPE; + +static CYG_ALIGNMENT_TYPE stack[NTHREADS] [ + (STACKSIZE+sizeof(CYG_ALIGNMENT_TYPE)-1) + / sizeof(CYG_ALIGNMENT_TYPE) ]; + +// Semaphores to halt execution of threads +static sem_t hold[NTHREADS]; + +// Flag to tell all threads to exit +static int all_exit; + +// Application thread data is passed here, the thread +// argument is +static CYG_ADDRWORD thread_data[NTHREADS]; + +static volatile int nthreads = 0; + +// Sleep for 1 tick... +static struct timespec sleeptime; + + +static pthread_t new_thread( void *(*entry)(void *), + CYG_ADDRWORD data, + int priority, + int do_resume) +{ + pthread_attr_t attr; + int _nthreads = nthreads++; + + struct sched_param schedparam; + schedparam.sched_priority = priority; + + pthread_attr_init( &attr ); + pthread_attr_setstackaddr( &attr, (void *)((char *)(&stack[_nthreads])+STACKSIZE) ); + pthread_attr_setstacksize( &attr, STACKSIZE ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + pthread_attr_setschedparam( &attr, &schedparam ); + + CYG_ASSERT(_nthreads < NTHREADS, + "Attempt to create more than NTHREADS threads"); + + thread_data[_nthreads] = data; + + sem_init( &hold[_nthreads], 0, do_resume ? 1 : 0 ); + all_exit = 0; + + pthread_create( &thread[_nthreads], + &attr, + entry, + (void *)_nthreads); + + return thread[_nthreads]; +} + + +static void kill_threads( void ) +{ + CYG_ASSERT(nthreads <= NTHREADS, + "More than NTHREADS threads"); + CYG_ASSERT( pthread_equal(pthread_self(),thread[0]), + "kill_threads() not called from thread 0"); + all_exit = 1; + while ( nthreads > 1 ) { + nthreads--; + if ( 0 != thread[nthreads] ) { + sem_post( &hold[nthreads] ); + pthread_cancel( thread[nthreads] ); + pthread_join( thread[nthreads], NULL ); + thread[nthreads] = 0; + sem_destroy( &hold[nthreads] ); + } + } + CYG_ASSERT(nthreads == 1, + "No threads left"); +} + +// ------------------------------------------------------------------------ + +#define DELAYFACTOR 1 // for debugging + +// ------------------------------------------------------------------------ + +pthread_mutex_t mutex; + +// These are for reporting back to the master thread +volatile int got_it = 0; +volatile int t3ran = 0; +volatile int t3ended = 0; +volatile int extras[4] = {0,0,0,0}; + +volatile int go_flag = 0; // but this one controls thread 3 from thread 2 + +// ------------------------------------------------------------------------ +// 0 to 3 of these run generally to interfere with the other processing, +// to cause multiple prio inheritances, and clashes in any orders. + +static void *extra_thread( void *arg ) +{ +#define XINFO( z ) \ + do { z[13] = '0' + data; CYG_TEST_INFO( z ); } while ( 0 ) + + static char running[] = "Extra thread Xa running"; + static char exiting[] = "Extra thread Xa exiting"; + static char resumed[] = "Extra thread Xa resumed"; + static char locked[] = "Extra thread Xa locked"; + static char unlocked[] = "Extra thread Xa unlocked"; + + int id = (int)arg; + CYG_ADDRWORD data = thread_data[id]; + + CYG_ASSERT( (id >= 4 && id <= 6), "extra_thread invalid id" ); + + // Emulate resume behaviour + sem_wait( &hold[id] ); + if( all_exit ) return 0; + + XINFO( running ); + + sem_wait( &hold[id] ); + + XINFO( resumed ); + + pthread_mutex_lock( &mutex ); + + XINFO( locked ); + + pthread_mutex_unlock( &mutex ); + + XINFO( unlocked ); + + extras[ data ] ++; + + XINFO( exiting ); + + return NULL; +} + +// ------------------------------------------------------------------------ + +static void *t1( void *arg ) +{ + int id = (int)arg; + //CYG_ADDRWORD data = thread_data[id]; + + // Emulate resume behaviour + sem_wait( &hold[id] ); + if( all_exit ) return 0; + + CYG_TEST_INFO( "Thread 1 running" ); + + sem_wait( &hold[id] ); + + pthread_mutex_lock( &mutex ); + + got_it++; + + CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,1]" ); + + pthread_mutex_unlock( &mutex ); + + CYG_TEST_CHECK( 0 == t3ended, "T3 ended prematurely [T1,2]" ); + + // That's all. + + CYG_TEST_INFO( "Thread 1 exit" ); + + return 0; +} + +// ------------------------------------------------------------------------ + +static void *t2( void *arg ) +{ + int i; + int id = (int)arg; + CYG_ADDRWORD data = thread_data[id]; + cyg_tick_count_t now, then; + + // Emulate resume behaviour + sem_wait( &hold[id] ); + if( all_exit ) return 0; + + CYG_TEST_INFO( "Thread 2 running" ); + + CYG_TEST_CHECK( 0 == (data & ~0x77), "Bad T2 arg: extra bits" ); + CYG_TEST_CHECK( 0 == (data & (data >> 4)), "Bad T2 arg: overlap" ); + + sem_wait( &hold[id] ); + + // depending on our config argument, optionally restart some of the + // extra threads to throw noise into the scheduler: + for ( i = 0; i < 3; i++ ) + if ( (1 << i) & data ) // bits 0-2 control + sem_post( &hold[i+4] ); // made sure extras are thread[4-6] + + // let those threads run + for( i = 0; i < DELAYFACTOR * 10; i++ ) + nanosleep( &sleeptime, NULL ); + + cyg_scheduler_lock(); // do this next lot atomically + + go_flag = 1; // unleash thread 3 + sem_post( &hold[1] ); // resume thread 1 + + // depending on our config argument, optionally restart some of the + // extra threads to throw noise into the scheduler at this later point: + for ( i = 4; i < 7; i++ ) + if ( (1 << i) & data ) // bits 4-6 control + sem_post( &hold[i] ); // made sure extras are thread[4-6] + + cyg_scheduler_unlock(); // let scheduling proceed + + // Need a delay (but not a CPU yield) to allow t3 to awaken and act on + // the go_flag, otherwise we check these details below too soon. + // Actually, waiting for the clock to tick a couple of times would be + // better, so that is what we will do. Must be a busy-wait. + then = cyg_current_time(); + do { + now = cyg_current_time(); + // Wait longer than the delay in t3 waiting on go_flag + } while ( now < (then + 3) ); + +#ifdef _POSIX_THREAD_PRIO_INHERIT + CYG_TEST_INFO( "Checking for mutex priority inheritance" ); + CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); + CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); +#else + CYG_TEST_INFO( "Checking for NO mutex priority inheritance" ); + CYG_TEST_CHECK( 0 == t3ran, "Thread 3 DID run" ); + CYG_TEST_CHECK( 0 == got_it, "Thread 1 DID get the mutex" ); +#endif + + CYG_TEST_CHECK( 0 == t3ended, "Thread 3 ended prematurely [T2,1]" ); + + for( i = 0; i < DELAYFACTOR * 20; i++ ) + nanosleep( &sleeptime, NULL ); // let those threads run + + CYG_TEST_CHECK( 1 == t3ran, "Thread 3 did not run" ); + CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); + CYG_TEST_CHECK( 1 == t3ended, "Thread 3 has not ended" ); + + for ( i = 0; i < 3; i++ ) + if ( (1 << i) & (data | data >> 4) ) // bits 0-2 and 4-6 control + CYG_TEST_CHECK( 1 == extras[i+1], "Extra thread did not run" ); + else + CYG_TEST_CHECK( 0 == extras[i+1], "Extra thread ran" ); + + CYG_TEST_PASS( "Thread 2 exiting, AOK" ); + // That's all: restart the control thread. + sem_post( &hold[0] ); + + return 0; +} + +// ------------------------------------------------------------------------ + +static void *t3( void *arg ) +{ + int i; + int id = (int)arg; + //CYG_ADDRWORD data = thread_data[id]; + + // Emulate resume behaviour + sem_wait( &hold[id] ); + if( all_exit ) return 0; + + CYG_TEST_INFO( "Thread 3 running" ); + + pthread_mutex_lock( &mutex ); + + for( i = 0; i < DELAYFACTOR * 5; i++ ) + nanosleep( &sleeptime, NULL ); // let thread 3a run + + sem_post( &hold[2] ); // resume thread 2 + + while ( 0 == go_flag ) + nanosleep( &sleeptime, NULL ); // wait until we are told to go + + t3ran ++; // record the fact + + CYG_TEST_CHECK( 0 == got_it, "Thread 1 claims to have got my mutex" ); + + pthread_mutex_unlock( &mutex ); + + t3ended ++; // record that we came back + + CYG_TEST_CHECK( 1 == got_it, "Thread 1 did not get the mutex" ); + + CYG_TEST_INFO( "Thread 3 exit" ); + + return 0; +} + +// ------------------------------------------------------------------------ + +static void *control_thread( void *arg ) +{ + int i,z; + int id = (int)arg; + //CYG_ADDRWORD data = thread_data[id]; + + // Emulate resume behaviour + sem_wait( &hold[id] ); + if( all_exit ) return 0; + + // one tick sleep time + sleeptime.tv_nsec = 10000000; + sleeptime.tv_sec = 0; + + CYG_TEST_INIT(); + CYG_TEST_INFO( "Control Thread running" ); + + // Go through the 27 possibilitied of resuming the extra threads + // 0: not at all + // 1: early in the process + // 2: later on + // which are represented by bits 0-3 and 4-6 resp in the argument to + // thread 2 (none set means no resume at all). + for ( i = 0; i < 27; i++ ) { + static int xx[] = { 0, 1, 16 }; + int j = i % 3; + int k = (i / 3) % 3; + int l = (i / 9) % 3; + + int d = xx[j] | (xx[k]<<1) | (xx[l]<<2) ; + + if ( cyg_test_is_simulator && (0 != i && 13 != i && 26 != i) ) + continue; // 13 is 111 base 3, 26 is 222 base 3 + +#ifdef _POSIX_THREAD_PRIO_INHERIT + // If the simple scheme plus relay enhancement, or any other + // *complete* scheme, we can run all three ancillary threads no + // problem, so no special action here. + +#else + // If no priority inheritance at all, running threads 1a and 2a is + // OK, but not thread 3a; it blocks the world. + if ( l ) // Cannot run thread 3a if no + break; // priority inheritance at all. +#endif + + // Reinitialize mutex to provide priority inheritance + { + pthread_mutexattr_t attr; + pthread_mutexattr_init( &attr ); + pthread_mutexattr_setprotocol( &attr, PTHREAD_PRIO_INHERIT ); + pthread_mutex_init( &mutex, &attr ); + } + + got_it = 0; + t3ran = 0; + t3ended = 0; + for ( z = 0; z < 4; z++ ) extras[z] = 0; + go_flag = 0; + + new_thread( t1, 0, 15, 1 ); // Slot 1 + new_thread( t2, d, 10, 1 ); // Slot 2 + new_thread( t3, 0, 5, 1 ); // Slot 3 + + new_thread( extra_thread, 1, 17, j ); // Slot 4 + new_thread( extra_thread, 2, 12, k ); // Slot 5 + new_thread( extra_thread, 3, 8, l ); // Slot 6 + + { + static char *a[] = { "inactive", "run early", "run late" }; + diag_printf( "\n----- [%2d] New Cycle: 0x%02x, Threads 1a %s, 2a %s, 3a %s -----\n", + i, d, a[j], a[k], a[l] ); + } + + sem_wait( &hold[0] ); + + kill_threads(); + pthread_mutex_destroy( &mutex ); + } + CYG_TEST_EXIT( "Control Thread exit" ); + + return 0; +} + +// ------------------------------------------------------------------------ + +static sem_t main_sem; + +externC int +main( int argc, char **argv ) +{ + new_thread( control_thread, 0, 20, 1 ); + + // We have nothing for main to do here, so put it to sleep on + // its own semaphore. We cannot let it just exit since that + // will end the whole program. + + sem_init( &main_sem, 0, 0 ); + + for(;;) sem_wait( &main_sem ); +} + +// ------------------------------------------------------------------------ +// Documentation: enclosed is the design of this test. +// +// It has been carefully constructed so that it does NOT use other kernel +// facilities (aside from delay-task) to test that priority inheritance is +// working, or not, as intended by the configuration. +// +// These notes describe the flow of control in one run of the test with the +// ancillary tasks optionally interspersed. The details of how those extra +// tasks are or are not allowed to run are not described. +// +// +// +// The only change in the test that depends on whether there is inheritance or +// not is the check in thread 2 on "3-ran" and "got it" flags marked **** +// +// +// volatile &c booleans: +// "got it" = FALSE +// "3-ran" = FALSE +// "3-ended" = FALSE +// "extras"[3] = FALSE +// +// thread 1. prio 5, self-suspend. +// +// thread 1a, prio 8, self-suspend. +// +// thread 2. prio 10, self-suspend. +// +// thread 2a, prio 12, self-suspend. +// +// thread 3. prio 15, runs, lock mutex, resume(2) +// +// thread 3a, prio 17, self-suspend. +// +// 2. runs, +// 2. resume(3a) +++OPTIONAL +// 2. resume(2a) +++OPTIONAL +// 2. resume(1a) +++OPTIONAL +// [1a lock-fail] thread 3->prio := 8 +// +// [3. runs maybe, does the looping thing] +// +// 2. sleep a while... +// +// [2a lock-fail] thread 3->prio := 12 +// +// [3. runs maybe, does the looping thing] +// +// [3a lock-fail] thread 3->prio unchanged +// +// [3. runs maybe, does the looping thing] +// +// 2. lock scheduler +// 2. set "go-flag" +// 2. resume(1) +// 2. resume(1a) +++OPTIONAL +// 2. resume(2a) +++OPTIONAL +// 2. resume(3a) +++OPTIONAL +// 2. unlock scheduler +// +// 1. runs, lock mutex - thread 3 has it locked +// +// 2. busy-waits a bit for thread 3 to come out of its delay() loop. +// This must be a *busy*wait so that 3 can only run via the +// inherited raised priority. +// +// [xa. all do the same: lock mutex, ] +// [xa. unlock mutex ] +// [xa. set a flag "extras"[x] to say we are done. ] +// [xa. exit ] +// +// +// +// INHERIT +// ------- +// +// thread 3->prio := 5 +// +// 3. runs, +// 3. set a flag to say "3-ran", +// 3. loop with a sleep(1) until "go-flag" is set. +// 3. check "got it" is false, +// 3. then unlock mutex, +// +// thread 3->prio := 15 +// +// 1. runs, set a flag to say "got it", +// 1. check "3-ended" flag is false +// 1. unlock mutex, +// 1. check "3-ended" flag is still false +// 1. exit. +// +// [1a locks, unlocks, exits] +// +// 2. runs, check "3-ran" and "got it" flags are TRUE **** +// 2. check "3-ended" flag is false +// 2. sleeps for a while so that... +// +// [2a locks, unlocks, exits] +// +// 3. runs, set "3-ended" flag, +// 3. check "3-ran" and "got it" flags +// 3. exit +// +// [3a locks, unlocks, exits] +// +// 2. awakens, checks all flags true, +// 2. check that all "extra" threads that we started have indeed run +// 2. end of test. +// +// +// +// +// NO-INHERIT +// ---------- +// thread 1 is waiting on the mutex +// +// [1a lock-fail] +// +// 2. runs, checks that "3-ran" and "got it" flags are FALSE **** +// 2. check "3-ended" flag is false +// 2. sleeps for a while so that... +// +// [2a. lock-fail] +// +// 3. runs, set a flag to say "3-ran", +// 3. check "got it" is false, +// 3. then unlock mutex, +// +// 1. runs, set a flag to say "got it", +// 1. check "3-ended" flag is false +// 1. unlock mutex, +// 1. check "3-ended" flag is still false +// 1. exit. +// +// [1a locks, unlocks, exits] +// [2a locks, unlocks, exits] +// +// 3. runs, set "3-ended" flag, +// 3. check "3-ran" and "got it" flags +// 3. exit +// +// [3a locks, unlocks, exits] +// +// 2. awakens, checks all flags true, +// 2. check that all "extra" threads that we started have indeed run +// 2. end of test. +// +// +// (the end) +// +// +// ------------------------------------------------------------------------ + +#endif + +// EOF pmutex3.c
deleted file mode 100644 --- a/packages/compat/posix/current/tests/tm_basic.cxx +++ /dev/null @@ -1,1714 +0,0 @@ -//========================================================================== -// -// tm_basic.cxx -// -// Basic timing test / scaffolding -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2002 Jonathan Larmour -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): gthomas,nickg -// Contributors: jlarmour -// Date: 1998-10-19 -// Description: Very simple kernel timing test -//####DESCRIPTIONEND#### -//========================================================================== - - -#include <cyg/infra/testcase.h> -#include <cyg/infra/diag.h> -#include <pkgconf/posix.h> -#include <pkgconf/system.h> -#ifdef CYGPKG_KERNEL -#include <pkgconf/kernel.h> -#endif - -#ifndef CYGPKG_POSIX_SIGNALS -#define NA_MSG "No POSIX signals" -#elif !defined(CYGPKG_POSIX_TIMERS) -#define NA_MSG "No POSIX timers" -#elif !defined(CYGPKG_POSIX_PTHREAD) -#define NA_MSG "POSIX threads not enabled" -#elif !defined(CYGFUN_KERNEL_API_C) -#define NA_MSG "Kernel C API not enabled" -#elif !defined(CYGSEM_KERNEL_SCHED_MLQUEUE) -#define NA_MSG "Kernel mlqueue scheduler not enabled" -#elif !defined(CYGVAR_KERNEL_COUNTERS_CLOCK) -#define NA_MSG "Kernel clock not enabled" -#elif CYGNUM_KERNEL_SCHED_PRIORITIES <= 12 -#define NA_MSG "Kernel scheduler properties <= 12" -#elif !defined(CYGPKG_POSIX_SEMAPHORES) -#define NA_MSG "POSIX semaphores not enabled" -#endif - -//========================================================================== - -#ifdef NA_MSG -extern "C" void -cyg_start(void) -{ - CYG_TEST_INIT(); - CYG_TEST_NA(NA_MSG); -} -#else - -#include <pkgconf/kernel.h> -#include <pkgconf/hal.h> - -#include <cyg/kernel/sched.hxx> -#include <cyg/kernel/thread.hxx> -#include <cyg/kernel/thread.inl> -#include <cyg/kernel/mutex.hxx> -#include <cyg/kernel/sema.hxx> -#include <cyg/kernel/sched.inl> -#include <cyg/kernel/clock.hxx> -#include <cyg/kernel/clock.inl> -#include <cyg/kernel/kapi.h> - -#include <cyg/infra/testcase.h> - -#include <cyg/kernel/test/stackmon.h> -#include CYGHWR_MEMORY_LAYOUT_H - - -// POSIX headers - -#include <sys/types.h> -#include <pthread.h> -#include <semaphore.h> -#include <time.h> -#include <signal.h> -#include <errno.h> - -//========================================================================== -// Define this to see the statistics with the first sample datum removed. -// This can expose the effects of caches on the speed of operations. - -#undef STATS_WITHOUT_FIRST_SAMPLE - -//========================================================================== - -// Structure used to keep track of times -typedef struct fun_times { - cyg_uint32 start; - cyg_uint32 end; -} fun_times; - -//========================================================================== - -#define STACK_SIZE (PTHREAD_STACK_MIN*2) - -// Defaults -#define NTEST_THREADS 16 -#define NMUTEXES 32 -#define NMBOXES 32 -#define NSEMAPHORES 32 -#define NTIMERS 32 - - -#define NSAMPLES 32 -#define NTHREAD_SWITCHES 128 -#define NSCHEDS 128 - -#define NSAMPLES_SIM 2 -#define NTEST_THREADS_SIM 2 -#define NTHREAD_SWITCHES_SIM 4 -#define NMUTEXES_SIM 2 -#define NMBOXES_SIM 2 -#define NSEMAPHORES_SIM 2 -#define NSCHEDS_SIM 4 -#define NTIMERS_SIM 2 - -//========================================================================== - -static int nsamples; -static int ntest_threads; -static int nthread_switches; -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX -static int nmutexes; -#endif -static int nmboxes; -static int nsemaphores; -static int nscheds; -static int ntimers; - -static char stacks[NTEST_THREADS][STACK_SIZE]; -static pthread_t threads[NTEST_THREADS]; -static int overhead; -static sem_t synchro; -static fun_times thread_ft[NTEST_THREADS]; - -static fun_times test2_ft[NTHREAD_SWITCHES]; -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX -static pthread_mutex_t test_mutexes[NMUTEXES]; -static fun_times mutex_ft[NMUTEXES]; -static pthread_t mutex_test_thread_handle; -#endif -#if 0 -static cyg_mbox test_mboxes[NMBOXES]; -static cyg_handle_t test_mbox_handles[NMBOXES]; -static fun_times mbox_ft[NMBOXES]; -static cyg_thread mbox_test_thread; -static cyg_handle_t mbox_test_thread_handle; -#endif - -static sem_t test_semaphores[NSEMAPHORES]; -static fun_times semaphore_ft[NSEMAPHORES]; -static pthread_t semaphore_test_thread_handle; - -static fun_times sched_ft[NSCHEDS]; - -static timer_t timers[NTIMERS]; -static fun_times timer_ft[NTIMERS]; - -static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; -static long ns_per_system_clock; - -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) -// Data kept by kernel real time clock measuring clock interrupt latency -extern cyg_tick_count total_clock_latency, total_clock_interrupts; -extern cyg_int32 min_clock_latency, max_clock_latency; -extern bool measure_clock_latency; -#endif - -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) -extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls; -extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency; -extern bool measure_clock_latency; -#endif - -//========================================================================== - -void run_sched_tests(void); -void run_thread_tests(void); -void run_thread_switch_test(void); -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX -void run_mutex_tests(void); -void run_mutex_circuit_test(void); -#endif -void run_mbox_tests(void); -void run_mbox_circuit_test(void); -void run_semaphore_tests(void); -void run_semaphore_circuit_test(void); -void run_timer_tests(void); - -//========================================================================== - -#ifndef max -#define max(n,m) (m > n ? n : m) -#endif - -//========================================================================== -// Wait until a clock tick [real time clock] has passed. This should keep it -// from happening again during a measurement, thus minimizing any fluctuations -void -wait_for_tick(void) -{ - cyg_tick_count_t tv0, tv1; - tv0 = cyg_current_time(); - while (true) { - tv1 = cyg_current_time(); - if (tv1 != tv0) break; - } -} - -//-------------------------------------------------------------------------- -// Display a number of ticks as microseconds -// Note: for improved calculation significance, values are kept in ticks*1000 -void -show_ticks_in_us(cyg_uint32 ticks) -{ - long long ns; - ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; - ns += 5; // for rounding to .01us - diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10)); -} - -//-------------------------------------------------------------------------- -// -// If the kernel is instrumented to measure clock interrupt latency, these -// measurements can be drastically perturbed by printing via "diag_printf()" -// since that code may run with interrupts disabled for long periods. -// -// In order to get accurate/reasonable latency figures _for the kernel -// primitive functions beint tested_, the kernel's latency measurements -// are suspended while the printing actually takes place. -// -// The measurements are reenabled after the printing, thus allowing for -// fair measurements of the kernel primitives, which are not distorted -// by the printing mechanisms. - -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) -void -disable_clock_latency_measurement(void) -{ - wait_for_tick(); - measure_clock_latency = false; -} - -void -enable_clock_latency_measurement(void) -{ - wait_for_tick(); - measure_clock_latency = true; -} - -// Ensure that the measurements are reasonable (no startup anomalies) -void -reset_clock_latency_measurement(void) -{ - disable_clock_latency_measurement(); - total_clock_latency = 0; - total_clock_interrupts = 0; - min_clock_latency = 0x7FFFFFFF; - max_clock_latency = 0; -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) - total_clock_dsr_latency = 0; - total_clock_dsr_calls = 0; - min_clock_dsr_latency = 0x7FFFFFFF; - max_clock_dsr_latency = 0; -#endif - enable_clock_latency_measurement(); - -} -#else -#define disable_clock_latency_measurement() -#define enable_clock_latency_measurement() -#define reset_clock_latency_measurement() -#endif - -//-------------------------------------------------------------------------- - -void -show_times_hdr(void) -{ - disable_clock_latency_measurement(); - diag_printf("\n"); - diag_printf(" Confidence\n"); - diag_printf(" Ave Min Max Var Ave Min Function\n"); - diag_printf(" ====== ====== ====== ====== ========== ========\n"); - enable_clock_latency_measurement(); -} - -void -show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first) -{ - int i, delta, min, max, con_ave, con_min, ave_dev; - int start_sample, total_samples; - cyg_int32 total, ave; - - if (ignore_first) { - start_sample = 1; - total_samples = nsamples-1; - } else { - start_sample = 0; - total_samples = nsamples; - } - total = 0; - min = 0x7FFFFFFF; - max = 0; - for (i = start_sample; i < nsamples; i++) { - if (ft[i].end < ft[i].start) { - // Clock wrapped around (timer tick) - delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; - } else { - delta = ft[i].end - ft[i].start; - } - delta -= overhead; - if (delta < 0) delta = 0; - delta *= 1000; - total += delta; - if (delta < min) min = delta; - if (delta > max) max = delta; - } - ave = total / total_samples; - total = 0; - ave_dev = 0; - for (i = start_sample; i < nsamples; i++) { - if (ft[i].end < ft[i].start) { - // Clock wrapped around (timer tick) - delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; - } else { - delta = ft[i].end - ft[i].start; - } - delta -= overhead; - if (delta < 0) delta = 0; - delta *= 1000; - delta = delta - ave; - if (delta < 0) delta = -delta; - ave_dev += delta; - } - ave_dev /= total_samples; - con_ave = 0; - con_min = 0; - for (i = start_sample; i < nsamples; i++) { - if (ft[i].end < ft[i].start) { - // Clock wrapped around (timer tick) - delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; - } else { - delta = ft[i].end - ft[i].start; - } - delta -= overhead; - if (delta < 0) delta = 0; - delta *= 1000; - if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; - if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; - } - con_ave = (con_ave * 100) / total_samples; - con_min = (con_min * 100) / total_samples; - show_ticks_in_us(ave); - show_ticks_in_us(min); - show_ticks_in_us(max); - show_ticks_in_us(ave_dev); - disable_clock_latency_measurement(); - diag_printf(" %3d%% %3d%%", con_ave, con_min); - diag_printf(" %s\n", title); - enable_clock_latency_measurement(); -} - -void -show_times(fun_times ft[], int nsamples, char *title) -{ - show_times_detail(ft, nsamples, title, false); -#ifdef STATS_WITHOUT_FIRST_SAMPLE - show_times_detail(ft, nsamples, "", true); -#endif -} - -//-------------------------------------------------------------------------- - -void -show_test_parameters(void) -{ - disable_clock_latency_measurement(); - diag_printf("\nTesting parameters:\n"); - diag_printf(" Clock samples: %5d\n", nsamples); - diag_printf(" Threads: %5d\n", ntest_threads); - diag_printf(" Thread switches: %5d\n", nthread_switches); -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - diag_printf(" Mutexes: %5d\n", nmutexes); -#endif - diag_printf(" Mailboxes: %5d\n", nmboxes); - diag_printf(" Semaphores: %5d\n", nsemaphores); - diag_printf(" Scheduler operations: %5d\n", nscheds); - diag_printf(" Timers: %5d\n", ntimers); - diag_printf("\n"); - enable_clock_latency_measurement(); -} - -void -end_of_test_group(void) -{ - disable_clock_latency_measurement(); - diag_printf("\n"); - enable_clock_latency_measurement(); -} - -//-------------------------------------------------------------------------- -// Compute a name for a thread - -char * -thread_name(char *basename, int indx) { - return "<<NULL>>"; // Not currently used -} - -//-------------------------------------------------------------------------- -// test0 - null test, just return - -void * -test0(void *indx) -{ - return indx; -} - -//-------------------------------------------------------------------------- -// test3 - loop, yeilding repeatedly and checking for cancellation - -void * -test3(void *indx) -{ - for(;;) - { - sched_yield(); - pthread_testcancel(); - } - - return indx; -} - -//-------------------------------------------------------------------------- -// test1 - empty test, simply exit. Last thread signals parent. - -void * -test1( void *indx) -{ - if ((cyg_uint32)indx == (cyg_uint32)(ntest_threads-1)) { - sem_post(&synchro); // Signal that last thread is dying - } - return indx; -} - -//-------------------------------------------------------------------------- -// test2 - measure thread switch times - -void * -test2(void *indx) -{ - int i; - for (i = 0; i < nthread_switches; i++) { - if ((int)indx == 0) { - HAL_CLOCK_READ(&test2_ft[i].start); - } else { - HAL_CLOCK_READ(&test2_ft[i].end); - } - sched_yield(); - } - if ((int)indx == 1) { - sem_post(&synchro); - } - - return indx; -} -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX -//-------------------------------------------------------------------------- -// Full-circuit mutex unlock/lock test - -void * -mutex_test(void * indx) -{ - int i; - pthread_mutex_lock(&test_mutexes[0]); - for (i = 0; i < nmutexes; i++) { - sem_wait(&synchro); - wait_for_tick(); // Wait until the next clock tick to minimize aberations - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_unlock(&test_mutexes[0]); - pthread_mutex_lock(&test_mutexes[0]); - sem_post(&synchro); - } - return indx; -} - -//-------------------------------------------------------------------------- -// Full-circuit mbox put/get test - -#if 0 -void -mbox_test(cyg_uint32 indx) -{ - void *item; - do { - item = cyg_mbox_get(test_mbox_handles[0]); - HAL_CLOCK_READ(&mbox_ft[(int)item].end); - cyg_semaphore_post(&synchro); - } while ((int)item != (nmboxes-1)); - cyg_thread_exit(0); -} -#endif -#endif -//-------------------------------------------------------------------------- -// Full-circuit semaphore post/wait test - -void * -semaphore_test(void * indx) -{ - int i; - for (i = 0; i < nsemaphores; i++) { - sem_wait(&test_semaphores[0]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - sem_post(&synchro); - } - return indx; -} - -//-------------------------------------------------------------------------- -// -// This set of tests is used to measure kernel primitives that deal with threads -// - -void -run_thread_tests(void) -{ - - - int i; - struct sched_param schedparam; - pthread_attr_t attr; - int policy; - void *retval; - - // Set my priority higher than any I plan to create - schedparam.sched_priority = 30; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - // Initiaize thread creation attributes - - pthread_attr_init( &attr ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &threads[i], - &attr, - test0, - (void *)i - ); - - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Create thread"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - sched_yield(); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Yield thread [all lower priority]"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - - schedparam.sched_priority = 11; - pthread_attr_setschedparam( &attr, &schedparam ); - pthread_setschedparam(threads[i], SCHED_RR, &schedparam); - - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Set priority"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - pthread_getschedparam( threads[i], &policy, &schedparam ); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Get priority"); - - cyg_thread_delay(1); // Let the test threads run - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - pthread_join(threads[i], &retval); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Join exited thread"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - sched_yield(); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Yield [no other] thread"); - - - // Recreate the test set - - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - for (i = 0; i < ntest_threads; i++) { - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &threads[i], - &attr, - test3, - (void *)i - ); - } - - cyg_thread_delay(1); // Let the test threads run - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - pthread_cancel(threads[i]); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Cancel [running] thread"); - - cyg_thread_delay(1); // Let the test threads do their cancellations - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - pthread_join(threads[i], &retval); - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Join [cancelled] thread"); - - - // Set my priority lower than any I plan to create - schedparam.sched_priority = 5; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - // Set up the end-of-threads synchronizer - sem_init(&synchro, 0, 0); - - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntest_threads; i++) { - HAL_CLOCK_READ(&thread_ft[i].start); - - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &threads[i], - &attr, - test2, - (void *)i - ); - - HAL_CLOCK_READ(&thread_ft[i].end); - } - show_times(thread_ft, ntest_threads, "Create [high priority] thread"); - - sem_wait(&synchro); // Wait for all threads to finish - - // Make sure they are all dead - for (i = 0; i < ntest_threads; i++) { - pthread_join(threads[i], &retval); - } - - run_thread_switch_test(); - end_of_test_group(); - -} - -//-------------------------------------------------------------------------- - -void -run_thread_switch_test(void) -{ - - int i; - struct sched_param schedparam; - pthread_attr_t attr; - void *retval; - - // Set my priority higher than any I plan to create - schedparam.sched_priority = 30; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - // Initiaize thread creation attributes - - pthread_attr_init( &attr ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - // Set up the end-of-threads synchronizer - - sem_init(&synchro, 0, 0); - - // Set up for thread context switch - - for (i = 0; i < 2; i++) { - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &threads[i], - &attr, - test2, - (void *)i - ); - } - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - - sem_wait(&synchro); - - show_times(test2_ft, nthread_switches, "Thread switch"); - - // Clean up - for (i = 0; i < 2; i++) { - pthread_join(threads[i], &retval); - } - -} - - -//-------------------------------------------------------------------------- -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX -void -run_mutex_tests(void) -{ - - int i; - pthread_mutexattr_t attr; - - pthread_mutexattr_init( &attr ); - - // Mutex primitives - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_init(&test_mutexes[i], &attr); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Init mutex"); - - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_lock(&test_mutexes[i]); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_unlock(&test_mutexes[i]); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Unlock [locked] mutex"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_trylock(&test_mutexes[i]); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_trylock(&test_mutexes[i]); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Trylock [locked] mutex"); - - // Must unlock mutices before destroying them. - for (i = 0; i < nmutexes; i++) { - pthread_mutex_unlock(&test_mutexes[i]); - } - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmutexes; i++) { - HAL_CLOCK_READ(&mutex_ft[i].start); - pthread_mutex_destroy(&test_mutexes[i]); - HAL_CLOCK_READ(&mutex_ft[i].end); - } - show_times(mutex_ft, nmutexes, "Destroy mutex"); - - - run_mutex_circuit_test(); - end_of_test_group(); -} - -//-------------------------------------------------------------------------- - -void -run_mutex_circuit_test(void) -{ - int i; - pthread_mutexattr_t mattr; - struct sched_param schedparam; - pthread_attr_t attr; - void *retval; - - // Set my priority lower than any I plan to create - schedparam.sched_priority = 5; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - // Initiaize thread creation attributes - - pthread_attr_init( &attr ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - // Set up for full mutex unlock/lock test - pthread_mutexattr_init( &mattr ); - pthread_mutex_init(&test_mutexes[0], &mattr); - sem_init(&synchro, 0, 0); - - pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &mutex_test_thread_handle, - &attr, - mutex_test, - (void *)0 - ); - - // Need to raise priority so that this thread will block on the "lock" - schedparam.sched_priority = 20; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - for (i = 0; i < nmutexes; i++) { - sem_post(&synchro); - pthread_mutex_lock(&test_mutexes[0]); - HAL_CLOCK_READ(&mutex_ft[i].end); - pthread_mutex_unlock(&test_mutexes[0]); - sem_wait(&synchro); - } - pthread_join(mutex_test_thread_handle, &retval); - show_times(mutex_ft, nmutexes, "Unlock/Lock mutex"); - -} - -#endif -//-------------------------------------------------------------------------- -// Message queue tests - -// Currently disabled, pending implementation of POSIX message queues - -#if 0 -void -run_mbox_tests(void) -{ - int i, cnt; - void *item; - // Mailbox primitives - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Create mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cnt = cyg_mbox_peek(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Peek [empty] mbox"); - -#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_put(test_mbox_handles[i], (void *)i); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Put [first] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cnt = cyg_mbox_peek(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_put(test_mbox_handles[i], (void *)i); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Put [second] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cnt = cyg_mbox_peek(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_get(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Get [first] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_get(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Get [second] mbox"); -#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_tryput(test_mbox_handles[i], (void *)i); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Tryput [first] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_peek_item(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_tryget(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_peek_item(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Peek item [empty] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - item = cyg_mbox_tryget(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Tryget [empty] mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_waiting_to_get(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Waiting to get mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_waiting_to_put(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Waiting to put mbox"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nmboxes; i++) { - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_delete(test_mbox_handles[i]); - HAL_CLOCK_READ(&mbox_ft[i].end); - } - show_times(mbox_ft, nmboxes, "Delete mbox"); - - run_mbox_circuit_test(); - end_of_test_group(); -} - -//-------------------------------------------------------------------------- - -void -run_mbox_circuit_test(void) -{ -#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT - int i; - // Set my priority lower than any I plan to create - cyg_thread_set_priority(cyg_thread_self(), 3); - // Set up for full mbox put/get test - cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]); - cyg_semaphore_init(&synchro, 0); - cyg_thread_create(2, // Priority - just a number - mbox_test, // entry - 0, // index - thread_name("thread", 0), // Name - &stacks[0][0], // Stack - STACK_SIZE, // Size - &mbox_test_thread_handle, // Handle - &mbox_test_thread // Thread data structure - ); - cyg_thread_resume(mbox_test_thread_handle); - for (i = 0; i < nmboxes; i++) { - wait_for_tick(); // Wait until the next clock tick to minimize aberations - HAL_CLOCK_READ(&mbox_ft[i].start); - cyg_mbox_put(test_mbox_handles[0], (void *)i); - cyg_semaphore_wait(&synchro); - } - cyg_thread_delete(mbox_test_thread_handle); - show_times(mbox_ft, nmboxes, "Put/Get mbox"); -#endif -} - -#endif - -//-------------------------------------------------------------------------- - -void -run_semaphore_tests(void) -{ - - int i; - int sem_val; - - // Semaphore primitives - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_init(&test_semaphores[i], 0, 0); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Init semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_post(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Post [0] semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_wait(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_trywait(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - sem_post(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_trywait(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_getvalue(&test_semaphores[i], &sem_val); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Get value of semaphore"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < nsemaphores; i++) { - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_destroy(&test_semaphores[i]); - HAL_CLOCK_READ(&semaphore_ft[i].end); - } - show_times(semaphore_ft, nsemaphores, "Destroy semaphore"); - - run_semaphore_circuit_test(); - end_of_test_group(); -} - -//-------------------------------------------------------------------------- - -void -run_semaphore_circuit_test(void) -{ - - int i; - struct sched_param schedparam; - pthread_attr_t attr; - void *retval; - - // Set my priority lower than any I plan to create - schedparam.sched_priority = 5; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - // Initiaize thread creation attributes - - pthread_attr_init( &attr ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - // Set up for full semaphore post/wait test - sem_init(&test_semaphores[0], 0, 0); - sem_init(&synchro, 0, 0); - - pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - pthread_create( &semaphore_test_thread_handle, - &attr, - semaphore_test, - (void *)0 - ); - - - for (i = 0; i < nsemaphores; i++) { - wait_for_tick(); // Wait until the next clock tick to minimize aberations - HAL_CLOCK_READ(&semaphore_ft[i].start); - sem_post(&test_semaphores[0]); - sem_wait(&synchro); - } - pthread_join(semaphore_test_thread_handle, &retval); - - show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore"); - - -} - -//-------------------------------------------------------------------------- - -// Timer callback function -void -sigrt0(int signo, siginfo_t *info, void *context) -{ - diag_printf("sigrt0 called\n"); - // empty call back -} - -// Callback used to test determinancy -static volatile int timer_cnt; -void -sigrt1(int signo, siginfo_t *info, void *context) -{ - if (timer_cnt == nscheds) return; - sched_ft[timer_cnt].start = 0; - HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); - if (timer_cnt == nscheds) { - sem_post(&synchro); - } -} - -static sem_t timer_sem; - -static void -sigrt2(int signo, siginfo_t *info, void *context) -{ - if (timer_cnt == nscheds) { - sem_post(&synchro); - sem_post(&timer_sem); - } else { - sched_ft[timer_cnt].start = 0; - sem_post(&timer_sem); - } -} - -// Null thread, used to keep scheduler busy -void * -timer_test(void * id) -{ - while (true) { - cyg_thread_yield(); - pthread_testcancel(); - } - - return id; -} - -// Thread that suspends itself at the first opportunity -void * -timer_test2(void *id) -{ - while (timer_cnt != nscheds) { - HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); - sem_wait(&timer_sem); - } - return id; -} - -void -run_timer_tests(void) -{ - int res; - int i; - struct sigaction sa; - struct sigevent sigev; - struct itimerspec tp; - - // Install signal handlers - sigemptyset( &sa.sa_mask ); - sa.sa_flags = SA_SIGINFO; - - sa.sa_sigaction = sigrt0; - sigaction( SIGRTMIN, &sa, NULL ); - - sa.sa_sigaction = sigrt1; - sigaction( SIGRTMIN+1, &sa, NULL ); - - sa.sa_sigaction = sigrt2; - sigaction( SIGRTMIN+2, &sa, NULL ); - - // Set up common bits of sigevent - - sigev.sigev_notify = SIGEV_SIGNAL; - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntimers; i++) { - HAL_CLOCK_READ(&timer_ft[i].start); - sigev.sigev_signo = SIGRTMIN; - sigev.sigev_value.sival_ptr = (void*)(&timers[i]); - res = timer_create( CLOCK_REALTIME, &sigev, &timers[i]); - HAL_CLOCK_READ(&timer_ft[i].end); - CYG_ASSERT( res == 0 , "timer_create() returned error"); - } - show_times(timer_ft, ntimers, "Create timer"); - - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 0; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 0; - for (i = 0; i < ntimers; i++) { - HAL_CLOCK_READ(&timer_ft[i].start); - res = timer_settime( timers[i], 0, &tp, NULL ); - HAL_CLOCK_READ(&timer_ft[i].end); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - } - show_times(timer_ft, ntimers, "Initialize timer to zero"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - tp.it_value.tv_sec = 1; - tp.it_value.tv_nsec = 250000000; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 0; - for (i = 0; i < ntimers; i++) { - HAL_CLOCK_READ(&timer_ft[i].start); - res = timer_settime( timers[i], 0, &tp, NULL ); - HAL_CLOCK_READ(&timer_ft[i].end); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - } - show_times(timer_ft, ntimers, "Initialize timer to 1.25 sec"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 0; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 0; - for (i = 0; i < ntimers; i++) { - HAL_CLOCK_READ(&timer_ft[i].start); - res = timer_settime( timers[i], 0, &tp, NULL ); - HAL_CLOCK_READ(&timer_ft[i].end); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - } - show_times(timer_ft, ntimers, "Disable timer"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - for (i = 0; i < ntimers; i++) { - HAL_CLOCK_READ(&timer_ft[i].start); - res = timer_delete( timers[i] ); - HAL_CLOCK_READ(&timer_ft[i].end); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - } - show_times(timer_ft, ntimers, "Delete timer"); - - - - sigev.sigev_signo = SIGRTMIN+1; - sigev.sigev_value.sival_ptr = (void*)(&timers[i]); - res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); - CYG_ASSERT( res == 0 , "timer_create() returned error"); - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 50000000; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 50000000;; - timer_cnt = 0; - res = timer_settime( timers[0], 0, &tp, NULL ); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - sem_init(&synchro, 0, 0); - wait_for_tick(); // Wait until the next clock tick to minimize aberations - do - { res = sem_wait(&synchro); - } while( res == -1 && errno == EINTR ); - CYG_ASSERT( res == 0 , "sem_wait() returned error"); - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 0; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 0; - res = timer_settime( timers[0], 0, &tp, NULL ); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - res = timer_delete( timers[0] ); - CYG_ASSERT( res == 0 , "timer_delete() returned error"); - show_times(sched_ft, nscheds, "Timer latency [0 threads]"); - - - - - struct sched_param schedparam; - pthread_attr_t attr; - void *retval; - - // Set my priority higher than any I plan to create - schedparam.sched_priority = 20; - pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); - - - // Initiaize thread creation attributes - - pthread_attr_init( &attr ); - pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); - pthread_attr_setschedpolicy( &attr, SCHED_RR ); - schedparam.sched_priority = 10; - pthread_attr_setschedparam( &attr, &schedparam ); - - for (i = 0; i < 2; i++) { - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - res = pthread_create( &threads[i], - &attr, - timer_test, - (void *)i - ); - CYG_ASSERT( res == 0 , "pthread_create() returned error"); - } - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - - sigev.sigev_signo = SIGRTMIN+1; - sigev.sigev_value.sival_ptr = (void*)(&timers[i]); - res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); - CYG_ASSERT( res == 0 , "timer_create() returned error"); - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 50000000; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 50000000;; - timer_cnt = 0; - res = timer_settime( timers[0], 0, &tp, NULL ); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - - sem_init(&synchro, 0, 0); - do - { res = sem_wait(&synchro); - } while( res == -1 && errno == EINTR ); - CYG_ASSERT( res == 0 , "sem_wait() returned error"); - res = timer_delete(timers[0]); - CYG_ASSERT( res == 0 , "timerdelete() returned error"); - show_times(sched_ft, nscheds, "Timer latency [2 threads]"); - for (i = 0; i < 2; i++) { - pthread_cancel(threads[i]); - pthread_join(threads[i], &retval); - } - - - - for (i = 0; i < ntest_threads; i++) { - pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - res = pthread_create( &threads[i], - &attr, - timer_test, - (void *)i - ); - CYG_ASSERT( res == 0 , "pthread_create() returned error"); - } - wait_for_tick(); // Wait until the next clock tick to minimize aberations - sigev.sigev_signo = SIGRTMIN+1; - sigev.sigev_value.sival_ptr = (void*)(&timers[i]); - res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); - CYG_ASSERT( res == 0 , "timer_create() returned error"); - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 50000000; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 50000000;; - timer_cnt = 0; - res = timer_settime( timers[0], 0, &tp, NULL ); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - - sem_init(&synchro, 0, 0); - do - { res = sem_wait(&synchro); - } while( res == -1 && errno == EINTR ); - CYG_ASSERT( res == 0 , "sem_wait() returned error"); - res = timer_delete(timers[0]); - CYG_ASSERT( res == 0 , "timerdelete() returned error"); - show_times(sched_ft, nscheds, "Timer latency [many threads]"); - for (i = 0; i < ntest_threads; i++) { - pthread_cancel(threads[i]); - pthread_join(threads[i], &retval); - } - - sem_init(&synchro, 0, 0); - sem_init(&timer_sem, 0, 0); - pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); - pthread_attr_setstacksize( &attr, STACK_SIZE ); - res = pthread_create( &threads[0], - &attr, - timer_test2, - (void *)0 - ); - CYG_ASSERT( res == 0 , "pthread_create() returned error"); - - wait_for_tick(); // Wait until the next clock tick to minimize aberations - sigev.sigev_signo = SIGRTMIN+2; - sigev.sigev_value.sival_ptr = (void*)(threads[0]); - res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); - CYG_ASSERT( res == 0 , "timer_create() returned error"); - tp.it_value.tv_sec = 0; - tp.it_value.tv_nsec = 50000000; - tp.it_interval.tv_sec = 0; - tp.it_interval.tv_nsec = 50000000;; - timer_cnt = 0; - res = timer_settime( timers[0], 0, &tp, NULL ); - CYG_ASSERT( res == 0 , "timer_settime() returned error"); - - do - { res = sem_wait(&synchro); - } while( res == -1 && errno == EINTR ); - CYG_ASSERT( res == 0 , "sem_wait() returned error"); - res = timer_delete(timers[0]); - CYG_ASSERT( res == 0 , "timerdelete() returned error"); - show_times(sched_ft, nscheds, "Timer -> thread post latency"); - sem_post(&timer_sem); -// pthread_cancel(threads[0]); - pthread_join(threads[0], &retval); - - - end_of_test_group(); -} - - -//-------------------------------------------------------------------------- - -void -run_all_tests() -{ - int i; - cyg_uint32 tv[nsamples], tv0, tv1; -// cyg_uint32 min_stack, max_stack, total_stack, actual_stack, j; - cyg_tick_count_t ticks, tick0, tick1; -#ifdef CYG_SCHEDULER_LOCK_TIMINGS - cyg_uint32 lock_ave, lock_max; -#endif -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) - cyg_int32 clock_ave; -#endif - - disable_clock_latency_measurement(); - -// cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] ); - cyg_test_dump_interrupt_stack_stats( "Startup" ); - cyg_test_dump_idlethread_stack_stats( "Startup" ); - cyg_test_clear_interrupt_stack(); - - diag_printf("\neCos Kernel Timings\n"); - diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n"); -#ifdef STATS_WITHOUT_FIRST_SAMPLE - diag_printf(" second line of results have first sample removed\n"); -#endif - - cyg_thread_delay(2); // Make sure the clock is actually running - - ns_per_system_clock = 1000000/rtc_resolution[1]; - - for (i = 0; i < nsamples; i++) { - HAL_CLOCK_READ(&tv[i]); - } - tv0 = 0; - for (i = 1; i < nsamples; i++) { - tv0 += tv[i] - tv[i-1]; - } - end_of_test_group(); - - overhead = tv0 / (nsamples-1); - diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead); - diag_printf("... this value will be factored out of all other measurements\n"); - - // Try and measure how long the clock interrupt handling takes - for (i = 0; i < nsamples; i++) { - tick0 = cyg_current_time(); - while (true) { - tick1 = cyg_current_time(); - if (tick0 != tick1) break; - } - HAL_CLOCK_READ(&tv[i]); - } - tv1 = 0; - for (i = 0; i < nsamples; i++) { - tv1 += tv[i] * 1000; - } - tv1 = tv1 / nsamples; - tv1 -= overhead; // Adjust out the cost of getting the timer value - diag_printf("Clock interrupt took"); - show_ticks_in_us(tv1); - diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000); - enable_clock_latency_measurement(); - - ticks = cyg_current_time(); - - show_test_parameters(); - show_times_hdr(); - - reset_clock_latency_measurement(); - - run_thread_tests(); -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - run_mutex_tests(); -// run_mbox_tests(); -#endif - run_semaphore_tests(); - run_timer_tests(); - -#ifdef CYG_SCHEDULER_LOCK_TIMINGS - Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max); - diag_printf("\nMax lock:"); - show_ticks_in_us(lock_max); - diag_printf(", Ave lock:"); - show_ticks_in_us(lock_ave); - diag_printf("\n"); -#endif - -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) - // Display latency figures in same format as all other numbers - disable_clock_latency_measurement(); - clock_ave = (total_clock_latency*1000) / total_clock_interrupts; - show_ticks_in_us(clock_ave); - show_ticks_in_us(min_clock_latency*1000); - show_ticks_in_us(max_clock_latency*1000); - show_ticks_in_us(0); - diag_printf(" Clock/interrupt latency\n\n"); - enable_clock_latency_measurement(); -#endif - -#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) - disable_clock_latency_measurement(); - clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls; - show_ticks_in_us(clock_ave); - show_ticks_in_us(min_clock_dsr_latency*1000); - show_ticks_in_us(max_clock_dsr_latency*1000); - show_ticks_in_us(0); - diag_printf(" Clock DSR latency\n\n"); - enable_clock_latency_measurement(); -#endif - -#if 0 - disable_clock_latency_measurement(); - min_stack = STACK_SIZE; - max_stack = 0; - total_stack = 0; - for (i = 0; i < (int)NTEST_THREADS; i++) { - for (j = 0; j < STACK_SIZE; j++) { - if (stacks[i][j]) break; - } - actual_stack = STACK_SIZE-j; - if (actual_stack < min_stack) min_stack = actual_stack; - if (actual_stack > max_stack) max_stack = actual_stack; - total_stack += actual_stack; - } - for (j = 0; j < STACKSIZE; j++) { - if (((char *)stack[0])[j]) break; - } - diag_printf("%5d %5d %5d (main stack: %5d) Thread stack used (%d total)\n", - total_stack/NTEST_THREADS, min_stack, max_stack, - STACKSIZE - j, STACK_SIZE); -#endif - -// cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] ); - cyg_test_dump_interrupt_stack_stats( "All done" ); - cyg_test_dump_idlethread_stack_stats( "All done" ); - - enable_clock_latency_measurement(); - - ticks = cyg_current_time(); - diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000)); - - CYG_TEST_PASS_FINISH("Basic timing OK"); -} - -int main( int argc, char **argv ) -{ - CYG_TEST_INIT(); - - if (cyg_test_is_simulator) { - nsamples = NSAMPLES_SIM; - ntest_threads = NTEST_THREADS_SIM; - nthread_switches = NTHREAD_SWITCHES_SIM; -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - nmutexes = NMUTEXES_SIM; -#endif - nmboxes = NMBOXES_SIM; - nsemaphores = NSEMAPHORES_SIM; - nscheds = NSCHEDS_SIM; - ntimers = NTIMERS_SIM; - } else { - nsamples = NSAMPLES; - ntest_threads = NTEST_THREADS; - nthread_switches = NTHREAD_SWITCHES; -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - nmutexes = NMUTEXES; -#endif - nmboxes = NMBOXES; - nsemaphores = NSEMAPHORES; - nscheds = NSCHEDS; - ntimers = NTIMERS; - } - - // Sanity -#ifdef WORKHORSE_TEST - ntest_threads = max(512, ntest_threads); -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - nmutexes = max(1024, nmutexes); -#endif - nsemaphores = max(1024, nsemaphores); - nmboxes = max(1024, nmboxes); - ncounters = max(1024, ncounters); - ntimers = max(1024, ntimers); -#else - ntest_threads = max(64, ntest_threads); -#ifdef CYGPKG_POSIX_PTHREAD_MUTEX - nmutexes = max(32, nmutexes); -#endif - nsemaphores = max(32, nsemaphores); - nmboxes = max(32, nmboxes); - ntimers = max(32, ntimers); -#endif - - run_all_tests(); - -} - -#endif // CYGFUN_KERNEL_API_C, etc. - -// EOF tm_basic.cxx
new file mode 100644 --- /dev/null +++ b/packages/compat/posix/current/tests/tm_posix.cxx @@ -0,0 +1,1714 @@ +//========================================================================== +// +// tm_posix.cxx +// +// Basic timing test / scaffolding +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2002 Jonathan Larmour +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas,nickg +// Contributors: jlarmour +// Date: 1998-10-19 +// Description: Very simple kernel timing test +//####DESCRIPTIONEND#### +//========================================================================== + + +#include <cyg/infra/testcase.h> +#include <cyg/infra/diag.h> +#include <pkgconf/posix.h> +#include <pkgconf/system.h> +#ifdef CYGPKG_KERNEL +#include <pkgconf/kernel.h> +#endif + +#ifndef CYGPKG_POSIX_SIGNALS +#define NA_MSG "No POSIX signals" +#elif !defined(CYGPKG_POSIX_TIMERS) +#define NA_MSG "No POSIX timers" +#elif !defined(CYGPKG_POSIX_PTHREAD) +#define NA_MSG "POSIX threads not enabled" +#elif !defined(CYGFUN_KERNEL_API_C) +#define NA_MSG "Kernel C API not enabled" +#elif !defined(CYGSEM_KERNEL_SCHED_MLQUEUE) +#define NA_MSG "Kernel mlqueue scheduler not enabled" +#elif !defined(CYGVAR_KERNEL_COUNTERS_CLOCK) +#define NA_MSG "Kernel clock not enabled" +#elif CYGNUM_KERNEL_SCHED_PRIORITIES <= 12 +#define NA_MSG "Kernel scheduler properties <= 12" +#elif !defined(CYGPKG_POSIX_SEMAPHORES) +#define NA_MSG "POSIX semaphores not enabled" +#endif + +//========================================================================== + +#ifdef NA_MSG +extern "C" void +cyg_start(void) +{ + CYG_TEST_INIT(); + CYG_TEST_NA(NA_MSG); +} +#else + +#include <pkgconf/kernel.h> +#include <pkgconf/hal.h> + +#include <cyg/kernel/sched.hxx> +#include <cyg/kernel/thread.hxx> +#include <cyg/kernel/thread.inl> +#include <cyg/kernel/mutex.hxx> +#include <cyg/kernel/sema.hxx> +#include <cyg/kernel/sched.inl> +#include <cyg/kernel/clock.hxx> +#include <cyg/kernel/clock.inl> +#include <cyg/kernel/kapi.h> + +#include <cyg/infra/testcase.h> + +#include <cyg/kernel/test/stackmon.h> +#include CYGHWR_MEMORY_LAYOUT_H + + +// POSIX headers + +#include <sys/types.h> +#include <pthread.h> +#include <semaphore.h> +#include <time.h> +#include <signal.h> +#include <errno.h> + +//========================================================================== +// Define this to see the statistics with the first sample datum removed. +// This can expose the effects of caches on the speed of operations. + +#undef STATS_WITHOUT_FIRST_SAMPLE + +//========================================================================== + +// Structure used to keep track of times +typedef struct fun_times { + cyg_uint32 start; + cyg_uint32 end; +} fun_times; + +//========================================================================== + +#define STACK_SIZE (PTHREAD_STACK_MIN*2) + +// Defaults +#define NTEST_THREADS 16 +#define NMUTEXES 32 +#define NMBOXES 32 +#define NSEMAPHORES 32 +#define NTIMERS 32 + + +#define NSAMPLES 32 +#define NTHREAD_SWITCHES 128 +#define NSCHEDS 128 + +#define NSAMPLES_SIM 2 +#define NTEST_THREADS_SIM 2 +#define NTHREAD_SWITCHES_SIM 4 +#define NMUTEXES_SIM 2 +#define NMBOXES_SIM 2 +#define NSEMAPHORES_SIM 2 +#define NSCHEDS_SIM 4 +#define NTIMERS_SIM 2 + +//========================================================================== + +static int nsamples; +static int ntest_threads; +static int nthread_switches; +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX +static int nmutexes; +#endif +static int nmboxes; +static int nsemaphores; +static int nscheds; +static int ntimers; + +static char stacks[NTEST_THREADS][STACK_SIZE]; +static pthread_t threads[NTEST_THREADS]; +static int overhead; +static sem_t synchro; +static fun_times thread_ft[NTEST_THREADS]; + +static fun_times test2_ft[NTHREAD_SWITCHES]; +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX +static pthread_mutex_t test_mutexes[NMUTEXES]; +static fun_times mutex_ft[NMUTEXES]; +static pthread_t mutex_test_thread_handle; +#endif +#if 0 +static cyg_mbox test_mboxes[NMBOXES]; +static cyg_handle_t test_mbox_handles[NMBOXES]; +static fun_times mbox_ft[NMBOXES]; +static cyg_thread mbox_test_thread; +static cyg_handle_t mbox_test_thread_handle; +#endif + +static sem_t test_semaphores[NSEMAPHORES]; +static fun_times semaphore_ft[NSEMAPHORES]; +static pthread_t semaphore_test_thread_handle; + +static fun_times sched_ft[NSCHEDS]; + +static timer_t timers[NTIMERS]; +static fun_times timer_ft[NTIMERS]; + +static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; +static long ns_per_system_clock; + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) +// Data kept by kernel real time clock measuring clock interrupt latency +extern cyg_tick_count total_clock_latency, total_clock_interrupts; +extern cyg_int32 min_clock_latency, max_clock_latency; +extern bool measure_clock_latency; +#endif + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) +extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls; +extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency; +extern bool measure_clock_latency; +#endif + +//========================================================================== + +void run_sched_tests(void); +void run_thread_tests(void); +void run_thread_switch_test(void); +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX +void run_mutex_tests(void); +void run_mutex_circuit_test(void); +#endif +void run_mbox_tests(void); +void run_mbox_circuit_test(void); +void run_semaphore_tests(void); +void run_semaphore_circuit_test(void); +void run_timer_tests(void); + +//========================================================================== + +#ifndef max +#define max(n,m) (m > n ? n : m) +#endif + +//========================================================================== +// Wait until a clock tick [real time clock] has passed. This should keep it +// from happening again during a measurement, thus minimizing any fluctuations +void +wait_for_tick(void) +{ + cyg_tick_count_t tv0, tv1; + tv0 = cyg_current_time(); + while (true) { + tv1 = cyg_current_time(); + if (tv1 != tv0) break; + } +} + +//-------------------------------------------------------------------------- +// Display a number of ticks as microseconds +// Note: for improved calculation significance, values are kept in ticks*1000 +void +show_ticks_in_us(cyg_uint32 ticks) +{ + long long ns; + ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; + ns += 5; // for rounding to .01us + diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10)); +} + +//-------------------------------------------------------------------------- +// +// If the kernel is instrumented to measure clock interrupt latency, these +// measurements can be drastically perturbed by printing via "diag_printf()" +// since that code may run with interrupts disabled for long periods. +// +// In order to get accurate/reasonable latency figures _for the kernel +// primitive functions beint tested_, the kernel's latency measurements +// are suspended while the printing actually takes place. +// +// The measurements are reenabled after the printing, thus allowing for +// fair measurements of the kernel primitives, which are not distorted +// by the printing mechanisms. + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) +void +disable_clock_latency_measurement(void) +{ + wait_for_tick(); + measure_clock_latency = false; +} + +void +enable_clock_latency_measurement(void) +{ + wait_for_tick(); + measure_clock_latency = true; +} + +// Ensure that the measurements are reasonable (no startup anomalies) +void +reset_clock_latency_measurement(void) +{ + disable_clock_latency_measurement(); + total_clock_latency = 0; + total_clock_interrupts = 0; + min_clock_latency = 0x7FFFFFFF; + max_clock_latency = 0; +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) + total_clock_dsr_latency = 0; + total_clock_dsr_calls = 0; + min_clock_dsr_latency = 0x7FFFFFFF; + max_clock_dsr_latency = 0; +#endif + enable_clock_latency_measurement(); + +} +#else +#define disable_clock_latency_measurement() +#define enable_clock_latency_measurement() +#define reset_clock_latency_measurement() +#endif + +//-------------------------------------------------------------------------- + +void +show_times_hdr(void) +{ + disable_clock_latency_measurement(); + diag_printf("\n"); + diag_printf(" Confidence\n"); + diag_printf(" Ave Min Max Var Ave Min Function\n"); + diag_printf(" ====== ====== ====== ====== ========== ========\n"); + enable_clock_latency_measurement(); +} + +void +show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first) +{ + int i, delta, min, max, con_ave, con_min, ave_dev; + int start_sample, total_samples; + cyg_int32 total, ave; + + if (ignore_first) { + start_sample = 1; + total_samples = nsamples-1; + } else { + start_sample = 0; + total_samples = nsamples; + } + total = 0; + min = 0x7FFFFFFF; + max = 0; + for (i = start_sample; i < nsamples; i++) { + if (ft[i].end < ft[i].start) { + // Clock wrapped around (timer tick) + delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; + } else { + delta = ft[i].end - ft[i].start; + } + delta -= overhead; + if (delta < 0) delta = 0; + delta *= 1000; + total += delta; + if (delta < min) min = delta; + if (delta > max) max = delta; + } + ave = total / total_samples; + total = 0; + ave_dev = 0; + for (i = start_sample; i < nsamples; i++) { + if (ft[i].end < ft[i].start) { + // Clock wrapped around (timer tick) + delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; + } else { + delta = ft[i].end - ft[i].start; + } + delta -= overhead; + if (delta < 0) delta = 0; + delta *= 1000; + delta = delta - ave; + if (delta < 0) delta = -delta; + ave_dev += delta; + } + ave_dev /= total_samples; + con_ave = 0; + con_min = 0; + for (i = start_sample; i < nsamples; i++) { + if (ft[i].end < ft[i].start) { + // Clock wrapped around (timer tick) + delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; + } else { + delta = ft[i].end - ft[i].start; + } + delta -= overhead; + if (delta < 0) delta = 0; + delta *= 1000; + if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; + if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; + } + con_ave = (con_ave * 100) / total_samples; + con_min = (con_min * 100) / total_samples; + show_ticks_in_us(ave); + show_ticks_in_us(min); + show_ticks_in_us(max); + show_ticks_in_us(ave_dev); + disable_clock_latency_measurement(); + diag_printf(" %3d%% %3d%%", con_ave, con_min); + diag_printf(" %s\n", title); + enable_clock_latency_measurement(); +} + +void +show_times(fun_times ft[], int nsamples, char *title) +{ + show_times_detail(ft, nsamples, title, false); +#ifdef STATS_WITHOUT_FIRST_SAMPLE + show_times_detail(ft, nsamples, "", true); +#endif +} + +//-------------------------------------------------------------------------- + +void +show_test_parameters(void) +{ + disable_clock_latency_measurement(); + diag_printf("\nTesting parameters:\n"); + diag_printf(" Clock samples: %5d\n", nsamples); + diag_printf(" Threads: %5d\n", ntest_threads); + diag_printf(" Thread switches: %5d\n", nthread_switches); +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + diag_printf(" Mutexes: %5d\n", nmutexes); +#endif + diag_printf(" Mailboxes: %5d\n", nmboxes); + diag_printf(" Semaphores: %5d\n", nsemaphores); + diag_printf(" Scheduler operations: %5d\n", nscheds); + diag_printf(" Timers: %5d\n", ntimers); + diag_printf("\n"); + enable_clock_latency_measurement(); +} + +void +end_of_test_group(void) +{ + disable_clock_latency_measurement(); + diag_printf("\n"); + enable_clock_latency_measurement(); +} + +//-------------------------------------------------------------------------- +// Compute a name for a thread + +char * +thread_name(char *basename, int indx) { + return "<<NULL>>"; // Not currently used +} + +//-------------------------------------------------------------------------- +// test0 - null test, just return + +void * +test0(void *indx) +{ + return indx; +} + +//-------------------------------------------------------------------------- +// test3 - loop, yeilding repeatedly and checking for cancellation + +void * +test3(void *indx) +{ + for(;;) + { + sched_yield(); + pthread_testcancel(); + } + + return indx; +} + +//-------------------------------------------------------------------------- +// test1 - empty test, simply exit. Last thread signals parent. + +void * +test1( void *indx) +{ + if ((cyg_uint32)indx == (cyg_uint32)(ntest_threads-1)) { + sem_post(&synchro); // Signal that last thread is dying + } + return indx; +} + +//-------------------------------------------------------------------------- +// test2 - measure thread switch times + +void * +test2(void *indx) +{ + int i; + for (i = 0; i < nthread_switches; i++) { + if ((int)indx == 0) { + HAL_CLOCK_READ(&test2_ft[i].start); + } else { + HAL_CLOCK_READ(&test2_ft[i].end); + } + sched_yield(); + } + if ((int)indx == 1) { + sem_post(&synchro); + } + + return indx; +} +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX +//-------------------------------------------------------------------------- +// Full-circuit mutex unlock/lock test + +void * +mutex_test(void * indx) +{ + int i; + pthread_mutex_lock(&test_mutexes[0]); + for (i = 0; i < nmutexes; i++) { + sem_wait(&synchro); + wait_for_tick(); // Wait until the next clock tick to minimize aberations + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_unlock(&test_mutexes[0]); + pthread_mutex_lock(&test_mutexes[0]); + sem_post(&synchro); + } + return indx; +} + +//-------------------------------------------------------------------------- +// Full-circuit mbox put/get test + +#if 0 +void +mbox_test(cyg_uint32 indx) +{ + void *item; + do { + item = cyg_mbox_get(test_mbox_handles[0]); + HAL_CLOCK_READ(&mbox_ft[(int)item].end); + cyg_semaphore_post(&synchro); + } while ((int)item != (nmboxes-1)); + cyg_thread_exit(0); +} +#endif +#endif +//-------------------------------------------------------------------------- +// Full-circuit semaphore post/wait test + +void * +semaphore_test(void * indx) +{ + int i; + for (i = 0; i < nsemaphores; i++) { + sem_wait(&test_semaphores[0]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + sem_post(&synchro); + } + return indx; +} + +//-------------------------------------------------------------------------- +// +// This set of tests is used to measure kernel primitives that deal with threads +// + +void +run_thread_tests(void) +{ + + + int i; + struct sched_param schedparam; + pthread_attr_t attr; + int policy; + void *retval; + + // Set my priority higher than any I plan to create + schedparam.sched_priority = 30; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + // Initiaize thread creation attributes + + pthread_attr_init( &attr ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &threads[i], + &attr, + test0, + (void *)i + ); + + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Create thread"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + sched_yield(); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Yield thread [all lower priority]"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + + schedparam.sched_priority = 11; + pthread_attr_setschedparam( &attr, &schedparam ); + pthread_setschedparam(threads[i], SCHED_RR, &schedparam); + + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Set priority"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + pthread_getschedparam( threads[i], &policy, &schedparam ); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Get priority"); + + cyg_thread_delay(1); // Let the test threads run + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + pthread_join(threads[i], &retval); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Join exited thread"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + sched_yield(); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Yield [no other] thread"); + + + // Recreate the test set + + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + for (i = 0; i < ntest_threads; i++) { + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &threads[i], + &attr, + test3, + (void *)i + ); + } + + cyg_thread_delay(1); // Let the test threads run + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + pthread_cancel(threads[i]); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Cancel [running] thread"); + + cyg_thread_delay(1); // Let the test threads do their cancellations + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + pthread_join(threads[i], &retval); + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Join [cancelled] thread"); + + + // Set my priority lower than any I plan to create + schedparam.sched_priority = 5; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + // Set up the end-of-threads synchronizer + sem_init(&synchro, 0, 0); + + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntest_threads; i++) { + HAL_CLOCK_READ(&thread_ft[i].start); + + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &threads[i], + &attr, + test2, + (void *)i + ); + + HAL_CLOCK_READ(&thread_ft[i].end); + } + show_times(thread_ft, ntest_threads, "Create [high priority] thread"); + + sem_wait(&synchro); // Wait for all threads to finish + + // Make sure they are all dead + for (i = 0; i < ntest_threads; i++) { + pthread_join(threads[i], &retval); + } + + run_thread_switch_test(); + end_of_test_group(); + +} + +//-------------------------------------------------------------------------- + +void +run_thread_switch_test(void) +{ + + int i; + struct sched_param schedparam; + pthread_attr_t attr; + void *retval; + + // Set my priority higher than any I plan to create + schedparam.sched_priority = 30; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + // Initiaize thread creation attributes + + pthread_attr_init( &attr ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + // Set up the end-of-threads synchronizer + + sem_init(&synchro, 0, 0); + + // Set up for thread context switch + + for (i = 0; i < 2; i++) { + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &threads[i], + &attr, + test2, + (void *)i + ); + } + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + + sem_wait(&synchro); + + show_times(test2_ft, nthread_switches, "Thread switch"); + + // Clean up + for (i = 0; i < 2; i++) { + pthread_join(threads[i], &retval); + } + +} + + +//-------------------------------------------------------------------------- +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX +void +run_mutex_tests(void) +{ + + int i; + pthread_mutexattr_t attr; + + pthread_mutexattr_init( &attr ); + + // Mutex primitives + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_init(&test_mutexes[i], &attr); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Init mutex"); + + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_lock(&test_mutexes[i]); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_unlock(&test_mutexes[i]); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Unlock [locked] mutex"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_trylock(&test_mutexes[i]); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_trylock(&test_mutexes[i]); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Trylock [locked] mutex"); + + // Must unlock mutices before destroying them. + for (i = 0; i < nmutexes; i++) { + pthread_mutex_unlock(&test_mutexes[i]); + } + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmutexes; i++) { + HAL_CLOCK_READ(&mutex_ft[i].start); + pthread_mutex_destroy(&test_mutexes[i]); + HAL_CLOCK_READ(&mutex_ft[i].end); + } + show_times(mutex_ft, nmutexes, "Destroy mutex"); + + + run_mutex_circuit_test(); + end_of_test_group(); +} + +//-------------------------------------------------------------------------- + +void +run_mutex_circuit_test(void) +{ + int i; + pthread_mutexattr_t mattr; + struct sched_param schedparam; + pthread_attr_t attr; + void *retval; + + // Set my priority lower than any I plan to create + schedparam.sched_priority = 5; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + // Initiaize thread creation attributes + + pthread_attr_init( &attr ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + // Set up for full mutex unlock/lock test + pthread_mutexattr_init( &mattr ); + pthread_mutex_init(&test_mutexes[0], &mattr); + sem_init(&synchro, 0, 0); + + pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &mutex_test_thread_handle, + &attr, + mutex_test, + (void *)0 + ); + + // Need to raise priority so that this thread will block on the "lock" + schedparam.sched_priority = 20; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + for (i = 0; i < nmutexes; i++) { + sem_post(&synchro); + pthread_mutex_lock(&test_mutexes[0]); + HAL_CLOCK_READ(&mutex_ft[i].end); + pthread_mutex_unlock(&test_mutexes[0]); + sem_wait(&synchro); + } + pthread_join(mutex_test_thread_handle, &retval); + show_times(mutex_ft, nmutexes, "Unlock/Lock mutex"); + +} + +#endif +//-------------------------------------------------------------------------- +// Message queue tests + +// Currently disabled, pending implementation of POSIX message queues + +#if 0 +void +run_mbox_tests(void) +{ + int i, cnt; + void *item; + // Mailbox primitives + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Create mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cnt = cyg_mbox_peek(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Peek [empty] mbox"); + +#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_put(test_mbox_handles[i], (void *)i); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Put [first] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cnt = cyg_mbox_peek(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_put(test_mbox_handles[i], (void *)i); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Put [second] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cnt = cyg_mbox_peek(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_get(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Get [first] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_get(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Get [second] mbox"); +#endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_tryput(test_mbox_handles[i], (void *)i); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Tryput [first] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_peek_item(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_tryget(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_peek_item(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Peek item [empty] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + item = cyg_mbox_tryget(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Tryget [empty] mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_waiting_to_get(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Waiting to get mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_waiting_to_put(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Waiting to put mbox"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nmboxes; i++) { + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_delete(test_mbox_handles[i]); + HAL_CLOCK_READ(&mbox_ft[i].end); + } + show_times(mbox_ft, nmboxes, "Delete mbox"); + + run_mbox_circuit_test(); + end_of_test_group(); +} + +//-------------------------------------------------------------------------- + +void +run_mbox_circuit_test(void) +{ +#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT + int i; + // Set my priority lower than any I plan to create + cyg_thread_set_priority(cyg_thread_self(), 3); + // Set up for full mbox put/get test + cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]); + cyg_semaphore_init(&synchro, 0); + cyg_thread_create(2, // Priority - just a number + mbox_test, // entry + 0, // index + thread_name("thread", 0), // Name + &stacks[0][0], // Stack + STACK_SIZE, // Size + &mbox_test_thread_handle, // Handle + &mbox_test_thread // Thread data structure + ); + cyg_thread_resume(mbox_test_thread_handle); + for (i = 0; i < nmboxes; i++) { + wait_for_tick(); // Wait until the next clock tick to minimize aberations + HAL_CLOCK_READ(&mbox_ft[i].start); + cyg_mbox_put(test_mbox_handles[0], (void *)i); + cyg_semaphore_wait(&synchro); + } + cyg_thread_delete(mbox_test_thread_handle); + show_times(mbox_ft, nmboxes, "Put/Get mbox"); +#endif +} + +#endif + +//-------------------------------------------------------------------------- + +void +run_semaphore_tests(void) +{ + + int i; + int sem_val; + + // Semaphore primitives + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_init(&test_semaphores[i], 0, 0); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Init semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_post(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Post [0] semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_wait(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_trywait(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + sem_post(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_trywait(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_getvalue(&test_semaphores[i], &sem_val); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Get value of semaphore"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < nsemaphores; i++) { + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_destroy(&test_semaphores[i]); + HAL_CLOCK_READ(&semaphore_ft[i].end); + } + show_times(semaphore_ft, nsemaphores, "Destroy semaphore"); + + run_semaphore_circuit_test(); + end_of_test_group(); +} + +//-------------------------------------------------------------------------- + +void +run_semaphore_circuit_test(void) +{ + + int i; + struct sched_param schedparam; + pthread_attr_t attr; + void *retval; + + // Set my priority lower than any I plan to create + schedparam.sched_priority = 5; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + // Initiaize thread creation attributes + + pthread_attr_init( &attr ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + // Set up for full semaphore post/wait test + sem_init(&test_semaphores[0], 0, 0); + sem_init(&synchro, 0, 0); + + pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + pthread_create( &semaphore_test_thread_handle, + &attr, + semaphore_test, + (void *)0 + ); + + + for (i = 0; i < nsemaphores; i++) { + wait_for_tick(); // Wait until the next clock tick to minimize aberations + HAL_CLOCK_READ(&semaphore_ft[i].start); + sem_post(&test_semaphores[0]); + sem_wait(&synchro); + } + pthread_join(semaphore_test_thread_handle, &retval); + + show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore"); + + +} + +//-------------------------------------------------------------------------- + +// Timer callback function +void +sigrt0(int signo, siginfo_t *info, void *context) +{ + diag_printf("sigrt0 called\n"); + // empty call back +} + +// Callback used to test determinancy +static volatile int timer_cnt; +void +sigrt1(int signo, siginfo_t *info, void *context) +{ + if (timer_cnt == nscheds) return; + sched_ft[timer_cnt].start = 0; + HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); + if (timer_cnt == nscheds) { + sem_post(&synchro); + } +} + +static sem_t timer_sem; + +static void +sigrt2(int signo, siginfo_t *info, void *context) +{ + if (timer_cnt == nscheds) { + sem_post(&synchro); + sem_post(&timer_sem); + } else { + sched_ft[timer_cnt].start = 0; + sem_post(&timer_sem); + } +} + +// Null thread, used to keep scheduler busy +void * +timer_test(void * id) +{ + while (true) { + cyg_thread_yield(); + pthread_testcancel(); + } + + return id; +} + +// Thread that suspends itself at the first opportunity +void * +timer_test2(void *id) +{ + while (timer_cnt != nscheds) { + HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); + sem_wait(&timer_sem); + } + return id; +} + +void +run_timer_tests(void) +{ + int res; + int i; + struct sigaction sa; + struct sigevent sigev; + struct itimerspec tp; + + // Install signal handlers + sigemptyset( &sa.sa_mask ); + sa.sa_flags = SA_SIGINFO; + + sa.sa_sigaction = sigrt0; + sigaction( SIGRTMIN, &sa, NULL ); + + sa.sa_sigaction = sigrt1; + sigaction( SIGRTMIN+1, &sa, NULL ); + + sa.sa_sigaction = sigrt2; + sigaction( SIGRTMIN+2, &sa, NULL ); + + // Set up common bits of sigevent + + sigev.sigev_notify = SIGEV_SIGNAL; + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntimers; i++) { + HAL_CLOCK_READ(&timer_ft[i].start); + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_value.sival_ptr = (void*)(&timers[i]); + res = timer_create( CLOCK_REALTIME, &sigev, &timers[i]); + HAL_CLOCK_READ(&timer_ft[i].end); + CYG_ASSERT( res == 0 , "timer_create() returned error"); + } + show_times(timer_ft, ntimers, "Create timer"); + + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 0; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 0; + for (i = 0; i < ntimers; i++) { + HAL_CLOCK_READ(&timer_ft[i].start); + res = timer_settime( timers[i], 0, &tp, NULL ); + HAL_CLOCK_READ(&timer_ft[i].end); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + } + show_times(timer_ft, ntimers, "Initialize timer to zero"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + tp.it_value.tv_sec = 1; + tp.it_value.tv_nsec = 250000000; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 0; + for (i = 0; i < ntimers; i++) { + HAL_CLOCK_READ(&timer_ft[i].start); + res = timer_settime( timers[i], 0, &tp, NULL ); + HAL_CLOCK_READ(&timer_ft[i].end); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + } + show_times(timer_ft, ntimers, "Initialize timer to 1.25 sec"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 0; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 0; + for (i = 0; i < ntimers; i++) { + HAL_CLOCK_READ(&timer_ft[i].start); + res = timer_settime( timers[i], 0, &tp, NULL ); + HAL_CLOCK_READ(&timer_ft[i].end); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + } + show_times(timer_ft, ntimers, "Disable timer"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + for (i = 0; i < ntimers; i++) { + HAL_CLOCK_READ(&timer_ft[i].start); + res = timer_delete( timers[i] ); + HAL_CLOCK_READ(&timer_ft[i].end); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + } + show_times(timer_ft, ntimers, "Delete timer"); + + + + sigev.sigev_signo = SIGRTMIN+1; + sigev.sigev_value.sival_ptr = (void*)(&timers[i]); + res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); + CYG_ASSERT( res == 0 , "timer_create() returned error"); + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 50000000; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 50000000;; + timer_cnt = 0; + res = timer_settime( timers[0], 0, &tp, NULL ); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + sem_init(&synchro, 0, 0); + wait_for_tick(); // Wait until the next clock tick to minimize aberations + do + { res = sem_wait(&synchro); + } while( res == -1 && errno == EINTR ); + CYG_ASSERT( res == 0 , "sem_wait() returned error"); + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 0; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 0; + res = timer_settime( timers[0], 0, &tp, NULL ); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + res = timer_delete( timers[0] ); + CYG_ASSERT( res == 0 , "timer_delete() returned error"); + show_times(sched_ft, nscheds, "Timer latency [0 threads]"); + + + + + struct sched_param schedparam; + pthread_attr_t attr; + void *retval; + + // Set my priority higher than any I plan to create + schedparam.sched_priority = 20; + pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); + + + // Initiaize thread creation attributes + + pthread_attr_init( &attr ); + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); + pthread_attr_setschedpolicy( &attr, SCHED_RR ); + schedparam.sched_priority = 10; + pthread_attr_setschedparam( &attr, &schedparam ); + + for (i = 0; i < 2; i++) { + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + res = pthread_create( &threads[i], + &attr, + timer_test, + (void *)i + ); + CYG_ASSERT( res == 0 , "pthread_create() returned error"); + } + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + + sigev.sigev_signo = SIGRTMIN+1; + sigev.sigev_value.sival_ptr = (void*)(&timers[i]); + res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); + CYG_ASSERT( res == 0 , "timer_create() returned error"); + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 50000000; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 50000000;; + timer_cnt = 0; + res = timer_settime( timers[0], 0, &tp, NULL ); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + + sem_init(&synchro, 0, 0); + do + { res = sem_wait(&synchro); + } while( res == -1 && errno == EINTR ); + CYG_ASSERT( res == 0 , "sem_wait() returned error"); + res = timer_delete(timers[0]); + CYG_ASSERT( res == 0 , "timerdelete() returned error"); + show_times(sched_ft, nscheds, "Timer latency [2 threads]"); + for (i = 0; i < 2; i++) { + pthread_cancel(threads[i]); + pthread_join(threads[i], &retval); + } + + + + for (i = 0; i < ntest_threads; i++) { + pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + res = pthread_create( &threads[i], + &attr, + timer_test, + (void *)i + ); + CYG_ASSERT( res == 0 , "pthread_create() returned error"); + } + wait_for_tick(); // Wait until the next clock tick to minimize aberations + sigev.sigev_signo = SIGRTMIN+1; + sigev.sigev_value.sival_ptr = (void*)(&timers[i]); + res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); + CYG_ASSERT( res == 0 , "timer_create() returned error"); + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 50000000; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 50000000;; + timer_cnt = 0; + res = timer_settime( timers[0], 0, &tp, NULL ); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + + sem_init(&synchro, 0, 0); + do + { res = sem_wait(&synchro); + } while( res == -1 && errno == EINTR ); + CYG_ASSERT( res == 0 , "sem_wait() returned error"); + res = timer_delete(timers[0]); + CYG_ASSERT( res == 0 , "timerdelete() returned error"); + show_times(sched_ft, nscheds, "Timer latency [many threads]"); + for (i = 0; i < ntest_threads; i++) { + pthread_cancel(threads[i]); + pthread_join(threads[i], &retval); + } + + sem_init(&synchro, 0, 0); + sem_init(&timer_sem, 0, 0); + pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); + pthread_attr_setstacksize( &attr, STACK_SIZE ); + res = pthread_create( &threads[0], + &attr, + timer_test2, + (void *)0 + ); + CYG_ASSERT( res == 0 , "pthread_create() returned error"); + + wait_for_tick(); // Wait until the next clock tick to minimize aberations + sigev.sigev_signo = SIGRTMIN+2; + sigev.sigev_value.sival_ptr = (void*)(threads[0]); + res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); + CYG_ASSERT( res == 0 , "timer_create() returned error"); + tp.it_value.tv_sec = 0; + tp.it_value.tv_nsec = 50000000; + tp.it_interval.tv_sec = 0; + tp.it_interval.tv_nsec = 50000000;; + timer_cnt = 0; + res = timer_settime( timers[0], 0, &tp, NULL ); + CYG_ASSERT( res == 0 , "timer_settime() returned error"); + + do + { res = sem_wait(&synchro); + } while( res == -1 && errno == EINTR ); + CYG_ASSERT( res == 0 , "sem_wait() returned error"); + res = timer_delete(timers[0]); + CYG_ASSERT( res == 0 , "timerdelete() returned error"); + show_times(sched_ft, nscheds, "Timer -> thread post latency"); + sem_post(&timer_sem); +// pthread_cancel(threads[0]); + pthread_join(threads[0], &retval); + + + end_of_test_group(); +} + + +//-------------------------------------------------------------------------- + +void +run_all_tests() +{ + int i; + cyg_uint32 tv[nsamples], tv0, tv1; +// cyg_uint32 min_stack, max_stack, total_stack, actual_stack, j; + cyg_tick_count_t ticks, tick0, tick1; +#ifdef CYG_SCHEDULER_LOCK_TIMINGS + cyg_uint32 lock_ave, lock_max; +#endif +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) + cyg_int32 clock_ave; +#endif + + disable_clock_latency_measurement(); + +// cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] ); + cyg_test_dump_interrupt_stack_stats( "Startup" ); + cyg_test_dump_idlethread_stack_stats( "Startup" ); + cyg_test_clear_interrupt_stack(); + + diag_printf("\neCos Kernel Timings\n"); + diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n"); +#ifdef STATS_WITHOUT_FIRST_SAMPLE + diag_printf(" second line of results have first sample removed\n"); +#endif + + cyg_thread_delay(2); // Make sure the clock is actually running + + ns_per_system_clock = 1000000/rtc_resolution[1]; + + for (i = 0; i < nsamples; i++) { + HAL_CLOCK_READ(&tv[i]); + } + tv0 = 0; + for (i = 1; i < nsamples; i++) { + tv0 += tv[i] - tv[i-1]; + } + end_of_test_group(); + + overhead = tv0 / (nsamples-1); + diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead); + diag_printf("... this value will be factored out of all other measurements\n"); + + // Try and measure how long the clock interrupt handling takes + for (i = 0; i < nsamples; i++) { + tick0 = cyg_current_time(); + while (true) { + tick1 = cyg_current_time(); + if (tick0 != tick1) break; + } + HAL_CLOCK_READ(&tv[i]); + } + tv1 = 0; + for (i = 0; i < nsamples; i++) { + tv1 += tv[i] * 1000; + } + tv1 = tv1 / nsamples; + tv1 -= overhead; // Adjust out the cost of getting the timer value + diag_printf("Clock interrupt took"); + show_ticks_in_us(tv1); + diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000); + enable_clock_latency_measurement(); + + ticks = cyg_current_time(); + + show_test_parameters(); + show_times_hdr(); + + reset_clock_latency_measurement(); + + run_thread_tests(); +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + run_mutex_tests(); +// run_mbox_tests(); +#endif + run_semaphore_tests(); + run_timer_tests(); + +#ifdef CYG_SCHEDULER_LOCK_TIMINGS + Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max); + diag_printf("\nMax lock:"); + show_ticks_in_us(lock_max); + diag_printf(", Ave lock:"); + show_ticks_in_us(lock_ave); + diag_printf("\n"); +#endif + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) + // Display latency figures in same format as all other numbers + disable_clock_latency_measurement(); + clock_ave = (total_clock_latency*1000) / total_clock_interrupts; + show_ticks_in_us(clock_ave); + show_ticks_in_us(min_clock_latency*1000); + show_ticks_in_us(max_clock_latency*1000); + show_ticks_in_us(0); + diag_printf(" Clock/interrupt latency\n\n"); + enable_clock_latency_measurement(); +#endif + +#if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) + disable_clock_latency_measurement(); + clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls; + show_ticks_in_us(clock_ave); + show_ticks_in_us(min_clock_dsr_latency*1000); + show_ticks_in_us(max_clock_dsr_latency*1000); + show_ticks_in_us(0); + diag_printf(" Clock DSR latency\n\n"); + enable_clock_latency_measurement(); +#endif + +#if 0 + disable_clock_latency_measurement(); + min_stack = STACK_SIZE; + max_stack = 0; + total_stack = 0; + for (i = 0; i < (int)NTEST_THREADS; i++) { + for (j = 0; j < STACK_SIZE; j++) { + if (stacks[i][j]) break; + } + actual_stack = STACK_SIZE-j; + if (actual_stack < min_stack) min_stack = actual_stack; + if (actual_stack > max_stack) max_stack = actual_stack; + total_stack += actual_stack; + } + for (j = 0; j < STACKSIZE; j++) { + if (((char *)stack[0])[j]) break; + } + diag_printf("%5d %5d %5d (main stack: %5d) Thread stack used (%d total)\n", + total_stack/NTEST_THREADS, min_stack, max_stack, + STACKSIZE - j, STACK_SIZE); +#endif + +// cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] ); + cyg_test_dump_interrupt_stack_stats( "All done" ); + cyg_test_dump_idlethread_stack_stats( "All done" ); + + enable_clock_latency_measurement(); + + ticks = cyg_current_time(); + diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000)); + + CYG_TEST_PASS_FINISH("Basic timing OK"); +} + +int main( int argc, char **argv ) +{ + CYG_TEST_INIT(); + + if (cyg_test_is_simulator) { + nsamples = NSAMPLES_SIM; + ntest_threads = NTEST_THREADS_SIM; + nthread_switches = NTHREAD_SWITCHES_SIM; +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + nmutexes = NMUTEXES_SIM; +#endif + nmboxes = NMBOXES_SIM; + nsemaphores = NSEMAPHORES_SIM; + nscheds = NSCHEDS_SIM; + ntimers = NTIMERS_SIM; + } else { + nsamples = NSAMPLES; + ntest_threads = NTEST_THREADS; + nthread_switches = NTHREAD_SWITCHES; +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + nmutexes = NMUTEXES; +#endif + nmboxes = NMBOXES; + nsemaphores = NSEMAPHORES; + nscheds = NSCHEDS; + ntimers = NTIMERS; + } + + // Sanity +#ifdef WORKHORSE_TEST + ntest_threads = max(512, ntest_threads); +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + nmutexes = max(1024, nmutexes); +#endif + nsemaphores = max(1024, nsemaphores); + nmboxes = max(1024, nmboxes); + ncounters = max(1024, ncounters); + ntimers = max(1024, ntimers); +#else + ntest_threads = max(64, ntest_threads); +#ifdef CYGPKG_POSIX_PTHREAD_MUTEX + nmutexes = max(32, nmutexes); +#endif + nsemaphores = max(32, nsemaphores); + nmboxes = max(32, nmboxes); + ntimers = max(32, ntimers); +#endif + + run_all_tests(); + +} + +#endif // CYGFUN_KERNEL_API_C, etc. + +// EOF tm_posix.cxx
