So, I want this program to wait for 5 seconds for an input. If there is no input it returns. If there is input, it renews the timer and starts the count again.
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
char buf[1024];
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
do {
tv.tv_sec = 5;
tv.tv_usec = 0;
printf("Please enter a number: \n");
retval = select(1, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval) {
scanf("%[^\n]%*c", buf);
}
else
printf("No data within five seconds.\n");
} while (tv.tv_sec != 0 && tv.tv_usec != 0);
exit(EXIT_SUCCESS);
}
It works fine with regular input, but when I press enter twice, it goes into infinite loop. Why? What is happening?
You need to put FD_SET(0, &rfds); within the loop...
... if it select times out, the rfds structure will be reset
as if FD_ZERO() had been called....
Additionally, I might suggest you change the scanf() to a more simple fgets() if moving the FD_SET() doesn't totally solve your problem (in any event, FD_SET needs to be moved).
Related
This is a C console/terminal program.
I would like to let the user wait for the program to do some background work until either the background work finishes or the user clicks on the <Enter> key. I do that with a statement:
getchar();
and I have another thread doing the background work.
When the thread is about to finish, I would like the thread to send programmatically the <Enter> key so that the control continues after the getchar() statement.
How is this possible?
The getchar() function will block until a character arrives. Though not standard C, you can use a select call in a loop to wait until a given file handle is readable, then read it. That would go something like the following demo code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
int main(void) {
fd_set rfds;
struct timeval tv;
int retval;
puts("Waiting for a character ...");
for (;;) {
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
if (select(1, &rfds, NULL, NULL, &tv) > 0) break;
puts("Delay over, doing some stuff, then waiting ...");
}
int ch = getchar();
printf("Character available, it was '%c'.\n", ch);
return 0;
}
In your particular case, I wouldn't have an infinite loop for(;;). Rather, I'd do something like:
int stillRunning = 1;
while (stillRunning) {
...
}
and then have the background task set stillRunning to zero to cause the loop to exit regardless of a keypress.
I am trying to modify an example I found.
The example:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
// don't care about writefds and exceptfds:
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed!\n");
else
printf("Timed out.\n");
return 0;
}
Which print time out if 2.5 seconds has passed without sending a message, otherwise printing a key was pressed.
I tried to put it inside a while loop:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
if (select(STDIN+1, &temp, NULL, NULL, &tv) == -1)
printf("err");
if (FD_ISSET(STDIN, &temp))
{
printf("A key was pressed!\n");
}
else
printf("Timed out.\n");
}
return 0;
}
In this code when I enter a key it keeps printing a key was pressed forever.
I read online the I have to set tv variable every time but still no help.
Do i need a temp fd_set
? what am I wrong ?
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
// Note: STDIN_FILENO, or fileno(stdin)
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
int ret,ch;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
ret = select(STDIN+1, &temp, NULL, NULL, &tv) ;
if (ret == -1) {
if (errno == EAGAIN) continue; // These are NOT Errors, but natural occuring events
if (errno == EINTR) continue; // The are reported to avoid your select() to block for too long
perror("erreur");
break;
}
else if (ret ==0) {
printf("Timed out.\n");
continue;
}
// Ok: select has returned > 0; there must be something to read
if (FD_ISSET(STDIN, &temp)) {
ch = getc(stdin); // Lookout: stdin is line-buffered
printf("A key was pressed: %d!\n", ch);
}
}
return 0;
}
I am trying to write a code to read input from the console continuously and update a variable in the application. But if we use scanf function, whenever the function hits it expects an input from the user through console and continues with further instruction only if it receives an input from the console, otherwise it waits unconditionally.
My code is something like
int x, y;
while(1)
{
scanf("%d", &x);
y = x;
----
----
//Remaining code for execution
}
My expectation is the application should not be waiting for input from the console. If the user enters some input in the console, it should read and use that input, otherwise even if no input is entered, the application should execute remaining instructions or it should use the old values. Is there any other way to write such code without using scanf? Thanks!
You can select()/epoll() function for taking input, if timeout occurs it will proceed further.
Since stdin is also an FD, you can register than FD for select to work on that given FD.
Refer : https://stackoverflow.com/a/21198059/6686352
You can use select() with a zero (not NULL) timeout to check if data is available, and only then call scanf.
Example (without correct error handling):
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
int main()
{
int x;
fd_set fds;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
while (1) {
FD_ZERO(&fds);
FD_SET(0, &fds); // Watch stdin (fd 0)
if (select(1, &fds, NULL, NULL, &tv)) {
scanf("%d", &x);
printf("Got %d from stdin", x);
}
printf("Working..\n");
sleep(1);
}
}
You can set stdin to non-blocking with fcntl. This makes scanf return early with EAGAIN if it would otherwise have blocked.
Example (without correct error handling):
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int x;
fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
while (1) {
int ret = scanf("%d", &x);
if (ret > 0)
printf("Got %d from stdin", x);
printf("Working..\n");
sleep(1);
}
}
Running this snippet of code to experiment with piping and signals. I'm trying to learn how to properly utilize the select() function between pipes.
This process will fork. If there is something to be read from stdIn it is then written to the write end of the pipe. It is supposed to execute either a basic command entered via terminal, or it runs hard-coded commands in the code. (It's running hard code right now as "ls.")
When I run this snippet, it should quit and stop running completely when I press the letter "q" followed by ENTER, or it should quit after it runs its assigned process.
Instead, even after I hit "q" or run the process it won't stop the program completely. It is still waiting for input. It will stop running once I have hit ENTER, but it never even executes my process.
For example, if I compile and run this as "./test ls" or even just run "./test" (because ls is hard-coded in so that SHOULD just run I think), it will not run the command ls. And the program will continue to run until I've hit ENTER again.
I'm certain my rudimentary understanding of select() has to do with this issue. I'm pretty sure my select() statement needs to break at some point but I don't know what or how to check for this.
I was told that there is a method WIFEXITED() that might be able to help me but I'm just not sure how it applies in this context.
I also would like to know how to check if your pipes are empty!
I DO know that I want this to be able to both take input from the terminal and record it and also run built in functions.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <stdio.h>
int main() {
int in[2]; // parent writes; child reads
pipe(in);
if (fork() == 0) {
// instantiate the values that will be execed
char *a[2];
//a[0] = "./test3";
a[0] = "ls";
a[1] = NULL;
// redirects what is being read from stdin to the pipe
//this redirection is for a separate test that is not included
close(in[1]);
close(0);
dup(in[0]);
close(in[0]); // close read
execvp(a[0], a);
}
else {
close(in[0]); // only want parent to write
// select() params
int nfds = 3;
int check = -1;
int done = 0;
fd_set readfds;
fd_set writefds;
FD_ZERO(&readfds); // set select params
FD_SET(0, &readfds);
FD_SET(in[1], &writefds);
while ((check = select(nfds, &readfds, &writefds, NULL, NULL)) > 0) {
int size = 0;
char buf[1000];
// write to pipe for child
if (FD_ISSET(0, &readfds) && FD_ISSET(in[1], &writefds)) {
while ((size = read(0, buf, sizeof(buf))) != 0) {
write(in[1], buf, size);
}
}
// reset
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(in[1], &writefds);
}
printf("%d --------------- %d\n", (FD_ISSET(in[1], &writefds)),
FD_ISSET(0, &readfds));
}
return 0;
}
Here is the potential set of test code that can be run with the above snipped if a[0] = ./test is uncommented and a[0] = ls is commented.
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>
int main () {
int fd;
char buf[11];
int ret, sret;
int flag = 0;
fd = 0;
fd_set readfds;
struct timeval timeout;
while(1) {
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
sret = select(fd + 1, &readfds, NULL, NULL, NULL);
memset((void *) buf, 0, 11);
ret = read(fd, (void *) buf, 10);
flag = strcmp(buf, "q\n") == 0;
if (flag) {
return 0;
}
printf("ret = %d\n", ret);
if(ret != -1) {
printf(" buf = %s\n", buf);
}
}
return 0;
}
i use this code for test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
fd_set rfds;
struct timeval tv;
int retval, len;
char buff[255] = {0};
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
do{
/* Wait up to five seconds. */
tv.tv_sec = 2;
tv.tv_usec = 0;
retval = select(1, &rfds, NULL, NULL, &tv);
if (retval == -1){
perror("select()");
exit(EXIT_FAILURE);
}
else if (retval){
/* FD_ISSET(0, &rfds) is true so input is available now. */
/* Read data from stdin using fgets. */
fgets(buff, sizeof(buff), stdin);
/* Remove trailing newline character from the input buffer if needed. */
len = strlen(buff) - 1;
if (buff[len] == '\n')
buff[len] = '\0';
printf("'%s' was read from stdin.\n", buff);
}
else
printf("No data within five seconds.\n");
}while(1);
exit(EXIT_SUCCESS);
}
i need that if the program read from stdin use printf, else if not use a printf with other string. The problem arises in the input
'd' enter
none enter
'd' enter
the program respond with the printf text of the none enter