missing events in 'poll'

Hi everyone!

I am missing some events when executing 'poll' system call. Here is an example code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <poll.h>
#include <thread>
#include <chrono>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/eventfd.h>
#include <sys/time.h>
#include <errno.h>

static struct pollfd fds[1];

static void run()
{
    ssize_t readSize;
    int data;
    while (true)
    {
        int pollFd = poll(fds, 1, -1);

        if (pollFd > 0)
        {
            if (fds[0].revents & POLLIN)
            {
                do
                {
                    readSize = read(fds[0].fd, &data, sizeof (int*));
                    std::cout << "value read = " << data << std::endl;
                }
                while (readSize == -1 && errno == EAGAIN);
                
            }
        }
    }

}

int main(void)
{
    fds[0].events = POLLIN;
    fds[0].fd = eventfd(0, EFD_NONBLOCK);

    std::thread threadRun(run);
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); //to make sure 'poll' is called before the 'write' is performed
    int data;
    int ret;
    for (size_t i = 0; i < 2; ++i)
    {
        data = i;
//        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        do
        {
            ret = write(fds[0].fd, &data, sizeof (int*));
        }
        while (ret < 0 && errno == EAGAIN);
    }

    threadRun.join();
    close(fds[0].fd);
    return 0;

}


With this code, I want to send two events (0 and 1) to the 'poll' system call.

The output of this program is :
 
value read = 1


However, if you remove the comment on line 52 (sleep_for), the output is :

1
2
value read = 0
value read = 1


Somehow, with the original code I am missing the event '0'. Why??

Thanks in advance!
Perhaps it's a mis-understanding of what eventfd is all about.

https://linux.die.net/man/2/eventfd

read(2)
Each successful read(2) returns an 8-byte integer. A read(2) will fail with the error EINVAL if the size of the supplied buffer is less than 8 bytes.

The value returned by read(2) is in host byte order—that is, the native byte order for integers on the host machine.

The semantics of read(2) depend on whether the eventfd counter currently has a nonzero value and whether the EFD_SEMAPHORE flag was specified when creating the eventfd file descriptor:

* If EFD_SEMAPHORE was not specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing that value, and the counter's value is reset to zero.

* If EFD_SEMAPHORE was specified and the eventfd counter has a nonzero value, then a read(2) returns 8 bytes containing the value 1, and the counter's value is decremented by 1.

* If the eventfd counter is zero at the time of the call to read(2), then the call either blocks until the counter becomes nonzero (at which time, the read(2) proceeds as described above) or
fails with the error EAGAIN if the file descriptor has been made nonblocking.

write(2)
A write(2) call adds the 8-byte integer value supplied in its buffer to the counter. The maximum value that may be stored in the counter is the largest unsigned 64-bit value minus 1 (i.e.,
0xfffffffffffffffe). If the addition would cause the counter's value to exceed the maximum, then the write(2) either blocks until a read(2) is performed on the file descriptor, or fails with
the error EAGAIN if the file descriptor has been made nonblocking.

A write(2) will fail with the error EINVAL if the size of the supplied buffer is less than 8 bytes, or if an attempt is made to write the value 0xffffffffffffffff.


See this modification to your code.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <poll.h>
#include <thread>
#include <chrono>
#include <iostream>
#include <iomanip>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/eventfd.h>
#include <sys/time.h>
#include <errno.h>

static struct pollfd fds[1];

static void run()
{
    ssize_t readSize;
    int64_t data;
    while (true)
    {
        int pollFd = poll(fds, 1, -1);

        if (pollFd > 0)
        {
            if (fds[0].revents & POLLIN)
            {
                readSize = read(fds[0].fd, &data, sizeof (data));
                std::cout << "value read = " << data << std::endl;
            }
        }
    }
}

int main(void)
{
    fds[0].events = POLLIN;
    fds[0].fd = eventfd(0, EFD_NONBLOCK);

    std::thread threadRun(run);
    int64_t data;
    int ret;
    for (size_t i = 0; i < 10; ++i)
    {
        data = i;
        if ( i == 5 )
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        do
        {
            ret = write(fds[0].fd, &data, sizeof (data));
        }
        while (ret < 0 && errno == EAGAIN);
    }

    threadRun.join();
    close(fds[0].fd);
    return 0;

}

$ g++ -std=c++11 foo.cpp -pthread
$ ./a.out 
value read = 10
value read = 35

All the write()'s are additive to the internal counter that eventfd() creates.


If you want to see 0,1,2,3... printed by the thread, then you should create a pipe.
https://linux.die.net/man/2/pipe

Hi Salem!

Yes, definitely 'pipe' solved my problem, because I can't afford to lose notifications.

Thanks a lot!
Registered users can post here. Sign in or register to post.