How to recall select after timeout in C? - c

I used select for synchronous I/O multiplexing.It will check for any data for 1 second.After 1 second if no data it will display a output (puts("Waited for 1 sec no data");) then it will check again for data.But this is working only at first time then it enters endless loops.
Is there any alternative solution for this.
//..............................
//.............................
//Creating listener socket and other sort of things
struct timeval tv;
tv.tv_sec=1;
tv.tv_usec=0;
while(1)
{
FD_ZERO(master);
FD_SET(listener,master);
fdmax = listener;
int retval=select(fdmax+1,master, NULL, NULL,&tv);
printf("retval is %d\n",retval);
if(retval == -1)
{
perror("Server-select() error");
}else if(retval)
{
puts("Data available");
//If there is no data do some work and checkagain.
}else
{
puts("Waited for 1 sec no data");
//If there is no data do some work and checkagain.
}
}

From man select:
On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1-2001 permits either behavior.) This causes problems both when Linux code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
So like master, you will have to set tv before each select call.
In my codes, I often have something like:
FD_ZERO(master);
FD_SET(listener,master);
fdmax = listener;
while (1)
{
struct timeval tv = {1, 0};
int retval=select(fdmax+1,master, NULL, NULL,&tv);
printf("retval is %d\n",retval);
if(retval == -1) {
perror("Server-select() error");
break; // <-- notice the break here
} else if(retval) {
puts("Data available");
} else {
puts("Waited for 1 sec no data");
}
}

In addition to Mathieu answer, it seems that before each call to select FD_ZERO must be called to empty readable file handle set and then calls the FD_SET.
I was struggling with select() returning always 0 after reaching the timeout regardless the fact that there are data to read (I read inputs from the keyboard, I checked with 'cat' command that data are sent at each Key press).
The code should be (Credit to previous answers):
while (1)
{
struct timeval tv = {1, 0};
FD_ZERO(master);
FD_SET(listener,master);
fdmax = listener;
int retval=select(fdmax+1,master, NULL, NULL,&tv);
printf("retval is %d\n",retval);
if(retval == -1) {
perror("Server-select() error");
break; // <-- notice the break here
} else if(retval) {
puts("Data available");
} else {
puts("Waited for 1 sec no data");
}
}

Related

How to port "select" to "poll" for third error data?

I have the following code that uses select:
fd_set fdsu;
FD_ZERO(&fdsu);
FD_SET(fd, &fdsu);
fd_set efds = fdsu;
fd_set dfds = fdsu;
while (1) {
select(cameraUSBP.fd + 1, NULL, &dfds, &efds, NULL);
if (FD_ISSET(cameraUSBP.fd, &efds)) {
errorData();
}
if (FD_ISSET(cameraUSBP.fd, &dfds)) {
writeData();
}
}
I want to port it to use poll:
struct pollfd pollfds[1];
pollfds[0].fd = fd;
pollfds[0].events = POLLIN;
while (1) {
poll(pollfds, 1, -1);
//how to insert writeData() and errorData()
}
I'm confused. How do I insert the writeData and errorData events?
First, your select() version has a number of significant errors.
From the linux manpage:
Note well: Upon return, each of the file descriptor sets is modified in place to indicate which file descriptors are currently "ready". Thus, if using select() within a loop, the sets must be reinitialized before each call.
You're not doing that. You also can't portably assign fd_sets like you're doing; it works on some implementations, it doesn't on others (Say, if it's implemented as an array). Nor are you checking to see if select() fails.
It should look like
while (1) {
fd_set efds, dfds;
FD_ZERO(&efds);
FD_SET(cameraUSBP.fd, &efds);
FD_ZERO(&dfds);
FD_SET(cameraUSBP.fd, &dfds);
if (select(cameraUSBP.fd + 1, NULL, &dfds, &efds, NULL) < 0) {
reportError(errno);
break; // or exit or whatever
}
if (FD_ISSET(cameraUSBP.fd, &efds)) {
errorData();
}
if (FD_ISSET(cameraUSBP.fd, &dfds)) {
writeData();
}
}
struct pollfd, on the other hand, has separate fields for events to monitor and events that happened, so it only has to be initialized once if the descriptors you're monitoring never change. You set events to the things you're interested in, using a bitwise or of flags, and check revents to see what happened by doing a bitwise and with the relevant flag.
struct pollfd pollfds[1];
pollfds[0].fd = cameraUSBP.fd;
pollfds[0].events = POLLOUT; // since you want to know when it's writable
while (1) {
if (poll(pollfds, 1, -1) < 0) {
reportError(errno);
break;
}
if (pollfds[0].revents & POLLERR) { // Doesn't need to be set in events
errorData();
}
if (pollfds[0].revents & POLLOUT) {
writeData();
}
}

C Program daemon uses 100% cpu usage

I'm initializing a daemon in C in a Debian:
/**
* Initializes the daemon so that mcu.serial would listen in the background
*/
void init_daemon()
{
pid_t process_id = 0;
pid_t sid = 0;
// Create child process
process_id = fork();
// Indication of fork() failure
if (process_id < 0) {
printf("Fork failed!\n");
logger("Fork failed", LOG_LEVEL_ERROR);
exit(1);
}
// PARENT PROCESS. Need to kill it.
if (process_id > 0) {
printf("process_id of child process %i\n", process_id);
exit(0);
}
//unmask the file mode
umask(0);
//set new session
sid = setsid();
if(sid < 0) {
printf("could not set new session");
logger("could not set new session", LOG_LEVEL_ERROR);
exit(1);
}
// Close stdin. stdout and stderr
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
The main daemon runs in the background and monitors a serial port to communicate with a microcontroller - it reads peripherals (such as button presses) and passes information to it. The main functional loop is
int main(int argc, char *argv[])
{
// We need the port to listen to commands writing
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
logger("ERROR, no port provided", LOG_LEVEL_ERROR);
exit(1);
}
int portno = atoi(argv[1]);
// Initialize serial port
init_serial();
// Initialize server for listening to socket
init_server(portno);
// Initialize daemon and run the process in the background
init_daemon();
// Timeout for reading socket
fd_set setSerial, setSocket;
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
char bufferWrite[BUFFER_WRITE_SIZE];
char bufferRead[BUFFER_READ_SIZE];
int n;
int sleep;
int newsockfd;
while (1)
{
// Reset parameters
bzero(bufferWrite, BUFFER_WRITE_SIZE);
bzero(bufferRead, BUFFER_WRITE_SIZE);
FD_ZERO(&setSerial);
FD_SET(fserial, &setSerial);
FD_ZERO(&setSocket);
FD_SET(sockfd, &setSocket);
// Start listening to socket for commands
listen(sockfd,5);
clilen = sizeof(cli_addr);
// Wait for command but timeout
n = select(sockfd + 1, &setSocket, NULL, NULL, &timeout);
if (n == -1) {
// Error. Handled below
}
// This is for READING button
else if (n == 0) {
// This timeout is okay
// This allows us to read the button press as well
// Now read the response, but timeout if nothing returned
n = select(fserial + 1, &setSerial, NULL, NULL, &timeout);
if (n == -1) {
// Error. Handled below
} else if (n == 0) {
// timeout
// This is an okay tiemout; i.e. nothing has happened
} else {
n = read(fserial, bufferRead, sizeof bufferRead);
if (n > 0) {
logger(bufferRead, LOG_LEVEL_INFO);
if (strcmp(stripNewLine(bufferRead), "ev b2") == 0) {
//logger("Shutting down now", LOG_LEVEL_INFO);
system("shutdown -h now");
}
} else {
logger("Could not read button press", LOG_LEVEL_WARN);
}
}
}
// This is for WRITING COMMANDS
else {
// Now read the command
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0 || n < 0) logger("Could not accept socket port", LOG_LEVEL_ERROR);
// Now read the command
n = read(newsockfd, bufferWrite, BUFFER_WRITE_SIZE);
if (n < 0) {
logger("Could not read command from socket port", LOG_LEVEL_ERROR);
} else {
//logger(bufferWrite, LOG_LEVEL_INFO);
}
// Write the command to the serial
write(fserial, bufferWrite, strlen(bufferWrite));
sleep = 200 * strlen(bufferWrite) - timeout.tv_usec; // Sleep 200uS/byte
if (sleep > 0) usleep(sleep);
// Now read the response, but timeout if nothing returned
n = select(fserial + 1, &setSerial, NULL, NULL, &timeout);
if (n == -1) {
// Error. Handled below
} else if (n == 0) {
// timeout
sprintf(bufferRead, "err\r\n");
logger("Did not receive response from MCU", LOG_LEVEL_WARN);
} else {
n = read(fserial, bufferRead, sizeof bufferRead);
}
// Error reading from the socket
if (n < 0) {
logger("Could not read response from serial port", LOG_LEVEL_ERROR);
} else {
//logger(bufferRead, LOG_LEVEL_INFO);
}
// Send MCU response to client
n = write(newsockfd, bufferRead, strlen(bufferRead));
if (n < 0) logger("Could not write confirmation to socket port", LOG_LEVEL_ERROR);
}
close(newsockfd);
}
close(sockfd);
return 0;
}
But the CPU usages is always at 100%. Why is that? What can I do?
EDIT
I commented out the entire while loop and made the main function as simple as:
int main(int argc, char *argv[])
{
init_daemon();
while(1) {
// All commented out
}
return 0;
}
And I'm still getting 100% cpu usage
You need to set timeout to the wanted value on every iteration, the struct gets modified on Linux so I think your loop is not pausing except for the first time, i.e. select() is only blocking the very first time.
Try to print tv_sec and tv_usec after select() and see, it's modified to reflect how much time was left before select() returned.
Move this part
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
inside the loop before the select() call and it should work as you expect it to, you can move many delcarations inside the loop too, that would make your code easier to maintan, you could for example move the loop content to a function in the future and that might help.
This is from the linux manual page select(2)
On Linux, select() modifies timeout to reflect the amount of time not slept; most other implementations do not do this. (POSIX.1-2001 permits either behavior.) This causes problems both when Linux code which reads timeout is ported to other operating systems, and when code is ported to Linux that reuses a struct timeval for multiple select()s in a loop without reinitializing it. Consider timeout to be undefined after select() returns.
I think the bold part in the qoute is the important one.

unix select is not sleeping

I am trying handle 4 different named unix pipes in a single listener process.
I tried to use the select to handle the file descriptor of the pipes.I opened all the named pipes in a non blocking mode
I am having a issue, select is not at all sleeping. Continuously running in a loop.
I dont know where is the problem in my code. I pasted my code below.
Always retaining the last file descriptor in select call eventhough it doesnt have a content in pipe.
Please suggest what is wrong in code?
Code
Pipe Open call(Invoked in Constructor)
diag_fd = open(DIAG_PIPE , O_RDONLY | O_NONBLOCK );
Main Loop
while(1)
{
FD_ZERO(&fds);
FD_SET(cp_fd, &fds);
FD_SET(diag_fd, &fds);
FD_SET(err_fd, &fds);
FD_SET(perf_fd, &fds);
if (select(cp_fd+1, &fds, NULL, NULL, &tv) < 0)
{
perror("select");
return ;
}
for (int fd = diag_fd; fd <= cp_fd; fd++)
{
if (FD_ISSET(fd, &fds))
{
if (fd == diag_fd)
{
ProcessDiagLogs();
}
else if (fd == err_fd)
{
ProcessErrLogs();
}
else if (fd == perf_fd)
{
ProcessPerfLogs();
}
else if (fd == cp_fd)
{
ProcessCPLogs();
}
}
}
Read call in One File Descriptor:
ProcessDiagLogs()
do
{
if ((num = read(diag_fd, s, BUF_LENGTH)) == -1)
perror("read");
else {
s[num] = '\0';
fputs(s, filed);
fflush(filed);
}
} while (num > 0);
select() allows you to monitor one or more file descriptors, waiting until one of them becomes "ready", i.e. data is available for.
The const struct timespec *timeout, tv, in your case specifies the timeout period, or how log he select waits for data until it returns ( this behaves like a sleep ). if the timeout is 0, the select return immediately, if it's NULL it can block indefinitely.
You don't show in your code how you initialized tv, but I'm going to guess it's zero, hence the behavior you are seeing.
Try initializing the timeout before you call select and see if that helps:
tv.tv_sec = 1;//or any other value you see fit
tv.tv_usec= 0;

File Descriptor for socket not working

Here is the code i am using. Whenever i write something to the Stdin, it works, but it is not working for socket. It's not able to enter the loop for Socket. I am new to socket programming.
void HandleConnection(int socket)
{
fd_set rfd;
struct timeval tv;
int retval;
printf("%d",socket);
MakeNonBlocking(socket);
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfd);
while(1)
{
FD_SET(STDIN, &rfd);
FD_SET(socket, &rfd);
/* Wait up to five seconds. */
tv.tv_sec = 50;
tv.tv_usec = 0;
retval = select(2, &rfd,NULL, NULL, &tv);
if(retval == 0)
{
printf("No data within fifty seconds.\n");
exit(1);
}
if(FD_ISSET(socket,&rfd))
{
printf("socket wala\n");
recieve_message(&socket);
send_message(&socket);
}
if(FD_ISSET(STDIN,&rfd))
{
printf("stdin wala\n");
recieve_message(&socket);
send_message(&socket);
}
}
}
FDZERO must go before FDSET inside the loop
select(2, ...) should be select(highest filedescriptor +1, ...).
when select returns you should check for negative value in case of errors
you should consider using pselect instead of select.
Clear tv before you reinitialize it.
It appears that you don't understand how the nfds argument to select() is used. The man page addresses this explicitly:
The first nfds
descriptors are checked in each set; i.e., the descriptors from 0 through nfds-1 in the descriptor sets are examined. (Example:
If you have set two file descriptors "4" and "17", nfds should not be "2", but rather "17 + 1" or "18".)
So here is how you should rewrite your code.
int maxfd = (socket > STDIN ? socket : STDIN) + 1; /* select() requires the number of FDs to scan, which is max(fds)+1 */
while(1){
FD_ZERO(&rfd); /* This needs to be done each time through the loop */
/* Watch stdin (fd 0) to see when it has input. */
FD_SET(STDIN, &rfd);
FD_SET(socket, &rfd);
/* Wait up to five seconds. */
tv.tv_sec = 50;
tv.tv_usec = 0;
retval = select(maxfd, &rfd,NULL, NULL, &tv);
if(retval == 0)
{
printf("No data within fifty seconds.\n");
exit(1);
}
if(retval == -1) /* Check for error */
{
perror("Error from select");
exit(2);
}
if(FD_ISSET(socket,&rfd))
{
printf("socket wala\n");
recieve_message(&socket);
send_message(&socket);
}
if(FD_ISSET(STDIN,&rfd))
{
printf("stdin wala\n");
recieve_message(&socket);
send_message(&socket);
}
}

