Alogani / asyncproc

Flexible child process spawner with strong async features
MIT License
11 stars 1 forks source link

Interactive+CaptureInput with unmerged Stdout and Stderr not implemented #1

Closed Alogani closed 5 months ago

Alogani commented 5 months ago

https://github.com/Alogani/asyncproc/blob/23949006ca7164b73fcfe9f9c22b34bbb1fbe67d/src/asyncproc/private/childproc_posix.nim#L79

Also need a refactor of proc newChildTerminal*(mergeStderr: bool) (handling streams closing/termios restore -> cleanups), to delegate less its responsabilities : https://github.com/Alogani/asyncproc/blob/23949006ca7164b73fcfe9f9c22b34bbb1fbe67d/src/asyncproc/private/childproc_posix.nim#L44

Alogani commented 5 months ago

Problem seems still present in last commit.

It seems to be focused on this line :

https://github.com/Alogani/asyncproc/blob/4fb0c41b7883b489c105ef629dfd42a45bac544a/src/asyncproc/private/childproc_posix.nim#L120

It seems posix.read in asyncfile.read is called even if file is not ready for read. It has not been possible yet to isolate the problem.

Alogani commented 5 months ago

Isolation of the problem :

using termios.tcgetattr in conjonction can make poll thinks data is available when there is not. If a read occurs at this moment, posix.read will block undefinitly even if new data is available

Still in progress to find how to circumvet the problem

Alogani commented 5 months ago

Proof of concept try

This code snipset works flawlessly (with TCSANOW and TCSAFLUSH with no distinction), which make the identification of the problem still difficult :

import asyncio/exports/asyncfile {.all.}
import termios, posix, os, bitops

var termiosBackup: Termios
if tcGetAttr(STDIN_FILENO, addr termiosBackup) == -1: raiseOSError(osLastError())
var termiosModified = termiosBackup
termiosModified = termiosBackup
termiosModified.c_lflag.clearMask(ICANON)
termiosModified.c_lflag.clearMask(ISIG)
termiosModified.c_lflag.clearMask(ECHO)
termiosModified.c_cc[VMIN] = 1.char
termiosModified.c_cc[VTIME] = 0.char

proc makeRaw() =
    if tcsetattr(STDIN_FILENO, TCSAFLUSH, addr termiosModified) == -1: raiseOSError(osLastError())

proc restore() =
    if tcsetattr(STDIN_FILENO, TCSAFLUSH, addr termiosBackup) == -1: raiseOSError(osLastError())

proc main() {.async.} =
    var fut: Future[string]
    echo "Simple read"
    echo await stdinAsync.readAvailable(10)
    while true:

        echo "Raw before poll"
        makeRaw()
        echo await stdinAsync.readAvailable(10)

        echo "Restored before poll"
        restore()
        echo await stdinAsync.readAvailable(10)

        echo "Raw after poll"
        fut = stdinAsync.readAvailable(10)
        await sleepAsync(10)
        makeRaw()
        echo await fut

        echo "Restored after poll"
        fut = stdinAsync.readAvailable(10)
        await sleepAsync(10)
        restore()
        echo await fut

waitFor main()