about summary refs log tree commit diff stats
path: root/src/local/client.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-02-29 23:23:40 +0100
committerbptato <nincsnevem662@gmail.com>2024-02-29 23:31:38 +0100
commitafafcaf1047f721c8d061d883329d0e556326511 (patch)
tree2abc62a06227c7aa9c573f9ce52424df638ccba8 /src/local/client.nim
parentf4b53af1261e6f9be16a315247ace80fcb816505 (diff)
downloadchawan-afafcaf1047f721c8d061d883329d0e556326511.tar.gz
buffer, client: fix deadlock with send() calls
This is an ancient bug, but it got much easier to trigger with mouse
scrolling support so it's time to fix it.

(The bug itself was that since both the client and buffer ends of the
controlling stream are blocking, they could get stuck when both were
trying to send() data to the other end but the buffer was full. So now
we set the client end to non-blocking.)
Diffstat (limited to 'src/local/client.nim')
-rw-r--r--src/local/client.nim17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/local/client.nim b/src/local/client.nim
index 76a61bfa..3a80b4bf 100644
--- a/src/local/client.nim
+++ b/src/local/client.nim
@@ -21,6 +21,7 @@ import display/term
 import html/chadombuilder
 import html/dom
 import html/event
+import io/bufstream
 import io/posixstream
 import io/promise
 import io/socketstream
@@ -41,6 +42,7 @@ import loader/loader
 import loader/request
 import local/container
 import local/pager
+import server/buffer
 import server/forkserver
 import types/blob
 import types/cookie
@@ -450,12 +452,15 @@ proc acceptBuffers(client: Client) =
       client.pager.procmap.del(pid)
     stream.close()
   var accepted: seq[Pid]
+  let registerFun = proc(fd: int) =
+    client.selector.unregister(fd)
+    client.selector.registerHandle(fd, {Read, Write}, 0)
   for pid, container in client.pager.procmap:
     let stream = connectSocketStream(pid, buffered = false, blocking = true)
     if stream == nil:
       client.pager.alert("Error: failed to set up buffer")
       continue
-    container.setStream(stream)
+    container.setStream(stream, registerFun)
     let fd = int(stream.fd)
     client.fdmap[fd] = container
     client.selector.registerHandle(fd, {Read}, 0)
@@ -513,6 +518,12 @@ proc handleRead(client: Client, fd: int) =
     let container = client.fdmap[fd]
     client.pager.handleEvent(container)
 
+proc handleWrite(client: Client, fd: int) =
+  let container = client.fdmap[fd]
+  if container.iface.stream.flushWrite():
+    client.selector.unregister(fd)
+    client.selector.registerHandle(fd, {Read}, 0)
+
 proc flushConsole*(client: Client) {.jsfunc.} =
   if client.console == nil:
     # hack for when client crashes before console has been initialized
@@ -561,6 +572,8 @@ proc inputLoop(client: Client) =
     for event in events:
       if Read in event.events:
         client.handleRead(event.fd)
+      if Write in event.events:
+        client.handleWrite(event.fd)
       if Error in event.events:
         client.handleError(event.fd)
       if Signal in event.events:
@@ -597,6 +610,8 @@ proc headlessLoop(client: Client) =
     for event in events:
       if Read in event.events:
         client.handleRead(event.fd)
+      if Write in event.events:
+        client.handleWrite(event.fd)
       if Error in event.events:
         client.handleError(event.fd)
       if selectors.Event.Timer in event.events: