# kqueue and eof



## noobster (Apr 18, 2009)

I am using a kqueue to asynchronously read from a file, but I couldn't figure out how to detect when the EOF has been reached. Does anyone know how to do that? Thanks.


----------



## Mel_Flynn (Apr 19, 2009)

```
if ( event.flags & EV_EOF )
    break; // or whatever you wanna do
```


----------



## noobster (Apr 19, 2009)

Thanks for your reply. I have the code below, but it never detects the EOF. It simply reads all the bytes from the file and that's it. What am I missing?


```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/event.h>
#include <fcntl.h>

int main()
{
    struct kevent ke;
    off_t nread = 0;
    
    int kq = kqueue();
    int fd = open("filename", O_RDONLY | O_NONBLOCK);
    
    EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
    kevent(kq, &ke, 1, NULL, 0, NULL);
    
    while (1)
    {
        memset(&ke, 0, sizeof(struct kevent));
        if (kevent(kq, NULL, 0, &ke, 1, NULL) == -1)
        {
            perror("kevent");
            exit(1);
        }
        if (ke.flags & EV_EOF)
        {
            printf("end of file!\n");
            exit(1);
        }
        
        char buf[1024];
        int n = read(ke.ident, buf, 1024);
        if (n <= 0)
        {
            perror("read");
            exit(1);
        }
        
        nread += n;
        printf("nread: %lld\n", nread);
    }
    return 0;
}
```


----------



## Mel_Flynn (Apr 19, 2009)

Why do you pass NULL as the changelist? I don't think you're getting any events. See if kevent returns 0, which is not an error (you didn't pass a changelist) and is equal to the number of events it triggered.


----------



## noobster (Apr 19, 2009)

I am passing the changelist in the first kevent() call, and then in the second call I'm checking for events. I suppose I could combine this into one call, but it should work the way it is as well. I checked the return value of kevent() and it's never 0.

I appreciate your help.


----------



## Mel_Flynn (Apr 19, 2009)

Never mind. EVFILT_READ on vnodes doesn't set EV_EOF cause you can detect going to EOF by reading ev.data. It contains "bytes left in file".


```
while (1)
        {
                char buf[64];
                int n;
                unsigned int left;

                if (kevent(kq, NULL, 0, &ke, 1, NULL) == -1)
                        err(EXIT_FAILURE, "kevent");

                if( ke.flags & EV_ERROR )
                        errc(EXIT_FAILURE, ev.data, "kevent");

                if (ke.flags & EV_EOF)
                {
                        printf("premature end of file!\n");
                        break;
                }
                n = read(ke.ident, buf, sizeof(buf));
                if (n <= 0)
                {
                        err(EX_FAILURE, "read");
                }

                nread += n;
                printf("nread: %lld\n", nread);
                left = (unsigned)ke.data;
                if( left <= sizeof(buf) )
                        break; /* At EOF */
        }
```

P.S.: probably better to use an off_t for left, and a constant instead of sizeof(buf), so your code compiles with WARNS=3.


----------



## noobster (Apr 19, 2009)

Thanks, that is exactly what I was looking for.


----------

