RTAI 3.3 test4: Stuck in rt_task_wait_period(): Code example

J. Niehaus Niehaus at vsys.de
Wed Jan 25 16:13:07 CET 2006


On Fri, 13 Jan 2006 10:01:58 +0100 "J. Niehaus" <Niehaus at vsys.de> wrote:

Hi,

as the problem is not solved yet I reduced our application to a small 
rtai-program which still reproduces the bug on all machines I tested it on.

We use rtai 3.3test4 with kernel 2.6.14.6 and busybox 1.01.

The program creates four threads and moves data between them using pthread_mutex_t and pthread_cond_t. After some seconds one or all the threads do not react anymore. One of the tasks runs in HRT the others are SRT.

It would be great if you could test the code on your machine and/or try to find the bug. The slower the cpu we use the more probable the error occurs. Normally 
'rtaipthreads -t 120 -p 10' reproduces the error (running 120sec, using a 10ms period, tested on cpus up to PIII, 1200Mhz).

Thanks,
	Jens

----------------- rtaipthreads.c -----------------
/*
 * rtaipthreads.c
 *
 * Copyright (C) 2006  J. Niehaus (Niehaus at vsys.de)
 * 
 * This program demonstrates posix threads with mutexes and does not work
 * properly with rtai3.3test4
 *
 * Compilation:
 * gcc -Wall -pedantic -O3 -g -I. -I/usr/realtime/include -g \n
 *     -I/usr/src/linux-2.6.14.6-RT/include -Wall -Wstrict-prototypes \n
 *     -pipe -std=gnu99 rtaipthreads.c -L/usr/realtime/lib -llxrt -lpthread \n
 *     -o rtaipthreads
 *
 * What it does:
 * Creates four additional tasks that communicate using pthread_mutex_t and
 * pthread_cond_t. Two of them are periodic (clienthrt and clientsrt). They
 * both send data to the thread called server. This one forwards the data to
 * the thread called listener and also sends it back to the sending task.
 *
 * All four tasks increase a global variable. These variables are all printed
 * by the main task. If one of the numbers stays the same that task got stuck.
 *
 *
 *
 * This program 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
 * of the License, or (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,MA  02111-1307,USA.
 */

#include <stdio.h>
#include <sys/mman.h>

#include <rtai_posix.h>

typedef struct
{
    pthread_t       thread;
    pthread_mutex_t datamutex;
    pthread_mutex_t condmutex;
    pthread_cond_t  cond;
    int             id;
    int             avail;
    int             data;
    int             alive;
    int             period;
} commstuff_t;

commstuff_t *initthread( void * (*func)(void *), int id, int ms );
void terminatethread( commstuff_t *cs );
int  getdata( commstuff_t *cs );
void putdata( commstuff_t *cs, int id );
void wakeup( commstuff_t *cs );
int  waitfordata( commstuff_t *cs );
void shutdown( void );
void mainloop( int periods );
void usage( void );
void parse( int argc, char *argv[], int *period, int *ms );
void dostuff( commstuff_t *cs );
void *serverfunc( void *x );
void *clienthrtfunc( void *param );
void *clientsrtfunc( void *param );
void *listenerfunc( void *param );

commstuff_t *server, *listener, *clienthrt, *clientsrt;
int         running;

int main( int argc, char *argv[] )
{
    RT_TASK *rttask;
    struct sched_param sp;
    int periods;
    int ms;

    rt_allow_nonroot_hrt();

    sp.sched_priority = sched_get_priority_max( SCHED_FIFO ) - 1;
     
    if( sched_setscheduler( 0, SCHED_FIFO, &sp ) == -1 )
    {
        fprintf( stderr, "Cannot set scheduler\n" );
        return 1;
    }
    mlockall( MCL_CURRENT | MCL_FUTURE );
    rttask = rt_task_init( 4,  0, 0, 0 );
    if ( !rttask )
    {
        fprintf( stderr, "Cannot init maintask\n" );
        return 1;
    }    
    rt_set_oneshot_mode();
    start_rt_timer( nano2count(100000) );
    running = 1;
	parse( argc, argv, &periods, &ms );

    listener = initthread( listenerfunc, 1, 0 );
    server  = initthread( serverfunc, 0, 0 );
    clienthrt = initthread( clienthrtfunc, 2, ms );
    clientsrt = initthread( clientsrtfunc, 3, ms );

    mainloop( periods );

    shutdown();
    stop_rt_timer();
    rt_task_delete( rttask );
    munlockall();
    sp.sched_priority = 0;
    sched_setscheduler( 0, SCHED_OTHER, &sp );
}

commstuff_t *initthread( void * (*func)(void *), int id, int ms )
{
    commstuff_t *cs;
    
    cs = malloc( sizeof( commstuff_t ) );
    pthread_mutex_init_rt( &cs->datamutex, NULL );
    pthread_mutex_init_rt( &cs->condmutex, NULL );
    pthread_cond_init_rt(  &cs->cond,      NULL );
    cs->avail  = 0;
    cs->data   = 0;
    cs->id     = id;
    cs->alive  = 0;
    cs->period = ms;
    pthread_create_rt( &cs->thread, NULL, func, cs );
    return cs;
}

void terminatethread( commstuff_t *cs )
{
    putdata( cs, (1<<4) );
    pthread_join_rt( cs->thread, NULL );
    pthread_mutex_destroy_rt( &cs->condmutex );
    pthread_cond_destroy_rt(  &cs->cond );
    pthread_mutex_destroy_rt( &cs->datamutex );
    free( cs );
}