socket programming with select

I have two nodes communicating with a socket. Each node has a read thread and a write thread to communicate with the other. Given below is the code for the read thread. The communication works fine between the two nodes with that code. But I am trying to add a select function in this thread and that is giving me problems (the code for select is in the comments. I just uncomment it to add the functionality). The problem is one node does not receive messages and only does the timeout. The other node gets the messages from the other node but never timesout. That problem is not there (both nodes send and receive messages) without the select (keeping the comments /* */).
Can anyone point out what the problem might be? Thanks.
void *Read_Thread(void *arg_passed)
{
int numbytes;
unsigned char *buf;
buf = (unsigned char *)malloc(MAXDATASIZE);
/*
fd_set master;
int fdmax;
FD_ZERO(&master);
*/
struct RWThread_args_template *my_args = (struct RWThread_args_template *)arg_passed;
/*
FD_SET(my_args->new_fd, &master);
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
int s_rv = 0;
fdmax = my_args->new_fd;
*/
while(1)
{
/*
s_rv = -1;
if((s_rv = select(fdmax+1, &master, NULL, NULL, &tv)) == -1)
{
perror("select");
exit(1);
}
if(s_rv == 0)
{
printf("Read: Timed out\n");
continue;
}
else
{
printf("Read: Received msg\n");
}
*/
if( (numbytes = recv(my_args->new_fd, buf, MAXDATASIZE-1, 0)) == -1 )
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("Read: received '%s'\n", buf);
}
pthread_exit(NULL);
}
You must set up master and tv before each call to select(), within the loop. They are both modified by the select() call.
In particular, if select() returned 0, then master will now be empty.

Resources