How to loop select() to poll for data ad infinitum - c

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
int main ()
{
char name[20];
fd_set input_set;
struct timeval timeout;
int ready_for_reading = 0;
int read_bytes = 0;
/* Empty the FD Set */
FD_ZERO(&input_set );
/* Listen to the input descriptor */
FD_SET(0, &input_set);
/* Waiting for some seconds */
timeout.tv_sec = 10; // 10 seconds
timeout.tv_usec = 0; // 0 milliseconds
/* Invitation for the user to write something */
printf("Enter Username: (in 15 seconds)\n");
printf("Time start now!!!\n");
/* Listening for input stream for any activity */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Here, first parameter is value of the socket descriptor + 1 (STDIN descriptor is 0, so
* 0 +1 = 1)
* in the set, second is our FD set for reading,
* third is the FD set in which any write activity needs to updated, which is not required
* in this case. Fourth is timeout
*/
if (ready_for_reading == -1) {
/* Some error has occured in input */
printf("Unable to read your input\n");
return -1;
} else {
if (ready_for_reading) {
read_bytes = read(0, name, 19);
printf("Read, %d bytes from input : %s \n", read_bytes, name);
} else {
printf(" 10 Seconds are over - no data input \n");
}
}
return 0;
}
How to do the same, but not just once, but in infinite loop which breaks after encountering 'quit' string (for example). Every way I tried - failed.
So if no data has been inputed after 10 seconds program just prints "10 secs are over - no data input" and then starts waiting again. Same after input - just begins again and behave the same every time in infinite loop.
Am little desperate already, please - help.
Thanks.

I don't really see the problem here. Basically just put everything you want in the loop, and let it run. Did you try this?
int main ()
{
/* Declarations and stuff */
/* ... */
/* The loop */
int break_condition = 0;
while (!break_condition)
{
/* Selection */
FD_ZERO(&input_set ); /* Empty the FD Set */
FD_SET(0, &input_set); /* Listen to the input descriptor */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Selection handling */
if (ready_for_reading)
{
/* Do something clever with the input */
}
else
{
/* Handle the error */
}
/* Test the breaking condition */
break_condition = some_calculation();
}
return 0;
}
Note that you have to have keep resetting the selection inside the loop so that it will respond again in the next iteration.

The select() function can be told to block indefinitely by setting timeout to NULL. See select(2) man page:
timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval stucture are zero, then select() returns immediately. (This is useful for polling.) If timeout is NULL (no timeout), select() can block indefinitely.
So what you want is:
...
ready_for_reading = select(1, &input_set, NULL, NULL, NULL);
...

Related

How to develop timeout on reception?

