diff options
author | bptato <nincsnevem662@gmail.com> | 2022-11-24 20:03:21 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2022-11-24 20:03:21 +0100 |
commit | 896489a6c500e28f13d0237ab691622cb5c5114f (patch) | |
tree | 91b92da01bc126c2489a3dd083df5f9de06927c6 /src/buffer | |
parent | ee930b0f5a587768d340c4204cf1f2e9fb818c89 (diff) | |
download | chawan-896489a6c500e28f13d0237ab691622cb5c5114f.tar.gz |
Avoid forking child processes from the main process
Caveat: this breaks piped streams.
Diffstat (limited to 'src/buffer')
-rw-r--r-- | src/buffer/buffer.nim | 50 | ||||
-rw-r--r-- | src/buffer/container.nim | 80 |
2 files changed, 53 insertions, 77 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim index 685fa4db..260fc8ea 100644 --- a/src/buffer/buffer.nim +++ b/src/buffer/buffer.nim @@ -30,6 +30,7 @@ import io/window import layout/box import render/renderdocument import render/rendertext +import types/buffersource import types/color import types/url import utils/twtstr @@ -43,21 +44,7 @@ type ContainerCommand* = enum SET_LINES, SET_NEEDS_AUTH, SET_CONTENT_TYPE, SET_REDIRECT, SET_TITLE, SET_HOVER, READ_LINE, LOAD_DONE, ANCHOR_FOUND, ANCHOR_FAIL, JUMP, OPEN, - SOURCE_READY, RESHAPE - - BufferSourceType* = enum - CLONE, LOAD_REQUEST, LOAD_PIPE - - BufferSource* = object - location*: URL - contenttype*: Option[string] # override - case t*: BufferSourceType - of CLONE: - clonepid*: Pid - of LOAD_REQUEST: - request*: Request - of LOAD_PIPE: - fd*: FileHandle + BUFFER_READY, SOURCE_READY, RESHAPE BufferMatch* = object success*: bool @@ -84,6 +71,7 @@ type pistream: Stream # for input pipe postream: Stream # for output pipe streamclosed: bool + loaded: bool source: string prevnode: StyledNode loader: FileLoader @@ -361,6 +349,7 @@ func getFd(buffer: Buffer): FileHandle = return buffer.bsource.fd proc setupSource(buffer: Buffer): int = + if buffer.loaded: return -2 let source = buffer.bsource let setct = source.contenttype.isNone if not setct: @@ -369,6 +358,7 @@ proc setupSource(buffer: Buffer): int = case source.t of CLONE: buffer.istream = connectSocketStream(source.clonepid) + if buffer.istream == nil: return -2 if setct: buffer.contenttype = "text/plain" of LOAD_PIPE: @@ -394,6 +384,7 @@ proc setupSource(buffer: Buffer): int = if setct: buffer.writeCommand(SET_CONTENT_TYPE, buffer.contenttype) buffer.selector.registerHandle(cast[int](buffer.getFd()), {Read}, 1) + buffer.loaded = true proc load(buffer: Buffer) = case buffer.contenttype @@ -805,7 +796,7 @@ proc readCommand(buffer: Buffer) = istream.sread(cy) buffer.updateHover(cx, cy) of GET_SOURCE: - let ssock = initServerSocket(getpid()) + let ssock = initServerSocket() buffer.writeCommand(SOURCE_READY) let stream = ssock.acceptSocketStream() if not buffer.streamclosed: @@ -815,10 +806,7 @@ proc readCommand(buffer: Buffer) = stream.close() ssock.close() -proc runBuffer(buffer: Buffer, readf, writef: File) = - buffer.pistream = newFileStream(readf) - buffer.postream = newFileStream(writef) - let rfd = readf.getFileHandle() +proc runBuffer(buffer: Buffer, rfd: int) = block loop: while true: let events = buffer.selector.select(-1) @@ -842,21 +830,25 @@ proc runBuffer(buffer: Buffer, readf, writef: File) = buffer.writeCommand(RESHAPE) buffer.pistream.close() buffer.postream.close() - when defined(posix): - #TODO remove this - if buffer.loader != nil: - assert kill(buffer.loader.process, cint(SIGTERM)) == 0 - buffer.loader = nil + buffer.loader.quit() quit(0) proc launchBuffer*(config: BufferConfig, source: BufferSource, - attrs: WindowAttributes, readf, writef: File) = + attrs: WindowAttributes, loader: FileLoader, + mainproc: Pid) = let buffer = new Buffer buffer.attrs = attrs buffer.windowChange() buffer.config = config - buffer.loader = newFileLoader() + buffer.loader = loader buffer.bsource = source buffer.selector = newSelector[int]() - buffer.selector.registerHandle(int(readf.getFileHandle()), {Read}, 0) - buffer.runBuffer(readf, writef) + let sstream = connectSocketStream(mainproc, false) + sstream.swrite(getpid()) + sstream.swrite(BUFFER_READY) + sstream.flush() + buffer.pistream = sstream + buffer.postream = sstream + let rfd = int(sstream.source.getFd()) + buffer.selector.registerHandle(rfd, {Read}, 0) + buffer.runBuffer(rfd) diff --git a/src/buffer/container.nim b/src/buffer/container.nim index 054424ce..4241e886 100644 --- a/src/buffer/container.nim +++ b/src/buffer/container.nim @@ -13,9 +13,12 @@ import config/bufferconfig import config/config import io/request import io/window +import ips/forkserver import ips/serialize import js/javascript import js/regex +import types/buffersource +import types/dispatcher import types/url import utils/twtstr @@ -64,8 +67,7 @@ type sourcepair*: Container istream*: Stream ostream*: Stream - ifd*: FileHandle - process: Pid + process*: Pid lines: SimpleFlexibleGrid lineshift: int numLines*: int @@ -76,53 +78,28 @@ type ispipe: bool jump: bool hlon*: bool + waitfor: bool pipeto: Container redraw*: bool + sourceready*: bool -proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize_t): cint {. - importc: "setvbuf", header: "<stdio.h>", tags: [].} - -proc newBuffer*(config: Config, source: BufferSource, ispipe = false): Container = +proc newBuffer*(dispatcher: Dispatcher, config: Config, source: BufferSource, ispipe = false, autoload = true): Container = let attrs = getWindowAttributes(stdout) - when defined(posix): - var pipefd_in, pipefd_out: array[0..1, cint] - if pipe(pipefd_in) == -1: - raise newException(Defect, "Failed to open input pipe.") - if pipe(pipefd_out) == -1: - raise newException(Defect, "Failed to open output pipe.") - let pid = fork() - if pid == -1: - raise newException(Defect, "Failed to fork buffer process") - elif pid == 0: - let bconfig = config.loadBufferConfig() - discard close(stdout.getFileHandle()) - # child process - discard close(pipefd_in[1]) # close write - discard close(pipefd_out[0]) # close read - var readf, writef: File - if not open(readf, pipefd_in[0], fmRead): - raise newException(Defect, "Failed to open input handle") - if not open(writef, pipefd_out[1], fmWrite): - raise newException(Defect, "Failed to open output handle") - discard c_setvbuf(readf, nil, IONBF, 0) - launchBuffer(bconfig, source, attrs, readf, writef) - else: - discard close(pipefd_in[0]) # close read - discard close(pipefd_out[1]) # close write - var readf, writef: File - if not open(writef, pipefd_in[1], fmWrite): - raise newException(Defect, "Failed to open output handle") - if not open(readf, pipefd_out[0], fmRead): - raise newException(Defect, "Failed to open input handle") - let istream = newFileStream(readf) - # Disable buffering of the read end so epoll doesn't get stuck - discard c_setvbuf(readf, nil, IONBF, 0) - let ostream = newFileStream(writef) - result = Container(istream: istream, ostream: ostream, source: source, - ifd: pipefd_out[0], process: pid, attrs: attrs, - width: attrs.width, height: attrs.height - 1, - contenttype: source.contenttype, ispipe: ispipe) - result.pos.setx = -1 + let ostream = dispatcher.forkserver.ostream + let istream = dispatcher.forkserver.istream + ostream.swrite(FORK_BUFFER) + ostream.swrite(source) + ostream.swrite(config.loadBufferConfig()) + ostream.swrite(attrs) + ostream.swrite(dispatcher.mainproc) + ostream.flush() + result = Container( + source: source, attrs: attrs, width: attrs.width, + height: attrs.height - 1, contenttype: source.contenttype, + ispipe: ispipe, waitfor: true + ) + istream.sread(result.process) + result.pos.setx = -1 func lineLoaded(container: Container, y: int): bool = return y - container.lineshift in 0..container.lines.high @@ -583,14 +560,14 @@ proc reshape*(container: Container, noreq = false) {.jsfunc.} = if not noreq: container.requestLines() -proc dupeBuffer*(container: Container, config: Config, location = none(URL), contenttype = none(string)): Container = +proc dupeBuffer*(dispatcher: Dispatcher, container: Container, config: Config, location = none(URL), contenttype = none(string)): Container = let source = BufferSource( t: CLONE, location: location.get(container.source.location), contenttype: if contenttype.isSome: contenttype else: container.contenttype, clonepid: container.process, ) - container.pipeto = newBuffer(config, source, container.ispipe) + container.pipeto = dispatcher.newBuffer(config, source, container.ispipe) container.writeCommand(GET_SOURCE) return container.pipeto @@ -639,6 +616,7 @@ proc handleCommand(container: Container, cmd: ContainerCommand): ContainerEvent container.istream.sread(container.hovertext) of LOAD_DONE: container.istream.sread(container.code) + if container.code == -2: return if container.code != 0: return ContainerEvent(t: FAIL) return ContainerEvent(t: SUCCESS) @@ -667,7 +645,13 @@ proc handleCommand(container: Container, cmd: ContainerCommand): ContainerEvent container.setCursorXY(x, y) container.jump = false of OPEN: - return ContainerEvent(t: OPEN, request: container.istream.readRequest()) + var request: Request + container.istream.sread(request) + return ContainerEvent(t: OPEN, request: request) + of BUFFER_READY: + if container.waitfor: + container.waitfor = false + container.load() of SOURCE_READY: if container.pipeto != nil: container.pipeto.load() |