All of lore.kernel.org
 help / color / mirror / Atom feed
From: Madars Vitolins <m@silodev.com>
To: Jason Baron <jbaron@akamai.com>,
	"Michael Kerrisk (man-pages)" <mtk.manpages@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	mingo@kernel.org, peterz@infradead.org, viro@ftp.linux.org.uk,
	normalperson@yhbt.net, corbet@lwn.net, luto@amacapital.net,
	torvalds@linux-foundation.org, hagen@jauu.net,
	linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	linux-api@vger.kernel.org
Subject: Re: [PATCH] epoll: add exclusive wakeups flag
Date: Tue, 15 Mar 2016 01:09:21 +0200	[thread overview]
Message-ID: <de62d81aa9c8865a2af30c10158462f0@silodev.com> (raw)
In-Reply-To: <56E73C9B.9060206@akamai.com>

Hi Jason and Michael,

Hmm... I tried to play with those pipe samples bellow, but even with 
sleep I got that all process wakeups (maybe I miss something too), also 
tried with EPOLLIN.

On same bases I created sample with Posix Queues with EPOLLIN | 
EPOLLEXCLUSIVE and the goods news are that it works correctly.

file q.c:
==================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>
#include <mqueue.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                         } while (0)

#define usageErr(msg, progName) \
                         do { fprintf(stderr, "Usage: "); \
                              fprintf(stderr, msg, progName); \
                              exit(EXIT_FAILURE); } while (0)

#ifndef EPOLLEXCLUSIVE
#define EPOLLEXCLUSIVE (1 << 28)
#endif

#define MAX_SIZE 10

