Re: [PATCH 1/2] os/connection: Call ClientReady() based on a level trigger rather than an edge trigger

2016-09-18 Thread Jeremy Huddleston Sequoia

> On Sep 18, 2016, at 09:58, Keith Packard  wrote:
> 
> Matthieu Herrb  writes:
> 
>> this doesn't fix an issue I'm seeing on OpenBSD with xterm not beeing
>> able to start (it makes the X server spin at 100% CPU in
>> WaitForSomething()), while Jeremy's patches do fix the issue for me.
> 
> I think Jeremy's patch will cause the server to spin while any client is
> not writable, which isn't good.

I don't believe that is the case because ClientReady does:

ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);

If I read the flow right, the level trigger causes WaitForSomething to spin up 
only when a client is ready to receive data.  ClientReady then mutes the 
trigger.  FlushClient then possibly re-enables it if we EAGAIN.  If/when the 
client is ready again (level trigger), ClientReady will fire again.

If the client is not ready to receive data, ClientReady won't fire.

My patch does indeed cause us to needlessly FlushAllOutput() if something else 
(eg: a new connection, new request) causes WaitForSomething() to spin up, but 
that's no different than someone currently just setting NewOutputPending=YES 
even though there is no pending output.

>> I've not been able to really understand the issue yet, but that's a
>> data point. (And I'm glad to see that it doesn't seem to be an OpenBSD
>> specific issue :)
> 
> I'd bet anyone using poll(2) instead of epoll(2) will see the same
> problems. It should be possible to reproduce this on Linux by using the
> poll path instead of epoll.




smime.p7s
Description: S/MIME cryptographic signature
___
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Re: [PATCH 1/2] os/connection: Call ClientReady() based on a level trigger rather than an edge trigger

2016-09-18 Thread Keith Packard
Matthieu Herrb  writes:

> this doesn't fix an issue I'm seeing on OpenBSD with xterm not beeing
> able to start (it makes the X server spin at 100% CPU in
> WaitForSomething()), while Jeremy's patches do fix the issue for me.

I think Jeremy's patch will cause the server to spin while any client is
not writable, which isn't good.

> I've not been able to really understand the issue yet, but that's a
> data point. (And I'm glad to see that it doesn't seem to be an OpenBSD
> specific issue :)

I'd bet anyone using poll(2) instead of epoll(2) will see the same
problems. It should be possible to reproduce this on Linux by using the
poll path instead of epoll.

-- 
-keith


signature.asc
Description: PGP signature
___
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Re: [PATCH 1/2] os/connection: Call ClientReady() based on a level trigger rather than an edge trigger

2016-09-18 Thread Matthieu Herrb
On Sun, Sep 18, 2016 at 08:42:00AM -0700, Keith Packard wrote:
> Jeremy Huddleston Sequoia  writes:
> 
> > On encountering an EAGAIN, FlushClient() re-adds the client to the
> > pending list and returns, but FlushClient() doesn't get called again.
> > We would expect it to be called via FlushAllOutput() via
> > WaitForSomething(), but that only happens when NewOutputPending is
> > set.  FlushAllOutput() also early-exits if NewOutputPending is not
> > set.
> >
> > The only place that is setting NewOutputPending is ClientReady().  The
> > problem there is that ClientReady() is called based on an edge trigger
> > and not a level trigger.
> 
> Hrm. I think this is a problem with our emulation of edge triggers as we
> don't tell the ospoll layer when we've detected that the client is not
> writable.
> 
> This should fix that; it makes the edge re-trigger whenever we start
> listening again:
> 
> diff --git a/os/ospoll.c b/os/ospoll.c
> index b00d422..8c99501 100644
> --- a/os/ospoll.c
> +++ b/os/ospoll.c
> @@ -352,10 +352,14 @@ ospoll_listen(struct ospoll *ospoll, int fd, int 
> xevents)
>  epoll_mod(ospoll, osfd);
>  #endif
>  #if POLL
> -if (xevents & X_NOTIFY_READ)
> +if (xevents & X_NOTIFY_READ) {
>  ospoll->fds[pos].events |= POLLIN;
> -if (xevents & X_NOTIFY_WRITE)
> +ospoll->fds[pos].revents &= ~POLLIN;
> +}
> +if (xevents & X_NOTIFY_WRITE) {
>  ospoll->fds[pos].events |= POLLOUT;
> +ospoll->fds[pos].revents &= ~POLLOUT;
> +}
>  #endif
>  }
>  }
> 
> I did find a bug with the NewOutputPending flag. We don't actually flush
> the client's buffer if there are still requests queued. This is a change
> From the previous behavior.
> 
> diff --git a/os/io.c b/os/io.c
> index ff0ec3d..c6db028 100644
> --- a/os/io.c
> +++ b/os/io.c
> @@ -615,6 +615,8 @@ FlushAllOutput(void)
>  if (!client_is_ready(client)) {
>  oc = (OsCommPtr) client->osPrivate;
>  (void) FlushClient(client, oc, (char *) NULL, 0);
> +} else {
> +NewOutputPending = TRUE;
>  }
>  }
>  }
> 
> -- 
> -keith


Hi

this doesn't fix an issue I'm seeing on OpenBSD with xterm not beeing
able to start (it makes the X server spin at 100% CPU in
WaitForSomething()), while Jeremy's patches do fix the issue for me.

Some other applications like xlogo, emacs 24 , or the XFCE4 base
desktop environment don't trigger it, but some other big applications
like inkscape trigger the same issue.

I've not been able to really understand the issue yet, but that's a
data point. (And I'm glad to see that it doesn't seem to be an OpenBSD
specific issue :)
-- 
Matthieu Herrb


pgpmGGI83FWWV.pgp
Description: PGP signature
___
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Re: [PATCH 1/2] os/connection: Call ClientReady() based on a level trigger rather than an edge trigger

2016-09-18 Thread Keith Packard
Jeremy Huddleston Sequoia  writes:

> On encountering an EAGAIN, FlushClient() re-adds the client to the
> pending list and returns, but FlushClient() doesn't get called again.
> We would expect it to be called via FlushAllOutput() via
> WaitForSomething(), but that only happens when NewOutputPending is
> set.  FlushAllOutput() also early-exits if NewOutputPending is not
> set.
>
> The only place that is setting NewOutputPending is ClientReady().  The
> problem there is that ClientReady() is called based on an edge trigger
> and not a level trigger.

Hrm. I think this is a problem with our emulation of edge triggers as we
don't tell the ospoll layer when we've detected that the client is not
writable.

This should fix that; it makes the edge re-trigger whenever we start
listening again:

diff --git a/os/ospoll.c b/os/ospoll.c
index b00d422..8c99501 100644
--- a/os/ospoll.c
+++ b/os/ospoll.c
@@ -352,10 +352,14 @@ ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
 epoll_mod(ospoll, osfd);
 #endif
 #if POLL
-if (xevents & X_NOTIFY_READ)
+if (xevents & X_NOTIFY_READ) {
 ospoll->fds[pos].events |= POLLIN;
-if (xevents & X_NOTIFY_WRITE)
+ospoll->fds[pos].revents &= ~POLLIN;
+}
+if (xevents & X_NOTIFY_WRITE) {
 ospoll->fds[pos].events |= POLLOUT;
+ospoll->fds[pos].revents &= ~POLLOUT;
+}
 #endif
 }
 }

I did find a bug with the NewOutputPending flag. We don't actually flush
the client's buffer if there are still requests queued. This is a change
From the previous behavior.

diff --git a/os/io.c b/os/io.c
index ff0ec3d..c6db028 100644
--- a/os/io.c
+++ b/os/io.c
@@ -615,6 +615,8 @@ FlushAllOutput(void)
 if (!client_is_ready(client)) {
 oc = (OsCommPtr) client->osPrivate;
 (void) FlushClient(client, oc, (char *) NULL, 0);
+} else {
+NewOutputPending = TRUE;
 }
 }
 }

-- 
-keith


signature.asc
Description: PGP signature
___
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

[PATCH 1/2] os/connection: Call ClientReady() based on a level trigger rather than an edge trigger

2016-09-17 Thread Jeremy Huddleston Sequoia
On encountering an EAGAIN, FlushClient() re-adds the client to the pending list
and returns, but FlushClient() doesn't get called again.  We would expect it to
be called via FlushAllOutput() via WaitForSomething(), but that only happens
when NewOutputPending is set.  FlushAllOutput() also early-exits if
NewOutputPending is not set.

The only place that is setting NewOutputPending is ClientReady().  The problem
there is that ClientReady() is called based on an edge trigger and not a level
trigger.

Signed-off-by: Jeremy Huddleston Sequoia 
CC: Keith Packard 
---
 os/connection.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/os/connection.c b/os/connection.c
index 0d42184..4630438 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -749,7 +749,7 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, 
CARD32 conn_time)
 SetConnectionTranslation(fd, client->index);
 #endif
 ospoll_add(server_poll, fd,
-   ospoll_trigger_edge,
+   ospoll_trigger_level,
ClientReady,
client);
 set_poll_client(client);
-- 
2.10.0 (Apple Git-99)

___
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel