nim-lang / Nim

Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
https://nim-lang.org
Other
16.62k stars 1.47k forks source link

std/asyncfile is not async. Documentation don't mention it #23461

Open Alogani opened 8 months ago

Alogani commented 8 months ago

Description

Hello,

std/asyncfile implementation is not truly async because it doesn't use selectors (at least on Unix. I don't know on Windows). The documentation don't mention it, resulting in deceptive behaviour

This is not a problem for regular files. But it's problematic for fifo, pipes, etc. For example, creating an asyncfile from stdin won't have the expected behaviour, because the call will be blocking the main thread.

Nim Version

2.0.2

Current Output

No response

Expected Output

No response

Possible Solution

The solution is to modify the current implementation to use for example addRead before reading asyncfile. For epoll, using addRead on regular file will raise an error.

Here are some proposal from some of my own library :

proc readSelect(self: AsyncFile): Future[void] =
    result = self.readListener.wait()
    if not self.pollable or self.readListener.isListening():
        return
    if bool(self.cancelled):
        self.readListener.trigger()
        return
    self.readListener.clear()
    proc cb(fd: AsyncFD): bool {.closure gcsafe.} =
        self.readListener.trigger()
        true
    AsyncFD(self.fd).addRead(cb)
## Or simpler, but could result in multiple callbacks for same AsyncFd :
proc readSelect(self: AsyncFile): Future[void] =
    var fut = newFuture[void]()
    proc cb(fd: AsyncFD): bool {.closure gcsafe.} =
        var fut.complete
        true
    AsyncFD(self.fd).addRead(cb)
    return fut
## Solution on Unix only
proc isPollable(fd: cint): bool =
    ## EPOLL will throw error on regular file and /dev/null (warning: /dev/null not checked)
    ## Solution: no async on regular file
    var stat: Stat
    discard fstat(fd, stat)
    not S_ISREG(stat.st_mode)

Additional Information

No response

Araq commented 8 months ago

On Windows it is async.