user2907139
user2907139

Reputation: 97

How to make read() non-blocking and reset read()

So i made this function which acts like a countdown.I want to read a command while the countdown decreases. My big problem is making read() the wait for a input while countdown is decreasing.As you can see I tried using select() but after the first printf("timeout.\n"); it stops trying to read. I made the show only once timeout or else it would go until countdown reached 0. I need to try read again.

int timer(int seconds) 
{
    time_t start, end;
    double elapsed;
    int opened=0; 
    char command[10];
    struct timeval tv;
    int fd_stdin,rv;
    fd_set rd;

    fd_stdin=fileno(stdin);

    FD_ZERO(&rd);
    FD_SET(fileno(stdin),&rd);

    tv.tv_sec=5;
    tv.tv_usec=0;

    time(&start);  /* start the timer */

    do
    {
        time(&end);

        elapsed = difftime(end, start);

        if(fmod(elapsed,5)==0)
        {
            printf("Time remaining: %f minutes.\n", (seconds-elapsed)/60);
            sleep(1);
            if(opened==0)
            {
                printf("Use opentest to open your test.\n");
                opened=1;
            }
            fflush(stdout);
        }
        int c;
        rv=select(fd_stdin+1,&rd,NULL,NULL,&tv);
        if(rv==-1)
        {
            perror("Error on select.\n");
            exit(1);
        }
        else if (rv==0 && c!=1)
        {
            printf("timeout.\n");
            rv=select(fd_stdin+1,&rd,NULL,NULL,&tv);
            c=1;
        }
        else 
        {
            c=0;
            read(fd_stdin,command,10);
        }
    }
    while(elapsed < seconds);
    return 0;
}

EDIT: to use the fmod() function , I compile like this: gcc client.c -lm -o client.exe. I don`t think this is the problem but I am not sure.

Upvotes: 1

Views: 393

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597941

select() modifies the fd_set upon exit to reflect which descriptors have been signaled. You are not resetting the fd_set after each timeout.

Also, on some platforms, select() modifies the timeval structure to reflect how much time is remaining, so you would have to reset the timeval each time you call select() on those platforms.

Also, your c variable is declared inside the loop and is uninitialized. Move it outside the loop instead.

Try something more like this:

int timer(int seconds) 
{
    time_t start, end;
    double elapsed;
    int opened = 0; 
    char command[10];
    struct timeval tv;
    int fd_stdin, rv;
    fd_set rd;
    int c = 0;

    fd_stdin = fileno(stdin);

    time(&start);  /* start the timer */

    do
    {
        time(&end);

        elapsed = difftime(end, start);

        if (fmod(elapsed, 5) == 0)
        {
            printf("Time remaining: %f minutes.\n", (seconds-elapsed)/60);
            sleep(1);
            if (opened == 0)
            {
                printf("Use opentest to open your test.\n");
                opened = 1;
            }
            fflush(stdout);
        }

        FD_ZERO(&rd);
        FD_SET(fd_stdin, &rd);

        tv.tv_sec = 5;
        tv.tv_usec = 0;

        rv = select(fd_stdin+1, &rd, NULL, NULL, &tv);
        if (rv == -1)
        {
            perror("Error on select.\n");
            exit(1);
        }
        else if (rv == 0)
        {
            if (c != 1)
            {
                printf("timeout.\n");
                c = 1;
            }
        }
        else 
        {
            c = 0;
            read(fd_stdin, command, 10);
        }
    }
    while (elapsed < seconds);
    return 0;
}

Upvotes: 1

Related Questions