about summary refs log tree commit diff stats
path: root/src/local
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
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')
-rw-r--r--src/local/client.nim17
-rw-r--r--src/local/container.nim13
-rw-r--r--src/local/pager.nim6
3 files changed, 26 insertions, 10 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:
diff --git a/src/local/container.nim b/src/local/container.nim
index 03cad675..5d5e6669 100644
--- a/src/local/container.nim
+++ b/src/local/container.nim
@@ -1,6 +1,5 @@
 import std/deques
 import std/options
-import std/streams
 import std/unicode
 
 when defined(posix):
@@ -11,6 +10,7 @@ import display/term
 import extern/stdio
 import io/promise
 import io/serialize
+import io/socketstream
 import js/javascript
 import js/jstypes
 import js/regex
@@ -144,8 +144,8 @@ jsDestructor(Highlight)
 jsDestructor(Container)
 
 proc newBuffer*(forkserver: ForkServer, config: BufferConfig,
-    request: Request, attrs: WindowAttributes, title = "",
-    redirectdepth = 0, canreinterpret = true, fd = FileHandle(-1),
+    request: Request, attrs: WindowAttributes, title: string,
+    redirectdepth: int, canreinterpret: bool, fd: FileHandle,
     contentType: Option[string]): Container =
   let (process, loaderPid) = forkserver.forkBuffer(request, config, attrs)
   if fd != -1:
@@ -1575,12 +1575,13 @@ proc handleCommand(container: Container) =
   container.iface.stream.sread(packetid)
   container.iface.resolve(packetid, len - slen(packetid))
 
-proc setStream*(container: Container, stream: Stream) =
+proc setStream*(container: Container, stream: SocketStream,
+    registerFun: proc(fd: int)) =
   if not container.cloned:
-    container.iface = newBufferInterface(stream)
+    container.iface = newBufferInterface(stream, registerFun)
     container.load()
   else:
-    container.iface = cloneInterface(stream)
+    container.iface = cloneInterface(stream, registerFun)
     # Maybe we have to resume loading. Let's try.
     discard container.iface.load().then(proc(res: int) =
       container.onload(res)
diff --git a/src/local/pager.nim b/src/local/pager.nim
index 1040c259..d8f7c5dd 100644
--- a/src/local/pager.nim
+++ b/src/local/pager.nim
@@ -21,8 +21,8 @@ import extern/editor
 import extern/runproc
 import extern/stdio
 import extern/tempfile
+import io/posixstream
 import io/promise
-import io/socketstream
 import js/error
 import js/javascript
 import js/jstypes
@@ -86,7 +86,7 @@ type
     statusgrid*: FixedGrid
     term*: Terminal
     tmpdir: string
-    unreg*: seq[(Pid, SocketStream)]
+    unreg*: seq[(Pid, PosixStream)]
     urimethodmap: URIMethodMap
     username: string
 
@@ -583,7 +583,7 @@ proc deleteContainer(pager: Pager, container: Container) =
       pager.setContainer(nil)
   container.parent = nil
   container.children.setLen(0)
-  pager.unreg.add((container.process, SocketStream(container.iface.stream)))
+  pager.unreg.add((container.process, container.iface.stream))
   pager.forkserver.removeChild(container.process)
 
 proc discardBuffer(pager: Pager, container = none(Container)) {.jsfunc.} =