I have developed a C program that receive can traffics from vcan0 interface.
I would like to add timeout on reception, I mean when a timeout expired (10 seconds for example) with no data received during this time, I print "no data received during 10 seconds" and I make a reboot of my pc(the reboot is made if a specific condition is satisfied).
I have tested with select function I get the timeout but when the specific condition is not satisfied I can't receive can traffics anymore.
should I add something for reactivate reception when I have timeout and specific condition is not satisfied? if yes how?
My program is like this:
...
while(1)
{
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000000; // 10 second
rv = select(fd_max + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
{
printf("no data received within 10 second"); /* a timeout occured */
if (specific condition is true)
{
reboot(RB_AUTOBOOT);
}
}
else
int s;
/* loop on all sockets */
for(i=s;i<=fd_max;i++)
{
read( i, buff, len );
/* some other instruction*/
}
}
...

ncurses in a multithreaded application

I have a multi threaded application which uses ncurses on a single thread to report information to the user. My code basically looks like this:
const unsigned int refresh_cycle = 180;
unsigned int refresh_count = refresh_cycle;
while(killswitch != 1) {
if (refresh_count >= refresh_cycle) {
// critical section which obtains some data worked on by a thread. only does this once every refresh cycle times
// mtx lock, fetch, mtx unlock
refresh_count = 0;
}
refresh_count++;
// get input
// draw some stuff
// refresh
}
What I notice is that the ncurses window gets refreshed lots and lots of times. Way more than is really needed for a user who could probably get by with only 15-30 refreshes in a second.
But now I am worrying this might 'steal' unnecesary processing power from one of the threads that is doing work. Is this a reasonable assertion?
Should I build in a sort of frame limiter with usleep() or would that be going overboard?
As per the comments, if in between the refreshes you need to deal with user input, then the easiest way is probably to call select() on STDIN_FILENO with a suitably small timeout. When select() returns, either because there is user input or because it timed out, do a refresh at that point.
Here's an example that'll let you see how to set this up, and shows when when and how many times select() is returning so you can visualize what's going on. Try letting it sit and run for a while, and then try holding down a key, and watch how the select() has returned [n] times message behaves in each case. The comments in the code explain what's happening:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <sys/select.h>
#include <ncurses.h>
/* struct to store curses info for cleanup */
struct curinfo {
WINDOW * main_window;
int old_cursor;
};
/* curses helper functions */
void start_curses(struct curinfo * info);
void stop_curses(struct curinfo * info);
/* main function */
int main(int argc, char * argv[])
{
/* Set default timeout */
int secs = 0;
int usecs = 500000;
/* Set timeout based on command line args, if provided */
if ( argc > 1 ) {
if ( !strcmp(argv[1], "veryshort") ) {
secs = 0;
usecs = 200000;
}
else if ( !strcmp(argv[1], "short") ) {
secs = 1;
usecs = 0;
}
else if ( !strcmp(argv[1], "medium") ) {
secs = 2;
usecs = 0;
}
else if ( !strcmp(argv[1], "long") ) {
secs = 5;
usecs = 0;
}
}
struct curinfo cinfo;
start_curses(&cinfo);
int input = '0'; /* Set to something printable */
int num_sel = 0; /* Number of times select() has returned */
while ( input != 'q' && input != 'Q' ) {
/* Output messages */
mvprintw(3, 3, "select() has returned %d times", num_sel);
mvprintw(4, 3, "Last character input was %c", input);
mvprintw(5, 3, "Press 'q' to quit");
refresh();
/* select() modifies the fd_sets passed to it,
* so zero and set them prior to each call. */
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
/* Same deal for the struct timeval, select() may
* modify it, it may not, so recreate to be portable. */
struct timeval tv;
tv.tv_sec = secs;
tv.tv_usec = usecs;
/* Store the return so we can check it */
int status = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
/* Check for error */
if ( status == -1 ) {
/* select() returned with an error. */
if ( errno != EINTR ) {
/* If interrupted by a signal, no problem,
* keep going. Otherwise, let's just quit. */
stop_curses(&cinfo);
perror("error calling select()");
return EXIT_FAILURE;
}
}
else if ( FD_ISSET(STDIN_FILENO, &fds) ) {
/* Only call getch() if input is ready.
* getch() will not block when we do it this way. */
if ( (input = getch()) == ERR ) {
stop_curses(&cinfo);
fprintf(stderr, "ERR returned from getch()\n");
return EXIT_FAILURE;
}
}
/* Increment number of times select() has returned */
++num_sel;
}
stop_curses(&cinfo);
return 0;
}
/* Starts curses and populates the passed struct */
void start_curses(struct curinfo * info)
{
if ( (info->main_window = initscr()) == NULL ) {
fprintf(stderr, "Error calling initscr()\n");
exit(EXIT_FAILURE);
}
keypad(stdscr, TRUE);
timeout(0);
raw();
nonl();
noecho();
info->old_cursor = curs_set(0);
refresh();
}
/* Stops curses and cleans up */
void stop_curses(struct curinfo * info)
{
delwin(info->main_window);
curs_set(info->old_cursor);
endwin();
refresh();
}

How can I implement timeout for read() when reading from a serial port (C/C++)

I am reading bytes from a serial port in C++ using a file descriptor and the posix/unix read() function. In this example, I am reading 1 byte from the serial port (baud rate settings and similiar are omitted for clarity):
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
char buf[1];
int bytesRead = read(fd, buf, 1);
close(fd);
return 0;
}
If the device connected to /dev/ttyS0 does not send any information, the program will hang. How can I set a timeout?
I have tried setting a time out like this:
struct termios options;
tcgetattr(fd, &options);
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 10;
tcsetattr(fd, TCSANOW, &options);
I thought it was supposed to give 1 second timeout, but it makes no difference. I think I have misunderstood VMIN and VTIME. What is VMIN and VTIME used for?
Then I searched the web and found somebody talking about the select() function. Is that the solution and if so, how would one apply that to the program above to make 1 second timeout?
Any help is appreciated. Thanks in advance :-)
Yes, use select(2). Pass in a file descriptor set containing just your fd in the read set and empty write/exception sets, and pass in an appropriate timeout. For example:
int fd = open(...);
// Initialize file descriptor sets
fd_set read_fds, write_fds, except_fds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
FD_SET(fd, &read_fds);
// Set timeout to 1.0 seconds
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
// Wait for input to become ready or until the time out; the first parameter is
// 1 more than the largest file descriptor in any of the sets
if (select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout) == 1)
{
// fd is ready for reading
}
else
{
// timeout or error
}
What is VMIN and VTIME used for?
If MIN > 0 and TIME = 0, MIN sets the number of characters to receive
before the read is satisfied. As TIME is zero, the timer is not used.
If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will
be satisfied if a single character is read, or TIME is exceeded (t =
TIME *0.1 s). If TIME is exceeded, no character will be returned.
If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The
read will be satisfied if MIN characters are received, or the time
between two characters exceeds TIME. The timer is restarted every time
a character is received and only becomes active after the first
character has been received.
If MIN = 0 and TIME = 0, read will be satisfied immediately. The
number of characters currently available, or the number of characters
requested will be returned. According to Antonino (see contributions),
you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get
the same result.
Source : http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
You can attempt capture signal to stop read operation. use alarm(1) before read, and if read function did not returned, alarm will send SIGALRM signal, then you can create signal processing function to capture this signal, like this:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf env_alarm;
static void sig_alarm(int signo)
{
longjmp(env_alarm, 1);
}
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
char buf[1];
if (signal(SIGALRM, sig_alarm) == SIG_ERR)
{
exit(0);
}
if (setjmp(env_alarm) != 0)
{
close(fd);
printf("Timeout Or Error\n");
exit(0);
}
alarm(1);
int bytesRead = read(fd, buf, 1);
alarm(0);
close(fd);
return 0;
}
But use select or poll or epoll will be better if your program is big.
select() is the way I would solve this problem.
There are several pages on the internet that will give info on how to use select(), such as http://www.unixguide.net/unix/programming/2.1.1.shtml
There are several possible approaches. If the program will eventually be timing more than one i/o operation, select() is the clear choice.
However, if the only input is from this i/o, then selecting non-blocking i/o and timing is a straightforward method. I have expanded it from single character i/o to multi-character to make it a more generally complete example:
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/time.h>
int main(void)
{
int fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); // sometimes "O_NONBLOCK"
char buf[10];
int done = 0, inbuf = 0;
struct timeval start, now;
gettimeofday (&start, NULL);
while (!done)
{
int bytesRead = read(fd, &buf[inbuf], sizeof buf - inbuf);
if (bytesRead < 0)
{
error_processing_here();
continue;
}
if (bytesRead == 0) // no data read to read
{
gettimeofday (&now, NULL);
if ((now.tv.sec - start.tv_sec) * 1000000 +
now.tv.usec - start.tv_usec > timeout_value_in_microsecs)
{
done = 2; // timeout
continue;
}
sleep(1); // not timed out yet, sleep a second
continue;
}
inbuf += bytesRead;
if (we have read all we want)
done = 1;
}
if (done == 2)
timeout_condition_handling();
close(fd);
return 0;
}

Timeout Function

I want to make a code in which Name of User will be asked to input, but in a time limit of 15 seconds. If user cross the limit & failed to input a name(or any string), then code will be terminated & "Time Out" Massage will be display otherwise Name should be saved & "Thanks" massage will be display. I had try like this but it's wrong & not working. Please give me a solution for this.. Thanks.
#include <stdio.h>
#include <time.h>
int timeout ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
return 1;
}
int main ()
{
char name[20];
printf("Enter Username: (in 15 seconds)\n");
printf("Time start now!!!\n");
scanf("%s",name);
if( timeout(5) == 1 ){
printf("Time Out\n");
return 0;
}
printf("Thnaks\n");
return 0;
}
Probably this dummy program might help you:
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#define WAIT 3
int main ()
{
char name[20] = {0}; // in case of single character input
fd_set input_set;
struct timeval timeout;
int ready_for_reading = 0;
int read_bytes = 0;
/* Empty the FD Set */
FD_ZERO(&input_set );
/* Listen to the input descriptor */
FD_SET(STDIN_FILENO, &input_set);
/* Waiting for some seconds */
timeout.tv_sec = WAIT; // WAIT seconds
timeout.tv_usec = 0; // 0 milliseconds
/* Invitation for the user to write something */
printf("Enter Username: (in %d seconds)\n", WAIT);
printf("Time start now!!!\n");
/* Listening for input stream for any activity */
ready_for_reading = select(1, &input_set, NULL, NULL, &timeout);
/* Here, first parameter is number of FDs in the set,
* second is our FD set for reading,
* third is the FD set in which any write activity needs to updated,
* which is not required in this case.
* Fourth is timeout
*/
if (ready_for_reading == -1) {
/* Some error has occured in input */
printf("Unable to read your input\n");
return -1;
}
if (ready_for_reading) {
read_bytes = read(0, name, 19);
if(name[read_bytes-1]=='\n'){
--read_bytes;
name[read_bytes]='\0';
}
if(read_bytes==0){
printf("You just hit enter\n");
} else {
printf("Read, %d bytes from input : %s \n", read_bytes, name);
}
} else {
printf(" %d Seconds are over - no data input \n", WAIT);
}
return 0;
}
Update:
This is now tested code.
Also, I have taken hints from man for select. This manual already contains a code snippet which is being used to read from the terminal and timeout in 5 seconds in case of no activity.
Just a brief explanation in case the code is not well written enough:
We add the input stream (fd = 1) to the FD set.
We initiate select call to listen to this FD set created for
any activity.
In case any activity occurs within the timeout period, that is
read through the read call.
In case there was no activity, timeout occurs.
Hope this helps.
scanf() is not the best function to get an input in a limited time frame.
Instead I would build a specific input function around select() (for managing timeout) and read() (for getting input) system calls.
One thing you have to think about, is that you have a single thread of execution in your program. As such, the timeout function will only be called when the scanf function will be terminated. This is not what you want.
One way to do this task, is to use the select function. It waits for a potentially limited amount of time (your timeout) for availability of input on some file descriptors (stdin for you).

