Skip to content
Advertisement

Can not achieve real time SCHED_FIFO thread within process

Good day everyone !

I am trying to get a 2nd thread (the serial thread) to run as near real time as possible.

Within my 2nd spawned serial thread I select() with timeout of 3 mS on a serial port.

I also get real time before select() … and then after to get select() delta time.

Problem is that sometimes I get no indication of select returning 0 (what I call a timeout due to the 3 mS elapsing) … but I do occasionally get a total time much greater than the 3 mS (4.447 for example).

I have to conclude that the serial thread is getting preempted?

Any ideas?

What Linux commands can I use to see if the thread is preempted?

Thanks!

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>



//-----------------------------------
// signal Handler stuff.
//-----------------------------------
static
struct  sigaction mySigActTerm;

volatile
int     myTerminate = 0;

void terminateHandler(int signum, siginfo_t *info, void *ptr)
{
  // set a flag here and get out.
  myTerminate = 1;
}



void getNowTime(char* str)
{
  time_t    rawtime;
  time(&rawtime);
  ctime_r(&rawtime, str);

  // clobber the unwanted newline.
  str[24] = '';
}



void myResLimit()
{
  struct
  rlimit    procLimit;

  char      strNowTime[26];

  getrlimit(RLIMIT_RTTIME, &procLimit);
  getNowTime(strNowTime);
  fprintf(stderr, "%s - RLIMIT_RTTIME: soft=%lld, hard=%lldn", strNowTime, (long long) procLimit.rlim_cur, (long long)procLimit.rlim_max);

  getrlimit(RLIMIT_RTPRIO, &procLimit);
  getNowTime(strNowTime);
  fprintf(stderr, "%s - RLIMIT_RTPRIO: soft=%lld, hard=%lldn", strNowTime, (long long) procLimit.rlim_cur, (long long) procLimit.rlim_max);

  getrlimit(RLIMIT_CPU, &procLimit);
  getNowTime(strNowTime);
  fprintf(stderr, "%s - RLIMIT_CPU: soft=%lld, hard=%lldn", strNowTime, (long long) procLimit.rlim_cur, (long long) procLimit.rlim_max);
}



void*   serialThread(void* arg)
{
    int     sfd;    // serial file descriptor.

    char    myChar;

    int     rtn;

    fd_set  myfds;

    struct
    timeval tm_out,
            start,
            end,
            delta;

    struct
    termios oldtio,
            newtio;

    sfd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);

    tcgetattr(sfd, &oldtio);

    newtio = oldtio;

    cfmakeraw(&newtio);

    newtio.c_cflag |= CREAD;
    newtio.c_cflag |= CLOCAL;
    newtio.c_cflag &= ~CSTOPB;
    newtio.c_cflag &= ~CRTSCTS;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS7;
    newtio.c_cflag |= PARENB;
    newtio.c_cflag &= ~PARODD;

    newtio.c_cc[VTIME] = 1;
    newtio.c_cc[VMIN] = 1;

    tcflush(sfd, TCIFLUSH);


    while (1) {
        FD_ZERO(&myfds);
        FD_SET(sfd, &myfds);

        tm_out.tv_sec = 0;
        tm_out.tv_usec = 3000;

        // get sys call start time.
        gettimeofday(&start, NULL);

        rtn = select(sfd+1 ,&myfds, NULL, NULL, &tm_out);

        // get sys call end time.
        gettimeofday(&end, NULL);

        timersub(&end, &start, &delta);

        if (rtn == 0) {
            fprintf(stderr, "tm_out = %02d.%06d    delta = %02d.%06dn", tm_out.tv_sec, tm_out.tv_usec, delta.tv_sec, delta.tv_usec);
        }
        else
          read(sfd, &myChar, 1);
    }
}



//-----------------------------------
// the one and only MAIN.
//-----------------------------------
int main()
{
  //-----------------------------------------------
  // locals.
  int               rtn;

  char              strNowTime[26];

  pthread_t         serialThdID;

  pthread_attr_t    serialAttr;

  struct
  sched_param       serialParam;


  //-----------------------------------------------
  // Log OS resource limits.
  myResLimit();

  //-----------------------------------------------
  // initialize the signals struct.
  // ... and setup signals.
  memset(&mySigActTerm, 0, sizeof(mySigActTerm));
  mySigActTerm.sa_sigaction = terminateHandler;
  mySigActTerm.sa_flags = SA_SIGINFO;

  sigaction(SIGTERM, &mySigActTerm, NULL);


  //-----------------------------------------------
  // set initial default pthread attr values.
  if ((rtn = pthread_attr_init(&serialAttr)) != 0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_attr_init()n%sn", strNowTime, strerror(rtn));
    exit(EXIT_FAILURE);
  }

  //-----------------------------------------------
  // set for best near real time policy.
  if ((rtn = pthread_attr_setschedpolicy(&serialAttr, SCHED_FIFO)) !=0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_attr_setschedpolicy()n%sn", strNowTime, strerror(rtn));
    exit(EXIT_FAILURE);
  }

  //-----------------------------------------------
  // set to explicit inherit or attr obj will be ignored.
  if ((rtn = pthread_attr_setinheritsched(&serialAttr, PTHREAD_EXPLICIT_SCHED)) !=0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_attr_setinheritsched()n%sn", strNowTime, strerror(rtn));
    exit(EXIT_FAILURE);
  }

  //-----------------------------------------------
  // set to un-limited thread priority.
  serialParam.sched_priority = 0;
  if ((rtn = pthread_attr_setschedparam(&serialAttr, &serialParam)) !=0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_attr_setschedparam()n%sn", strNowTime, strerror(rtn));
    exit(EXIT_FAILURE);
  }

  //-----------------------------------------------
  // start the new thread.
  if ((rtn = pthread_create(&serialThdID, &serialAttr, serialThread, NULL)) == 0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - starting serial thread.n", strNowTime);
  }
  else {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_create() returned %dn%sn", strNowTime, rtn, strerror(rtn));
    exit(EXIT_FAILURE);
  }

  //-----------------------------------------------
  // no need to keep this junk if pthread_create() succeeded.
  if ((rtn = pthread_attr_destroy(&serialAttr)) != 0) {
    getNowTime(strNowTime);
    fprintf(stderr, "%s - main() - pthread_attr_destroy()n%sn", strNowTime, strerror(rtn));
  }




  while (myTerminate == 0) {

  }
}

Advertisement

Answer

Well no one seems to know why this is happening to me but … … after nearly a year struggling … … I found a post that is exactly what is happening to me.

I post a link so no one else will suffer my fate.

C – select() seems to block for longer than timeout

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement