about summary refs log tree commit diff stats
path: root/src/loader
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-09-03 00:07:40 +0200
committerbptato <nincsnevem662@gmail.com>2024-09-03 00:15:20 +0200
commit6d8c2fca2e39cc9f3cc9a99cac5584864eaa0ed4 (patch)
tree72a4dad7bec3afa433574df7b3413b0177d21aea /src/loader
parent6ecac397b43de14589c29b601fd9e4d8b8524d9a (diff)
downloadchawan-6d8c2fca2e39cc9f3cc9a99cac5584864eaa0ed4.tar.gz
loader: fix crashes with kqueue backend
pain...

(also, fix an fd leak, plus a more general bug where we registered
empty output handles.)
Diffstat (limited to 'src/loader')
-rw-r--r--src/loader/loader.nim25
-rw-r--r--src/loader/loaderhandle.nim2
2 files changed, 23 insertions, 4 deletions
diff --git a/src/loader/loader.nim b/src/loader/loader.nim
index 01593a00..b655b917 100644
--- a/src/loader/loader.nim
+++ b/src/loader/loader.nim
@@ -196,9 +196,27 @@ proc register(ctx: LoaderContext; output: OutputHandle) =
   ctx.selector.registerHandle(int(output.ostream.fd), {Write}, 0)
   output.registered = true
 
+const bsdPlatform = defined(macosx) or defined(freebsd) or defined(netbsd) or
+  defined(openbsd) or defined(dragonfly)
 proc unregister(ctx: LoaderContext; output: OutputHandle) =
   assert output.registered
-  ctx.selector.unregister(int(output.ostream.fd))
+  # so kqueue-based selectors raise when we try to unregister a pipe whose
+  # reader is at EOF. "solution": clean up this mess ourselves.
+  let fd = int(output.ostream.fd)
+  when bsdPlatform:
+    let oc = ctx.selector.count
+    try:
+      ctx.selector.unregister(fd)
+    except IOSelectorsException:
+      # ????
+      for name, f in ctx.selector[].fieldPairs:
+        when name == "fds":
+          cast[ptr int](addr f[fd])[] = -1
+        elif name == "changes":
+          f.setLen(0)
+      ctx.selector.count = oc - 1
+  else:
+    ctx.selector.unregister(int(output.ostream.fd))
   output.registered = false
 
 # Either write data to the target output, or append it to the list of buffers to
@@ -405,6 +423,7 @@ proc loadFromCache(ctx: LoaderContext; client: ClientData; handle: LoaderHandle;
     let ps = newPosixStream(client.cacheMap[n].path, O_RDONLY, 0)
     if startFrom != 0:
       ps.seek(startFrom)
+    handle.istream = ps
     if ps == nil:
       handle.rejectHandle(ERROR_FILE_NOT_IN_CACHE)
       client.cacheMap.del(n)
@@ -412,7 +431,6 @@ proc loadFromCache(ctx: LoaderContext; client: ClientData; handle: LoaderHandle;
     handle.sendResult(0)
     handle.sendStatus(200)
     handle.sendHeaders(newHeaders())
-    handle.istream = ps
     handle.output.ostream.setBlocking(false)
     let cachedHandle = ctx.findCachedHandle(id)
     ctx.loadStreamRegular(handle, cachedHandle)
@@ -497,7 +515,8 @@ proc loadResource(ctx: LoaderContext; client: ClientData;
             let output = outputIn.tee(ostream, ctx.getOutputId(), client.pid)
             ctx.outputMap[ostream.fd] = output
             output.suspended = false
-            ctx.register(output)
+            if not output.isEmpty:
+              ctx.register(output)
           else:
             ostream.sclose()
         ctx.addFd(handle)
diff --git a/src/loader/loaderhandle.nim b/src/loader/loaderhandle.nim
index 7637bdac..156bd22c 100644
--- a/src/loader/loaderhandle.nim
+++ b/src/loader/loaderhandle.nim
@@ -195,12 +195,12 @@ proc iclose*(handle: LoaderHandle) =
     handle.istream = nil
 
 proc oclose*(output: OutputHandle) =
+  assert not output.registered
   output.ostream.sclose()
   output.ostream = nil
 
 proc close*(handle: LoaderHandle) =
   handle.iclose()
   for output in handle.outputs:
-    assert not output.registered
     if output.ostream != nil:
       output.oclose()