using select() with pipe

I am reading/writing to a pipe created by pipe(pipe_fds). So basically with following code, I am reading from that pipe:
fp = fdopen(pipe_fds[0], "r");
And when ever I get something, I print it out by:
while (fgets(buf, 200, fp)) {
printf("%s", buf);
}
What I want is, when for certain amount of time nothing appears on the pipe to read from, I want to know about it and do:
printf("dummy");
Can this be achieved by select() ? Any pointers on how to do that will be great.
Let's say you wanted to wait 5 seconds and then if nothing was written to the pipe, you print out "dummy."
fd_set set;
struct timeval timeout;
/* Initialize the file descriptor set. */
FD_ZERO(&set);
FD_SET(pipe_fds[0], &set);
/* Initialize the timeout data structure. */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
/* In the interest of brevity, I'm using the constant FD_SETSIZE, but a more
efficient implementation would use the highest fd + 1 instead. In your case
since you only have a single fd, you can replace FD_SETSIZE with
pipe_fds[0] + 1 thereby limiting the number of fds the system has to
iterate over. */
int ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
// a return value of 0 means that the time expired
// without any acitivity on the file descriptor
if (ret == 0)
{
printf("dummy");
}
else if (ret < 0)
{
// error occurred
}
else
{
// there was activity on the file descripor
}
IIRC, select has a timeout that you then check with FD_ISSET to tell if it was I/O or not that returned.

Resources