Question

while studying for my finals I found a very interesting questing. This is what I desire to code.

Program read stdin into buffer (of fixed size). When buffer is full, program prints it to file. But if buffer isn't filled in fixed time (timeout), program prints to file [TIMEOUT] and the rest of buffer (currently read)

First example:

buffer_size = 5; timeout = 4;

$ while : ; do printf 1; sleep 1; done | ./a.out

should write [TIMEOUT]1111[TIMEOUT]1111[TIMEOUT]1111 etc. because while-loop writes only 4 chars (within 4 second limit).

Second example

buffer_size = 3; timeout = 5;

$ while : ; do printf 1; sleep 1; done | ./a.out

should write 111 111 111 etc. because while-loop writes 3 chars (within 3 seconds < 5 sec limit) so timeout never happens.

I'm trying to code it using poll but I don't know how to find out, whether all chars have been written or only one. I can't also get stuck on read(0, buffer, buffer_size) as I would miss timeout. Is it even possible? I guess it is as our teacher pointed it out as a good excersice.

Of course, busy wait is unacceptable, only classic POSIX syscalls allowed (poll, select, read, write, open...).

Could anybody hint me, please? I have no clue how to manage this behaviour and neighter stackoverflow nor google gave me answer (or maybe I just don't know what to search for)

Thanks in advance

Was it helpful?

Solution 2

thanks guys, I figured it out in other way (but still no busy-wait). I attach the code below for further students :)

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <libgen.h>
#include <err.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>

extern char ** environ;

/*
usage:

$ while : ; do printf 1; sleep 1; done | XTIMEOUT=4 XSIZE=5 ./a.out
[TIMEOUT]1111[TIMEOUT]1111[TIMEOUT]1111...

$ while : ; do printf 1; sleep 1; done | XTIMEOUT=5 XSIZE=3 ./a.out
111...
*/

uint64_t
now()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    double time_in_mill =  (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
    return (uint64_t) time_in_mill;
}

int
main(int argc, char ** argv) { 

    //  ----------------------------------
    //  boring stuff

    size_t timeout = 11 * 1000;
    size_t buffer_size = 10;

    char * tmp_env;
    if ((tmp_env = getenv("XTIMEOUT")) != NULL) {
        timeout = atoi(tmp_env) * 1000;
    }
    if ((tmp_env = getenv("XSIZE")) != NULL) {
        buffer_size = atoi(tmp_env);
    }

    //  ----------------------------------
    //  fun starts here

    //  buffers
    char * buffer = (char *) malloc(buffer_size * sizeof(char));
    char * buffer2 = (char *) malloc(buffer_size * sizeof(char));

    //  set stdin non-blocking
    int saved_flags = fcntl(0, F_GETFL);
    fcntl(0, saved_flags | O_NONBLOCK);


    //  poll structure
    struct pollfd ufds[1];
    ufds[0].fd = 0;
    ufds[0].events = POLLIN;

    int rv, n, k;
    size_t pos = 0;
    uint64_t start_time;

    int rem_time = timeout;

    for (;;) {
        start_time = now();
        //printf("pollig for %d\n", rem_time);
        rv = poll(ufds, 1, rem_time);

        if (rv == -1) {     //  err
            err(1, "poll");
        }
        else if (rv == 0) { //  timeout
            write(1, "[TIMEOUT]", 9);
            write(1, buffer, pos);
            pos = 0;
            rem_time = timeout;
        }
        else {      //  regular
            if (ufds[0].revents & POLLIN) {     //  real action
                if ((n = read(0, buffer2, buffer_size-pos)) == -1) {    //  read up to free space
                    err(1, "read");
                }

                for (k = 0; k < n; ++k) {   //  copy (maybe strcp)
                    buffer[k+pos] = buffer2[k];
                }

                pos += n;   //  pos has changed

                if (pos == buffer_size) {   //  buffer is full -> write it out and set new timeout
                    write(1, buffer, buffer_size); write(1, "", 1);
                    pos = 0;
                    rem_time = timeout;
                }
                else {      // still not enough, make timeout shorter (by the length of computation)
                    rem_time = rem_time - now() + start_time;
                }
            }
            else {      //  poll failed!
                err(1, "false alarm");
            }
        }
    }

    free(buffer);
    free(buffer2);

    return (0);
}

OTHER TIPS

Here are some hints:

  1. Use select() with a timeout
  2. Set the FD to O_NONBLOCK with fcntl
  3. Only read from the FD when FD_ISSET returns true
  4. Read until you get EWOULDBLOCK or EAGAIN (which indicate timeout). Repeat the loop if you see EINTR.

Here is a better answer: go to your library and get a copy of Stephens out. I believe it's this book: http://www.amazon.com/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0321637739 you want (all of his are great). However, this is still the canonical reference volume to teach you how to do this stuff and should be a core text for your course.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top