select() problem - Linux

This is a discussion on select() problem - Linux ; Hi all, i am writing small daemon.....and when i was seeing the end ......that was just the beginning of my problems. General idea was to monitor list of files that was given on start. For this example i am using ...

+ Reply to Thread
Results 1 to 7 of 7

Thread: select() problem

  1. select() problem

    Hi all,

    i am writing small daemon.....and when i was seeing the end ......that
    was just the beginning
    of my problems.

    General idea was to monitor list of files that was given on start.

    For this example i am using test1.txt and test2.txt because I've
    succeeded to replicate my problem
    ,at least i think so....))))

    so the files are....

    test1.txt
    -----8<-----8<-----8<-----8<-----8<-----8<-----8<
    Testing from test1
    -----8<-----8<-----8<-----8<-----8<-----8<-----8<



    test2.txt
    -----8<-----8<-----8<-----8<-----8<-----8<-----8<
    Testing from test1
    -----8<-----8<-----8<-----8<-----8<-----8<-----8<

    and daemon.c


    Now the problem is following:

    when i compile (gcc daemon.c => a.out) and run binary in this version
    all works fine....and
    if I do
    #echo "some new line" >> test1.txt

    i would see on my screen that select figured it out and i am having new
    data for processing and it
    would print it out.

    but when i uncomment last fprintf my while and select goes
    ballistic.....it prints numbers forever...not
    blocking......

    So why is that this line "fprintf(stderr,"%d\n",i++);" causes this behavior.

    tnx for help.



    --------------daemon---code---------------------------------

    #include
    #include
    #include
    #include
    #include

    int main(void) {

    FILE *fp1,*fp2;
    fd_set fdst;
    char buffer[100];
    int i;


    if((fp1 = fopen("test1.txt","r")) == NULL){
    return 0;
    }

    if((fp2 = fopen("test2.txt","r")) == NULL){
    return 0;
    }



    /* Daemon-specific initialization goes here */

    /* The Big Loop */
    while (1) {
    /* Do some task here ... */

    FD_ZERO(&fdst);
    FD_SET(fileno(fp1),&fdst);
    FD_SET(fileno(fp2),&fdst);

    select(fileno(fp2)+1,&fdst,NULL,NULL,NULL);


    if(FD_ISSET(fileno(fp1),&fdst)){

    while(fgets(buffer,100,fp1) != NULL){
    puts(buffer);

    }
    }


    if(FD_ISSET(fileno(fp2),&fdst)){

    while(fgets(buffer,100,fp2) != NULL){
    puts(buffer);
    }

    }

    //fprintf(stderr,"%d\n",i++);

    }

    exit(EXIT_SUCCESS);
    }

  2. Re: select() problem

    That fprintf() gets executed once per loop, whether or not the files
    have been modified. What do you want it to do instead? If you want to
    count the number of times a file has been modified, you'll need another
    control structure.

    Cheers,

    Phil Hobbs

  3. Re: select() problem

    Phil Hobbs wrote:
    > That fprintf() gets executed once per loop, whether or not the files
    > have been modified.

    That's the problem

    What do you want it to do instead?
    I want to block for reading if there is no new stuff in file appended on
    the end.....like tail.

    Eg.

    Watch the log.....if there are new stuff in the log....unblock process
    data...and then block some more.....and loop.

  4. Re: select() problem

    __zip__ wrote:
    > Phil Hobbs wrote:
    >
    >> That fprintf() gets executed once per loop, whether or not the files
    >> have been modified.

    >
    > That's the problem
    >
    > What do you want it to do instead?
    > I want to block for reading if there is no new stuff in file appended on
    > the end.....like tail.
    >
    > Eg.
    >
    > Watch the log.....if there are new stuff in the log....unblock process
    > data...and then block some more.....and loop.


    Sure, but what do you want the fprintf() to do? Right now, if the files
    have not updated, your code effectively looks like this:


    while(1) {
    fprintf(...);
    }

    Of course that will produce reams of numbers--the loop is spinning like
    mad, regardless of whether the fprintf() is there or not. What did you
    expect it to do?

    If you want the fprintf() to print only when the files are updated, put
    it inside the control structures. If you want it to loop slowly and
    output the iteration count as a check, put in a nanosleep().

    Cheers,

    Phil Hobbs

  5. Re: select() problem

    Phil Hobbs wrote:
    > __zip__ wrote:
    >> Phil Hobbs wrote:
    >>
    >>> That fprintf() gets executed once per loop, whether or not the files
    >>> have been modified.

    >>
    >> That's the problem
    >>
    >> What do you want it to do instead?
    >> I want to block for reading if there is no new stuff in file appended
    >> on the end.....like tail.
    >>
    >> Eg.
    >>
    >> Watch the log.....if there are new stuff in the log....unblock process
    >> data...and then block some more.....and loop.

    >
    > Sure, but what do you want the fprintf() to do? Right now, if the files
    > have not updated, your code effectively looks like this:
    >
    >
    > while(1) {
    > fprintf(...);
    > }
    >
    > Of course that will produce reams of numbers--the loop is spinning like
    > mad, regardless of whether the fprintf() is there or not. What did you
    > expect it to do?
    >
    > If you want the fprintf() to print only when the files are updated, put
    > it inside the control structures. If you want it to loop slowly and
    > output the iteration count as a check, put in a nanosleep().
    >
    > Cheers,
    >
    > Phil Hobbs

    Using fprintf was just a method of showing that select isn't blocking
    rather it's passing flow of exection down the path.
    It's strange that select() doesn't block.

    If I have a file test.txt and invoke select with file descriptor set
    for reading on the file in descriptor set as argument to select i would
    expect that select() would block, and fprintf wouldn't run.
    Then i could run in some other terminal echo "data 12345" >> test.txt
    and select would unblock and i can check if descriptor is set and read
    data from file until end and then block again.So fprintf would increment
    only if there is data in file.Looking at this prosibility fprintf would
    actually show number of times select unblocked.

    Is there any other prefered method for acquiring info on newly arrived
    data in file.

    PS: I am writing daemon (GPL of course....) and monitoring some log
    files i core action......good advice would be helpful.

    tnx
    Nikola.

  6. Re: select() problem

    On Mon, 24 Jul 2006 17:43:23 +0200, __zip__ wrote:

    > but when i uncomment last fprintf my while and select goes
    > ballistic.....it prints numbers forever...not
    > blocking......


    > /* The Big Loop */
    > while (1) {
    > /* Do some task here ... */
    >
    > FD_ZERO(&fdst);
    > FD_SET(fileno(fp1),&fdst);
    > FD_SET(fileno(fp2),&fdst);
    >
    > select(fileno(fp2)+1,&fdst,NULL,NULL,NULL);


    This will unblock when the file is ready to be read. An end-of-file
    condition won't keep it blocked as that is considered a valid value to
    read. This behaviour is documented. From the select() man page:

    readfds will be watched to see if characters become available for
    read- ing (more precisely, to see if a read will not block - in
    particular, a file descriptor is also ready on end-of-file) ...


    > if(FD_ISSET(fileno(fp1),&fdst)){
    >
    > while(fgets(buffer,100,fp1) != NULL){
    > puts(buffer);
    >
    > }
    > }


    If the file is at EOF, FD_ISSET() will be true but the fgets() will
    return NULL so nothing will be printed.


    > if(FD_ISSET(fileno(fp2),&fdst)){
    >
    > while(fgets(buffer,100,fp2) != NULL){
    > puts(buffer);
    > }
    >
    > }
    >
    > //fprintf(stderr,"%d\n",i++);


    Commenting or uncommenting this has no effect on what's happening, only
    on what you see. The loop is spinning regardless.


    > }
    >
    > exit(EXIT_SUCCESS);
    > }


    You either need to just wait on a timer and then loop in fgets() !=
    NULL, or you need to use the dnotify/inotify functionality to get a
    notification when the file changes.


    --
    -| Bob Hauck
    -| A proud member of the unhinged moonbat horde.
    -| http://www.haucks.org/

  7. Re: select() problem

    Bob Hauck wrote:
    >On Mon, 24 Jul 2006 17:43:23 +0200, __zip__ wrote:
    >
    >> but when i uncomment last fprintf my while and select goes
    >> ballistic.....it prints numbers forever...not
    >> blocking......

    >
    >> /* The Big Loop */
    >> while (1) {
    >> /* Do some task here ... */
    >>
    >> FD_ZERO(&fdst);
    >> FD_SET(fileno(fp1),&fdst);
    >> FD_SET(fileno(fp2),&fdst);
    >>
    >> select(fileno(fp2)+1,&fdst,NULL,NULL,NULL);

    >
    >This will unblock when the file is ready to be read. An end-of-file
    >condition won't keep it blocked as that is considered a valid value to
    >read. This behaviour is documented. From the select() man page:


    It gets even worse than that, too. Select(3) looks at data
    buffered at the point were the low level functions, i.e. read(2)
    and write(2), operate. The Standard IO Library functions, such
    as fgets(3) operate on data buffered at the user level, at least
    one step past that. Which is to say that using select(3) to
    indicate when read(2) will block on a the input buffer is not an
    indication of when fgets(3) will find "new" data in the high
    level buffer.

    Additionally, the read(2) function works on individual bytes,
    while the fgets(3) function works on complete lines.

    ....

    >You either need to just wait on a timer and then loop in fgets() !=
    >NULL, or you need to use the dnotify/inotify functionality to get a
    >notification when the file changes.


    It appears something similar to "tail -f fname" is what the OP
    wants. A loop like this:

    for (; {
    fgets(buf, BUFFERSIZE, fp);
    if (ferror(fp)) {
    fprintf(stderr,"Error reading file: %s\n", argv[1]);
    exit(EXIT_FAILURE);
    }
    if (feof(fp)) {
    fsetpos(fp, &pos);
    clearerr(fp);
    sleep(1); /* give up the cpu to other processes */
    continue;
    }
    fgetpos(fp, &pos);
    printf("%s", buf);
    fflush(stdout);
    }

    --
    Floyd L. Davidson
    Ukpeagvik (Barrow, Alaska) floyd@apaflo.com

+ Reply to Thread