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
Here are some hints:
- Use
select()
with a timeout
- Set the FD to
O_NONBLOCK
with fcntl
- Only read from the FD when
FD_ISSET
returns true
- 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.
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);
}