int getdata( commstuff_t *cs )
{
    int val;

    pthread_mutex_lock_rt( &cs->datamutex );
    val = cs->data;
    cs->data = 0;
    pthread_mutex_unlock_rt( &cs->datamutex );
    return val;
}

void putdata( commstuff_t *cs, int id )
{
    pthread_mutex_lock_rt( &cs->datamutex );
    cs->data |= (1<<id);
    pthread_mutex_unlock_rt( &cs->datamutex );
    wakeup( cs );
}

void wakeup( commstuff_t *cs )
{
    pthread_mutex_lock_rt( &cs->condmutex );
    cs->avail = 1;
    pthread_cond_signal_rt( &cs->cond );
    pthread_mutex_unlock_rt( &cs->condmutex );
}

int waitfordata( commstuff_t *cs )
{
    pthread_mutex_lock_rt( &cs->condmutex );
    while ( !cs->avail )
    {
        pthread_cond_wait_rt( &cs->cond, &cs->condmutex );
    }
    cs->avail = 0;
    pthread_mutex_unlock_rt( &cs->condmutex );
    return getdata( cs );
}

void shutdown( void )
{
    printf( "Shutting threads down\n" );
    running = 0;
    terminatethread( server );
    terminatethread( listener );
    terminatethread( clienthrt );
    terminatethread( clientsrt );
    printf( "All threads finished\n" );
}

void mainloop( int periods )
{
    int i;

    printf( "Starting mainloop\n" );
    for( i=0; i<=periods; i++ )
    {
        printf( "%i) Server: %i, listener: %i, clienthrt: %i, clientsrt: %i\n",
                i, server->alive, listener->alive, clienthrt->alive,
                clientsrt->alive );
        sleep( 1 );
    }
}

void usage( void )
{
    printf( "Usage: rtaipthreads [ -t periods ] [-p cycle]\n" );
    printf( "        -t: time in seconds (default 5)\n" );
    printf( "        -p: period for cyclic threads in ms (default 100)\n" );
}

void parse( int argc, char *argv[], int *period, int *ms )
{
    *period = 5;
    *ms = 100;
    argv++;
	--argc;
    while ( argc )
    {
        if ( !strcmp( argv[0], "-t" ) )
        {
            if ( argc>1 )
            {
                *period = atoi( argv[1] );
            }
            else
            {
                usage();
                exit( 1 );
            }
            argc -= 2; argv+=2;
        }
        else if ( !strcmp( argv[0], "-p" ) )
        {
            if ( argc>1 )
            {
                *ms = atoi( argv[1] );
            }
            else
            {
                usage();
                exit( 1 );
            }
            argc -= 2; argv+=2;
        }
        else
        {
            usage();
            exit( 1 );
        }
    }
}

void dostuff( commstuff_t *cs )
{
    int i,j;

    for( i=0; i<10; i++ )
    {
        j=i;
    }
}


void *serverfunc( void *x )
{
    RT_TASK *rttask;
    commstuff_t *cs = x;
    int val;

    rttask = rt_task_init( cs->id, 0, 0, 0 );
    printf( "thread(event,srt)    'server'    started\n" );
    while ( running )
    {
        val = waitfordata( cs );
        cs->alive++;
        if ( running && val & (1<<2) )
        {
            putdata( listener, cs->id );
            putdata( clienthrt, cs->id );
        }
        if ( running && val & (1<<3) )
        {
            putdata( listener, cs->id );
            putdata( clientsrt, cs->id );
        }
    } 
    rt_task_delete( rttask );
    printf( "thread(event,srt)    'server'    terminating\n" );
    return NULL;
}


void *clienthrtfunc( void *param )
{
    RT_TASK *rttask;
    commstuff_t *cs = param;

    rttask = rt_task_init( (int) cs->id, 0, 0, 0 );
    printf( "thread(periodic,hrt) 'clienthrt' started, period %lli\n",
            1000LL*1000LL*cs->period );

    rt_make_hard_real_time();
    rt_task_make_periodic_relative_ns( rttask, 0, 1000LL*1000LL*cs->period );
    while ( running )
    {
        dostuff( cs );
        putdata( server, cs->id );
        cs->alive++;
        rt_task_wait_period();
    }
    rt_task_delete( rttask );
    printf( "thread(periodic,hrt) 'clienthrt' terminating\n" );
    return NULL;
}

void *clientsrtfunc( void *param )
{
    RT_TASK *rttask;
    commstuff_t *cs = param;

    rttask = rt_task_init( (int) cs->id, 0, 0, 0 );
    printf( "thread(periodic,srt) 'clientsrt' started, period %lli\n",
            1000LL*1000LL*cs->period );

    while ( running )
    {
        dostuff( cs );
        putdata( server, cs->id );
        cs->alive++;
        usleep( cs->period * 1000 );
    }
    rt_task_delete( rttask );
    printf( "thread(periodic,srt) 'clientsrt' terminating\n" );
    return NULL;
}

void *listenerfunc( void *param )
{
    RT_TASK *rttask;
    commstuff_t *cs = param;
    int val;

    rttask = rt_task_init( cs->id, 0, 0, 0 );
    printf( "thread(event,srt)    'listener'  started\n" );
    while ( running )
    {
        val = waitfordata( cs );
        cs->alive++;
        if ( running && val & (1<<0) )
        {
            putdata( server, cs->id );
        }
    } 
    rt_task_delete( rttask );
    printf( "thread(event,srt)    'listener'  terminating\n" );
    return NULL;
}





More information about the Rtai mailing list