int
main (int argc, char *argv[])
{
   int epfd, nready;
   struct epoll_event ev, rev;
   mqd_t fd;
   struct mq_attr attr;
   char buffer[MAX_SIZE + 1];
   int cnum;

   /* initialize the queue attributes */
   attr.mq_flags = 0;
   attr.mq_maxmsg = 5;
   attr.mq_msgsize = MAX_SIZE;
   attr.mq_curmsgs = 0;

   /* cleanup for multiple runs... */
   mq_unlink ("/TESTQ");

   /* create the message queue */
   fd =
     mq_open ("/TESTQ", O_CREAT | O_RDWR | O_NONBLOCK, S_IWUSR | S_IRUSR,
	     &attr);
   if (fd == -1)
     errExit ("open");

   for (cnum = 0; cnum < 3; cnum++)
     {
       switch (fork ())
	{
	case -1:
	  errExit ("fork");

	case 0:		/* Child */
	  epfd = epoll_create (2);
	  if (epfd == -1)
	    errExit ("epoll_create");

	  ev.events = EPOLLIN | EPOLLEXCLUSIVE;
	  if (epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
	    errExit ("epoll_ctl");

	  printf ("About to wait...\n");
	  nready = epoll_wait (epfd, &rev, 1, -1);
	  if (nready == -1)
	    errExit ("epoll-wait");

	  printf ("Child %d: epoll_wait() returned %d\n", cnum, nready);
	  exit (EXIT_SUCCESS);

	default:
	  break;
	}
     }
   sleep (1);
   /* send a msq to Q */
   memset (buffer, 0, MAX_SIZE);
   if (0 > mq_send (fd, buffer, MAX_SIZE, 0))
     errExit ("mq_send");
   printf ("msg sent ok...\n");

   wait (NULL);
   wait (NULL);
   wait (NULL);

   exit (EXIT_SUCCESS);
}
==================

$ gcc q.c -lrt
$ ./a.out
About to wait...
About to wait...
About to wait...
msg sent ok...
Child 2: epoll_wait() returned 1
^C
$



Best regards,
Madars


Jason Baron @ 2016-03-15 00:35 rakstīja:
> Hi Michael,
> 
> On 03/14/2016 05:03 PM, Michael Kerrisk (man-pages) wrote:
>> Hi Jason,
>> 
>> On 03/15/2016 09:01 AM, Michael Kerrisk (man-pages) wrote:
>>> Hi Jason,
>>> 
>>> On 03/15/2016 08:32 AM, Jason Baron wrote:
>>>> 
>>>> 
>>>> On 03/14/2016 01:47 PM, Michael Kerrisk (man-pages) wrote:
>>>>> [Restoring CC, which I see I accidentally dropped, one iteration 
>>>>> back.]
>> 
>> [...]
>> 
>>>>> Returning to the second sentence in this description:
>>>>> 
>>>>>               When a wakeup event occurs and multiple epoll file 
>>>>> descrip‐
>>>>>               tors are attached to the same target file using 
>>>>> EPOLLEXCLU‐
>>>>>               SIVE, one or  more  of  the  epoll  file  descriptors 
>>>>>  will
>>>>>               receive  an  event with epoll_wait(2).
>>>>> 
>>>>> There is a point that is unclear to me: what does "target file" 
>>>>> refer to?
>>>>> Is it an open file description (aka open file table entry) or an 
>>>>> inode?
>>>>> I suspect the former, but it was not clear in your original text.
>>>>> 
>>>> 
>>>> So from epoll's perspective, the wakeups are associated with a 'wait
>>>> queue'. So if the open() and subsequent EPOLL_CTL_ADD (which is done 
>>>> via
>>>> file->poll()) results in adding to the same 'wait queue' then we 
>>>> will
>>>> get 'exclusive' wakeup behavior.
>>>> 
>>>> So in general, I think the answer here is that its associated with 
>>>> the
>>>> inode (I coudn't say with 100% certainty without really looking at 
>>>> all
>>>> file->poll() implementations). Certainly, with the 'FIFO' example 
>>>> below,
>>>> the two scenarios will have the same behavior with respect to
>>>> EPOLLEXCLUSIVE.
>> 
>> So, I was actually a little surprised by this, and went away and 
>> tested
>> this point. It appears to me that that the two scenarios described 
>> below
>> do NOT have the same behavior with respect to EPOLLEXCLUSIVE. See 
>> below.
>> 
>>> So, in both scenarios, *one or more* processes will get a wakeup?
>>> (I'll try to add something to the text to clarify the detail we're
>>> discussing.)
>>> 
>>>> Also, the 'non-exclusive' mode would be subject to the same question 
>>>> of
>>>> which wait queue is the epfd is associated with...
>>> 
>>> I'm not sure of the point you are trying to make here?
>>> 
>>> Cheers,
>>> 
>>> Michael
>>> 
>>> 
>>>>> To make this point even clearer, here are two scenarios I'm 
>>>>> thinking of.
>>>>> In each case, we're talking of monitoring the read end of a FIFO.
>>>>> 
>>>>> ===
>>>>> 
>>>>> Scenario 1:
>>>>> 
>>>>> We have three processes each of which
>>>>> 1. Creates an epoll instance
>>>>> 2. Opens the read end of the FIFO
>>>>> 3. Adds the read end of the FIFO to the epoll instance, specifying
>>>>>    EPOLLEXCLUSIVE
>>>>> 
>>>>> When input becomes available on the FIFO, how many processes
>>>>> get a wakeup?
>> 
>> When I test this scenario, all three processes get a wakeup.
>> 
>>>>> ===
>>>>> 
>>>>> Scenario 3
>>>>> 
>>>>> A parent process opens the read end of a FIFO and then calls
>>>>> fork() three times to create three children. Each child then:
>>>>> 
>>>>> 1. Creates an epoll instance
>>>>> 2. Adds the read end of the FIFO to the epoll instance, specifying
>>>>> EPOLLEXCLUSIVE
>>>>> 
>>>>> When input becomes available on the FIFO, how many processes
>>>>> get a wakeup?
>> 
>> When I test this scenario, one process gets a wakeup.
>> 
>> In other words, "target file" appears to mean open file description
>> (aka open file table entry), not inode.
>> 
>> This is actually what I suspected might be the case, but now I am
>> puzzled. Given what I've discovered and what you suggest are the
>> semantics, is the implementation correct? (I suspect that it is,
>> but it is at odds with your statement above. My test programs are
>> inline below.
>> 
>> Cheers,
>> 
>> Michael
>> 
> 
> Thanks for the test cases. So in your first test case, you are exiting
> immediately after the epoll_wait() returns. So this is actually causing
> the next wakeup. And then the 2nd thread returns from epoll_wait() and
> this causes the 3rd wakeup.
> 
> So the wakeups are actually not happening from the write directly, but
> instead from the readers doing a close(). If you do some sort of sleep
> after the epoll_wait() you can confirm the behavior. So I believe this
> is working as expected.
> 
> Thanks,
> 
> -Jason
> 
> 
>> ============
>> 
>> /* t_EPOLLEXCLUSIVE_multipen.c
>> 
>>    Licensed under GNU GPLv2 or later.
>> */
>> #include <sys/epoll.h>
>> #include <sys/stat.h>
>> #include <fcntl.h>
>> #include <sys/types.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <unistd.h>
>> #include <string.h>
>> 
>> #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
>>                         } while (0)
>> 
>> #define usageErr(msg, progName) \
>>                         do { fprintf(stderr, "Usage: "); \
>>                              fprintf(stderr, msg, progName); \
>>                              exit(EXIT_FAILURE); } while (0)
>> 
>> #ifndef EPOLLEXCLUSIVE
>> #define EPOLLEXCLUSIVE (1 << 28)
>> #endif
>> 
>> int
>> main(int argc, char *argv[])
>> {
>>     int fd, epfd, nready;
>>     struct epoll_event ev, rev;
>> 
>>     if (argc != 2 || strcmp(argv[1], "--help") == 0)
>>         usageErr("%s <FIFO>n", argv[0]);
>> 
>>     epfd = epoll_create(2);
>>     if (epfd == -1)
>>         errExit("epoll_create");
>> 
>>     fd = open(argv[1], O_RDONLY);
>>     if (fd == -1)
>>         errExit("open");
>>     printf("Opened %s\n", argv[1]);
>> 
>>     ev.events = EPOLLIN | EPOLLEXCLUSIVE;
>>     if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
>>         errExit("epoll_ctl");
>> 
>>     nready = epoll_wait(epfd, &rev, 1, -1);
>>     if (nready == -1)
>>         errExit("epoll-wait");
>>     printf("epoll_wait() returned %d\n", nready);
>> 
>>     exit(EXIT_SUCCESS);
>> }
>> 
>> ===============
>> 
>> /* t_EPOLLEXCLUSIVE_fork.c
>> 
>>    Licensed under GNU GPLv2 or later.
>> */
>> 
>> #include <sys/epoll.h>
>> #include <sys/stat.h>
>> #include <fcntl.h>
>> #include <sys/types.h>
>> #include <sys/wait.h>
>> #include <stdio.h>
>> #include <stdlib.h>
>> #include <unistd.h>
>> #include <string.h>
>> 
>> #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
>>                         } while (0)
>> 
>> #define usageErr(msg, progName) \
>>                         do { fprintf(stderr, "Usage: "); \
>>                              fprintf(stderr, msg, progName); \
>>                              exit(EXIT_FAILURE); } while (0)
>> 
>> #ifndef EPOLLEXCLUSIVE
>> #define EPOLLEXCLUSIVE (1 << 28)
>> #endif
>> 
>> int
>> main(int argc, char *argv[])
>> {
>>     int fd, epfd, nready;
>>     struct epoll_event ev, rev;
>>     int cnum;
>> 
>>     if (argc != 2 || strcmp(argv[1], "--help") == 0)
>>         usageErr("%s <FIFO>n", argv[0]);
>> 
>>     fd = open(argv[1], O_RDONLY);
>>     if (fd == -1)
>>         errExit("open");
>>     printf("Opened %s\n", argv[1]);
>> 
>>     for (cnum = 0; cnum < 3; cnum++) {
>>         switch (fork()) {
>>         case -1:
>>             errExit("fork");
>> 
>>         case 0: /* Child */
>>             epfd = epoll_create(2);
>>             if (epfd == -1)
>>                 errExit("epoll_create");
>> 
>>             ev.events = EPOLLIN | EPOLLEXCLUSIVE;
>>             if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
>>                 errExit("epoll_ctl");
>> 
>>             nready = epoll_wait(epfd, &rev, 1, -1);
>>             if (nready == -1)
>>                 errExit("epoll-wait");
>>             printf("Child %d: epoll_wait() returned %d\n", cnum, 
>> nready);
>>             exit(EXIT_SUCCESS);
>> 
>>         default:
>>             break;
>>         }
>>     }
>> 
>>     wait(NULL);
>>     wait(NULL);
>>     wait(NULL);
>> 
>>     exit(EXIT_SUCCESS);
>> }
>> 

  reply	other threads:[~2016-03-14 23:22 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-08  3:23 [PATCH] epoll: add exclusive wakeups flag Jason Baron
2015-12-08  3:23 ` [PATCH] epoll: add EPOLLEXCLUSIVE flag Jason Baron
2015-12-08  3:23   ` Jason Baron
2016-01-28  7:16 ` [PATCH] epoll: add exclusive wakeups flag Michael Kerrisk (man-pages)
2016-01-28  7:16   ` Michael Kerrisk (man-pages)
2016-01-28 17:57   ` Jason Baron
2016-01-29  8:14     ` Michael Kerrisk (man-pages)
2016-02-01 19:42       ` Jason Baron
2016-02-01 19:42         ` Jason Baron
2016-03-10 18:53       ` Jason Baron
2016-03-10 19:47         ` Michael Kerrisk (man-pages)
2016-03-10 19:47           ` Michael Kerrisk (man-pages)
2016-03-10 19:58         ` Michael Kerrisk (man-pages)
2016-03-10 19:58           ` Michael Kerrisk (man-pages)
2016-03-10 20:40           ` Jason Baron
2016-03-10 20:40             ` Jason Baron
2016-03-11 20:30             ` Michael Kerrisk (man-pages)
2016-03-11 20:30               ` Michael Kerrisk (man-pages)
     [not found]               ` <56E32FC5.4030902@akamai.com>
     [not found]                 ` <56E353CF.6050503@gmail.com>
     [not found]                   ` <56E6D0ED.20609@akamai.com>
2016-03-14 17:47                     ` Michael Kerrisk (man-pages)
2016-03-14 19:32                       ` Jason Baron
2016-03-14 19:32                         ` Jason Baron
2016-03-14 20:01                         ` Michael Kerrisk (man-pages)
2016-03-14 20:01                           ` Michael Kerrisk (man-pages)
2016-03-14 21:03                           ` Michael Kerrisk (man-pages)
2016-03-14 21:03                             ` Michael Kerrisk (man-pages)
2016-03-14 22:35                             ` Jason Baron
2016-03-14 23:09                               ` Madars Vitolins [this message]
2016-03-14 23:26                               ` Michael Kerrisk (man-pages)
2016-03-14 23:26                                 ` Michael Kerrisk (man-pages)
2016-03-15  2:36                                 ` Jason Baron
2016-03-15  2:36                                   ` Jason Baron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=de62d81aa9c8865a2af30c10158462f0@silodev.com \
    --to=m@silodev.com \
    --cc=akpm@linux-foundation.org \
    --cc=corbet@lwn.net \
    --cc=hagen@jauu.net \
    --cc=jbaron@akamai.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=mingo@kernel.org \
    --cc=mtk.manpages@gmail.com \
    --cc=normalperson@yhbt.net \
    --cc=peterz@infradead.org \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@ftp.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.