2254 lines
80 KiB
Diff
2254 lines
80 KiB
Diff
From b50326bf9b53f02d7a1244dbf12a00b35a0ff71e Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Sun, 30 Jan 2022 10:20:04 +0100
|
|
Subject: [PATCH 1/8] nimNoLibc float formatting
|
|
|
|
---
|
|
lib/pure/strutils.nim | 6 ++-
|
|
lib/system/formatfloat.nim | 76 +++++++++++++++++++-------------------
|
|
lib/system/strmantle.nim | 67 ++++++++++++++++++---------------
|
|
3 files changed, 80 insertions(+), 69 deletions(-)
|
|
|
|
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
|
|
index 361fa72ef..9c6dd5225 100644
|
|
--- a/lib/pure/strutils.nim
|
|
+++ b/lib/pure/strutils.nim
|
|
@@ -1839,7 +1839,7 @@ func find*(a: SkipTable, s, sub: string, start: Natural = 0, last = 0): int {.
|
|
inc skip, a[s[skip + subLast]]
|
|
return -1
|
|
|
|
-when not (defined(js) or defined(nimdoc) or defined(nimscript)):
|
|
+when not (defined(js) or defined(nimdoc) or defined(nimscript) or defined(nimNoLibc)):
|
|
func c_memchr(cstr: pointer, c: char, n: csize_t): pointer {.
|
|
importc: "memchr", header: "<string.h>".}
|
|
func c_strstr(haystack, needle: cstring): cstring {.
|
|
@@ -2327,7 +2327,7 @@ func validIdentifier*(s: string): bool {.rtl, extern: "nsuValidIdentifier".} =
|
|
|
|
|
|
# floating point formatting:
|
|
-when not defined(js):
|
|
+when not (defined(js) or defined(nimNoLibc)):
|
|
func c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
|
|
importc: "sprintf", varargs}
|
|
|
|
@@ -2377,6 +2377,8 @@ func formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
|
|
# Depending on the locale either dot or comma is produced,
|
|
# but nothing else is possible:
|
|
if result[i] in {'.', ','}: result[i] = decimalSep
|
|
+ elif defined(nimNoLibc):
|
|
+ discard # TODO
|
|
else:
|
|
const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e']
|
|
var
|
|
diff --git a/lib/system/formatfloat.nim b/lib/system/formatfloat.nim
|
|
index 3bcd3257b..c81c08dda 100644
|
|
--- a/lib/system/formatfloat.nim
|
|
+++ b/lib/system/formatfloat.nim
|
|
@@ -7,14 +7,14 @@
|
|
# distribution, for details about the copyright.
|
|
#
|
|
|
|
-proc c_memcpy(a, b: pointer, size: csize_t): pointer {.importc: "memcpy", header: "<string.h>", discardable.}
|
|
+from system/memory import nimCopyMem
|
|
|
|
proc addCstringN(result: var string, buf: cstring; buflen: int) =
|
|
# no nimvm support needed, so it doesn't need to be fast here either
|
|
let oldLen = result.len
|
|
let newLen = oldLen + buflen
|
|
result.setLen newLen
|
|
- c_memcpy(result[oldLen].addr, buf, buflen.csize_t)
|
|
+ nimCopyMem(result[oldLen].addr, buf, buflen.csize_t)
|
|
|
|
import dragonbox, schubfach
|
|
|
|
@@ -30,8 +30,9 @@ proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int
|
|
result = float32ToChars(buf, value, forceTrailingDotZero=true)
|
|
buf[result] = '\0'
|
|
|
|
-proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
|
|
- importc: "sprintf", varargs, noSideEffect.}
|
|
+when not defined(nimNoLibc):
|
|
+ proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
|
|
+ importc: "sprintf", varargs, noSideEffect.}
|
|
|
|
proc writeToBuffer(buf: var array[65, char]; value: cstring) =
|
|
var i = 0
|
|
@@ -39,42 +40,43 @@ proc writeToBuffer(buf: var array[65, char]; value: cstring) =
|
|
buf[i] = value[i]
|
|
inc i
|
|
|
|
-proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int =
|
|
- ## This is the implementation to format floats.
|
|
- ##
|
|
- ## returns the amount of bytes written to `buf` not counting the
|
|
- ## terminating '\0' character.
|
|
- var n: int = c_sprintf(addr buf, "%.16g", value)
|
|
- var hasDot = false
|
|
- for i in 0..n-1:
|
|
- if buf[i] == ',':
|
|
- buf[i] = '.'
|
|
- hasDot = true
|
|
- elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
|
- hasDot = true
|
|
- if not hasDot:
|
|
- buf[n] = '.'
|
|
- buf[n+1] = '0'
|
|
- buf[n+2] = '\0'
|
|
- result = n + 2
|
|
- else:
|
|
- result = n
|
|
- # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)'
|
|
- # of '-1.#IND' are produced.
|
|
- # We want to get rid of these here:
|
|
- if buf[n-1] in {'n', 'N', 'D', 'd', ')'}:
|
|
- writeToBuffer(buf, "nan")
|
|
- result = 3
|
|
- elif buf[n-1] == 'F':
|
|
- if buf[0] == '-':
|
|
- writeToBuffer(buf, "-inf")
|
|
- result = 4
|
|
+when defined(c_sprintf):
|
|
+ proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat): int =
|
|
+ ## This is the implementation to format floats.
|
|
+ ##
|
|
+ ## returns the amount of bytes written to `buf` not counting the
|
|
+ ## terminating '\0' character.
|
|
+ var n: int = c_sprintf(addr buf, "%.16g", value)
|
|
+ var hasDot = false
|
|
+ for i in 0..n-1:
|
|
+ if buf[i] == ',':
|
|
+ buf[i] = '.'
|
|
+ hasDot = true
|
|
+ elif buf[i] in {'a'..'z', 'A'..'Z', '.'}:
|
|
+ hasDot = true
|
|
+ if not hasDot:
|
|
+ buf[n] = '.'
|
|
+ buf[n+1] = '0'
|
|
+ buf[n+2] = '\0'
|
|
+ result = n + 2
|
|
else:
|
|
- writeToBuffer(buf, "inf")
|
|
+ result = n
|
|
+ # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' or 'nan(ind)'
|
|
+ # of '-1.#IND' are produced.
|
|
+ # We want to get rid of these here:
|
|
+ if buf[n-1] in {'n', 'N', 'D', 'd', ')'}:
|
|
+ writeToBuffer(buf, "nan")
|
|
result = 3
|
|
+ elif buf[n-1] == 'F':
|
|
+ if buf[0] == '-':
|
|
+ writeToBuffer(buf, "-inf")
|
|
+ result = 4
|
|
+ else:
|
|
+ writeToBuffer(buf, "inf")
|
|
+ result = 3
|
|
|
|
proc writeFloatToBuffer*(buf: var array[65, char]; value: BiggestFloat | float32): int {.inline.} =
|
|
- when defined(nimPreviewFloatRoundtrip):
|
|
+ when defined(nimPreviewFloatRoundtrip) or not defined(writeFloatToBufferSprintf):
|
|
writeFloatToBufferRoundtrip(buf, value)
|
|
else:
|
|
writeFloatToBufferSprintf(buf, value)
|
|
@@ -92,7 +94,7 @@ proc addFloatSprintf*(result: var string; x: float) =
|
|
doAssert false
|
|
else:
|
|
var buffer {.noinit.}: array[65, char]
|
|
- let n = writeFloatToBufferSprintf(buffer, x)
|
|
+ let n = writeFloatToBuffer(buffer, x)
|
|
result.addCstringN(cstring(buffer[0].addr), n)
|
|
|
|
proc nimFloatToString(a: float): cstring =
|
|
diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim
|
|
index 9cf4f9e55..084e1db6b 100644
|
|
--- a/lib/system/strmantle.nim
|
|
+++ b/lib/system/strmantle.nim
|
|
@@ -43,8 +43,9 @@ proc hashString(s: string): int {.compilerproc.} =
|
|
h = h + h shl 15
|
|
result = cast[int](h)
|
|
|
|
-proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
|
- importc: "strtod", header: "<stdlib.h>", noSideEffect.}
|
|
+when not defined(nimNoLibc):
|
|
+ proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
|
|
+ importc: "strtod", header: "<stdlib.h>", noSideEffect.}
|
|
|
|
const
|
|
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
|
@@ -180,36 +181,42 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
|
number = sign * integer.float * powtens[slop] * powtens[absExponent-slop]
|
|
return i - start
|
|
|
|
- # if failed: slow path with strtod.
|
|
- var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
|
- var ti = 0
|
|
- let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
|
-
|
|
- let endPos = i
|
|
- result = endPos - start
|
|
- i = start
|
|
- # re-parse without error checking, any error should be handled by the code above.
|
|
- if i < endPos and s[i] == '.': i.inc
|
|
- while i < endPos and s[i] in {'0'..'9','+','-'}:
|
|
- if ti < maxlen:
|
|
- t[ti] = s[i]; inc(ti)
|
|
- inc(i)
|
|
- while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point
|
|
+ when defined(c_strtod):
|
|
+ # if failed: slow path with strtod.
|
|
+ var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
|
+ var ti = 0
|
|
+ let maxlen = t.high - "e+000".len # reserve enough space for exponent
|
|
+
|
|
+ let endPos = i
|
|
+ result = endPos - start
|
|
+ i = start
|
|
+ # re-parse without error checking, any error should be handled by the code above.
|
|
+ if i < endPos and s[i] == '.': i.inc
|
|
+ while i < endPos and s[i] in {'0'..'9','+','-'}:
|
|
+ if ti < maxlen:
|
|
+ t[ti] = s[i]; inc(ti)
|
|
inc(i)
|
|
+ while i < endPos and s[i] in {'.', '_'}: # skip underscore and decimal point
|
|
+ inc(i)
|
|
|
|
- # insert exponent
|
|
- t[ti] = 'E'
|
|
- inc(ti)
|
|
- t[ti] = if expNegative: '-' else: '+'
|
|
- inc(ti, 4)
|
|
-
|
|
- # insert adjusted exponent
|
|
- t[ti-1] = ('0'.ord + absExponent mod 10).char
|
|
- absExponent = absExponent div 10
|
|
- t[ti-2] = ('0'.ord + absExponent mod 10).char
|
|
- absExponent = absExponent div 10
|
|
- t[ti-3] = ('0'.ord + absExponent mod 10).char
|
|
- number = c_strtod(addr t, nil)
|
|
+ # insert exponent
|
|
+ t[ti] = 'E'
|
|
+ inc(ti)
|
|
+ t[ti] = if expNegative: '-' else: '+'
|
|
+ inc(ti, 4)
|
|
+
|
|
+ # insert adjusted exponent
|
|
+ t[ti-1] = ('0'.ord + absExponent mod 10).char
|
|
+ absExponent = absExponent div 10
|
|
+ t[ti-2] = ('0'.ord + absExponent mod 10).char
|
|
+ absExponent = absExponent div 10
|
|
+ t[ti-3] = ('0'.ord + absExponent mod 10).char
|
|
+ number = c_strtod(addr t, nil)
|
|
+ else:
|
|
+ number = NaN
|
|
+ raise newException(
|
|
+ FloatInexactDefect,
|
|
+ "insufficent precision in platform-specific parser")
|
|
|
|
when defined(nimHasInvariant):
|
|
{.pop.} # staticBoundChecks
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From e7d190166a317d5a2d73bdee5777cff826319f61 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Tue, 15 Feb 2022 16:28:41 -0600
|
|
Subject: [PATCH 2/8] Massive stub-out for nimNoLibc
|
|
|
|
---
|
|
lib/pure/asyncfile.nim | 2 +-
|
|
lib/pure/dynlib.nim | 16 ++--
|
|
lib/pure/os.nim | 183 +++++++++++++++++++++++----------------
|
|
lib/pure/osproc.nim | 2 +-
|
|
lib/pure/reservedmem.nim | 2 +-
|
|
lib/pure/segfaults.nim | 2 +-
|
|
lib/pure/selectors.nim | 7 +-
|
|
lib/pure/streams.nim | 2 +-
|
|
lib/pure/terminal.nim | 2 +-
|
|
lib/pure/unittest.nim | 2 +-
|
|
lib/std/tempfiles.nim | 2 +-
|
|
lib/system/dyncalls.nim | 36 ++++----
|
|
lib/system/gc_common.nim | 4 +-
|
|
lib/system/mmdisp.nim | 2 +-
|
|
lib/system/strmantle.nim | 2 +-
|
|
lib/system/syslocks.nim | 2 +-
|
|
16 files changed, 153 insertions(+), 115 deletions(-)
|
|
|
|
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
|
|
index 222a89b97..6c5fd8a92 100644
|
|
--- a/lib/pure/asyncfile.nim
|
|
+++ b/lib/pure/asyncfile.nim
|
|
@@ -28,7 +28,7 @@ import asyncdispatch, os
|
|
|
|
when defined(windows) or defined(nimdoc):
|
|
import winlean
|
|
-else:
|
|
+elif defined(posix):
|
|
import posix
|
|
|
|
type
|
|
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
|
|
index 48fd91b8f..b5567a5af 100644
|
|
--- a/lib/pure/dynlib.nim
|
|
+++ b/lib/pure/dynlib.nim
|
|
@@ -118,7 +118,7 @@ when defined(posix) and not defined(nintendoswitch):
|
|
proc unloadLib(lib: LibHandle) = discard dlclose(lib)
|
|
proc symAddr(lib: LibHandle, name: cstring): pointer = dlsym(lib, name)
|
|
|
|
-elif defined(nintendoswitch):
|
|
+elif defined(nintendoswitch) or defined(nimNoLibc):
|
|
#
|
|
# =========================================================================
|
|
# Nintendo switch DevkitPro sdk does not have these. Raise an error if called.
|
|
@@ -126,19 +126,19 @@ elif defined(nintendoswitch):
|
|
#
|
|
|
|
proc dlclose(lib: LibHandle) =
|
|
- raise newException(OSError, "dlclose not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "dlclose not implemented on this platform!")
|
|
proc dlopen(path: cstring, mode: int): LibHandle =
|
|
- raise newException(OSError, "dlopen not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "dlopen not implemented on this platform!")
|
|
proc dlsym(lib: LibHandle, name: cstring): pointer =
|
|
- raise newException(OSError, "dlsym not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "dlsym not implemented on this platform!")
|
|
proc loadLib(path: string, global_symbols = false): LibHandle =
|
|
- raise newException(OSError, "loadLib not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "loadLib not implemented on this platform!")
|
|
proc loadLib(): LibHandle =
|
|
- raise newException(OSError, "loadLib not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "loadLib not implemented on this platform!")
|
|
proc unloadLib(lib: LibHandle) =
|
|
- raise newException(OSError, "unloadLib not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "unloadLib not implemented on this platform!")
|
|
proc symAddr(lib: LibHandle, name: cstring): pointer =
|
|
- raise newException(OSError, "symAddr not implemented on Nintendo Switch!")
|
|
+ raise newException(OSError, "symAddr not implemented on this platform!")
|
|
|
|
elif defined(genode):
|
|
#
|
|
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
|
|
index 24945095f..8674b5e05 100644
|
|
--- a/lib/pure/os.nim
|
|
+++ b/lib/pure/os.nim
|
|
@@ -36,6 +36,9 @@ import strutils, pathnorm
|
|
|
|
const weirdTarget = defined(nimscript) or defined(js)
|
|
|
|
+const fileSystemMissing = not defined(nimdoc) and (
|
|
+ defined(fileSystemMissing) or (defined(genode) and not defined(posix)))
|
|
+
|
|
since (1, 1):
|
|
const
|
|
invalidFilenameChars* = {'/', '\\', ':', '*', '?', '"', '<', '>', '|', '^', '\0'} ## \
|
|
@@ -1163,7 +1166,8 @@ proc fileExists*(filename: string): bool {.rtl, extern: "nos$1",
|
|
## See also:
|
|
## * `dirExists proc <#dirExists,string>`_
|
|
## * `symlinkExists proc <#symlinkExists,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
wrapUnary(a, getFileAttributesW, filename)
|
|
else:
|
|
@@ -1182,7 +1186,8 @@ proc dirExists*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
|
|
## See also:
|
|
## * `fileExists proc <#fileExists,string>`_
|
|
## * `symlinkExists proc <#symlinkExists,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
wrapUnary(a, getFileAttributesW, dir)
|
|
else:
|
|
@@ -1202,7 +1207,8 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
|
|
## See also:
|
|
## * `fileExists proc <#fileExists,string>`_
|
|
## * `dirExists proc <#dirExists,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
wrapUnary(a, getFileAttributesW, link)
|
|
else:
|
|
@@ -1237,46 +1243,48 @@ proc findExe*(exe: string, followSymlinks: bool = true;
|
|
## meets the actual file. This behavior can be disabled if desired
|
|
## by setting `followSymlinks = false`.
|
|
|
|
- if exe.len == 0: return
|
|
- template checkCurrentDir() =
|
|
- for ext in extensions:
|
|
- result = addFileExt(exe, ext)
|
|
- if fileExists(result): return
|
|
- when defined(posix):
|
|
- if '/' in exe: checkCurrentDir()
|
|
+ when fileSystemMissing: discard
|
|
else:
|
|
- checkCurrentDir()
|
|
- let path = getEnv("PATH")
|
|
- for candidate in split(path, PathSep):
|
|
- if candidate.len == 0: continue
|
|
- when defined(windows):
|
|
- var x = (if candidate[0] == '"' and candidate[^1] == '"':
|
|
- substr(candidate, 1, candidate.len-2) else: candidate) /
|
|
- exe
|
|
+ if exe.len == 0: return
|
|
+ template checkCurrentDir() =
|
|
+ for ext in extensions:
|
|
+ result = addFileExt(exe, ext)
|
|
+ if fileExists(result): return
|
|
+ when defined(posix):
|
|
+ if '/' in exe: checkCurrentDir()
|
|
else:
|
|
- var x = expandTilde(candidate) / exe
|
|
- for ext in extensions:
|
|
- var x = addFileExt(x, ext)
|
|
- if fileExists(x):
|
|
- when not defined(windows):
|
|
- while followSymlinks: # doubles as if here
|
|
- if x.symlinkExists:
|
|
- var r = newString(maxSymlinkLen)
|
|
- var len = readlink(x, r, maxSymlinkLen)
|
|
- if len < 0:
|
|
- raiseOSError(osLastError(), exe)
|
|
- if len > maxSymlinkLen:
|
|
- r = newString(len+1)
|
|
- len = readlink(x, r, len)
|
|
- setLen(r, len)
|
|
- if isAbsolute(r):
|
|
- x = r
|
|
+ checkCurrentDir()
|
|
+ let path = getEnv("PATH")
|
|
+ for candidate in split(path, PathSep):
|
|
+ if candidate.len == 0: continue
|
|
+ when defined(windows):
|
|
+ var x = (if candidate[0] == '"' and candidate[^1] == '"':
|
|
+ substr(candidate, 1, candidate.len-2) else: candidate) /
|
|
+ exe
|
|
+ else:
|
|
+ var x = expandTilde(candidate) / exe
|
|
+ for ext in extensions:
|
|
+ var x = addFileExt(x, ext)
|
|
+ if fileExists(x):
|
|
+ when not defined(windows):
|
|
+ while followSymlinks: # doubles as if here
|
|
+ if x.symlinkExists:
|
|
+ var r = newString(maxSymlinkLen)
|
|
+ var len = readlink(x, r, maxSymlinkLen)
|
|
+ if len < 0:
|
|
+ raiseOSError(osLastError(), exe)
|
|
+ if len > maxSymlinkLen:
|
|
+ r = newString(len+1)
|
|
+ len = readlink(x, r, len)
|
|
+ setLen(r, len)
|
|
+ if isAbsolute(r):
|
|
+ x = r
|
|
+ else:
|
|
+ x = parentDir(x) / r
|
|
else:
|
|
- x = parentDir(x) / r
|
|
- else:
|
|
- break
|
|
- return x
|
|
- result = ""
|
|
+ break
|
|
+ return x
|
|
+ result = ""
|
|
|
|
when weirdTarget:
|
|
const times = "fake const"
|
|
@@ -1289,7 +1297,8 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1",
|
|
## * `getLastAccessTime proc <#getLastAccessTime,string>`_
|
|
## * `getCreationTime proc <#getCreationTime,string>`_
|
|
## * `fileNewer proc <#fileNewer,string,string>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
var res: Stat
|
|
if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
|
|
result = res.st_mtim.toTime
|
|
@@ -1307,7 +1316,8 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeir
|
|
## * `getLastModificationTime proc <#getLastModificationTime,string>`_
|
|
## * `getCreationTime proc <#getCreationTime,string>`_
|
|
## * `fileNewer proc <#fileNewer,string,string>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
var res: Stat
|
|
if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
|
|
result = res.st_atim.toTime
|
|
@@ -1329,7 +1339,8 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noWeirdT
|
|
## * `getLastModificationTime proc <#getLastModificationTime,string>`_
|
|
## * `getLastAccessTime proc <#getLastAccessTime,string>`_
|
|
## * `fileNewer proc <#fileNewer,string,string>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
var res: Stat
|
|
if stat(file, res) < 0'i32: raiseOSError(osLastError(), file)
|
|
result = res.st_ctim.toTime
|
|
@@ -1348,7 +1359,8 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noWeirdTarget.} =
|
|
## * `getLastModificationTime proc <#getLastModificationTime,string>`_
|
|
## * `getLastAccessTime proc <#getLastAccessTime,string>`_
|
|
## * `getCreationTime proc <#getCreationTime,string>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
# If we don't have access to nanosecond resolution, use '>='
|
|
when not StatHasNanoseconds:
|
|
result = getLastModificationTime(a) >= getLastModificationTime(b)
|
|
@@ -1371,7 +1383,8 @@ when not defined(nimscript):
|
|
## * `setCurrentDir proc <#setCurrentDir,string>`_
|
|
## * `currentSourcePath template <system.html#currentSourcePath.t>`_
|
|
## * `getProjectPath proc <macros.html#getProjectPath>`_
|
|
- when defined(nodejs):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(nodejs):
|
|
var ret: cstring
|
|
{.emit: "`ret` = process.cwd();".}
|
|
return $ret
|
|
@@ -1428,7 +1441,8 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [], noWeirdTarget.} =
|
|
## * `getConfigDir proc <#getConfigDir>`_
|
|
## * `getTempDir proc <#getTempDir>`_
|
|
## * `getCurrentDir proc <#getCurrentDir>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32:
|
|
raiseOSError(osLastError(), newDir)
|
|
@@ -1565,7 +1579,8 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
|
|
##
|
|
## See also:
|
|
## * `sameFileContent proc <#sameFileContent,string,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var success = true
|
|
var f1 = openHandle(path1)
|
|
var f2 = openHandle(path2)
|
|
@@ -1625,7 +1640,8 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
|
|
## See also:
|
|
## * `setFilePermissions proc <#setFilePermissions,string,set[FilePermission]>`_
|
|
## * `FilePermission enum <#FilePermission>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
var a: Stat
|
|
if stat(filename, a) < 0'i32: raiseOSError(osLastError(), filename)
|
|
result = {}
|
|
@@ -1671,7 +1687,8 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission],
|
|
## See also:
|
|
## * `getFilePermissions <#getFilePermissions,string>`_
|
|
## * `FilePermission enum <#FilePermission>`_
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
var p = 0.Mode
|
|
if fpUserRead in permissions: p = p or S_IRUSR.Mode
|
|
if fpUserWrite in permissions: p = p or S_IWUSR.Mode
|
|
@@ -1750,7 +1767,8 @@ proc createSymlink*(src, dest: string) {.noWeirdTarget.} =
|
|
## * `createHardlink proc <#createHardlink,string,string>`_
|
|
## * `expandSymlink proc <#expandSymlink,string>`_
|
|
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 2
|
|
# allows anyone with developer mode on to create a link
|
|
let flag = dirExists(src).int32 or SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
|
|
@@ -1773,7 +1791,8 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
|
|
##
|
|
## See also:
|
|
## * `createSymlink proc <#createSymlink,string,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
result = symlinkPath
|
|
else:
|
|
result = newString(maxSymlinkLen)
|
|
@@ -1950,7 +1969,8 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE
|
|
## * `removeFile proc <#removeFile,string>`_
|
|
## * `moveFile proc <#moveFile,string,string>`_
|
|
result = true
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
let f = newWideCString(file)
|
|
else:
|
|
@@ -1991,7 +2011,8 @@ proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.}
|
|
## Returns false in case of `EXDEV` error or `AccessDeniedError` on windows (if `isDir` is true).
|
|
## In case of other errors `OSError` is raised.
|
|
## Returns true in case of success.
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
let s = newWideCString(source)
|
|
let d = newWideCString(dest)
|
|
@@ -2001,16 +2022,18 @@ proc tryMoveFSObject(source, dest: string, isDir: bool): bool {.noWeirdTarget.}
|
|
else:
|
|
result = c_rename(source, dest) == 0'i32
|
|
|
|
- if not result:
|
|
- let err = osLastError()
|
|
- let isAccessDeniedError =
|
|
- when defined(windows):
|
|
- const AccessDeniedError = OSErrorCode(5)
|
|
- isDir and err == AccessDeniedError
|
|
- else:
|
|
- err == EXDEV.OSErrorCode
|
|
- if not isAccessDeniedError:
|
|
- raiseOSError(err, $(source, dest))
|
|
+ when fileSystemMissing: discard
|
|
+ else:
|
|
+ if not result:
|
|
+ let err = osLastError()
|
|
+ let isAccessDeniedError =
|
|
+ when defined(windows):
|
|
+ const AccessDeniedError = OSErrorCode(5)
|
|
+ isDir and err == AccessDeniedError
|
|
+ else:
|
|
+ err == EXDEV.OSErrorCode
|
|
+ if not isAccessDeniedError:
|
|
+ raiseOSError(err, $(source, dest))
|
|
|
|
proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
|
|
tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect], noWeirdTarget.} =
|
|
@@ -2093,7 +2116,8 @@ template defaultWalkFilter(item): bool =
|
|
template walkCommon(pattern: string, filter) =
|
|
## Common code for getting the files and directories with the
|
|
## specified `pattern`
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var
|
|
f: WIN32_FIND_DATA
|
|
res: int
|
|
@@ -2189,7 +2213,8 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
|
|
## Returns the full (`absolute`:idx:) path of an existing file `filename`.
|
|
##
|
|
## Raises `OSError` in case of an error. Follows symlinks.
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var bufsize = MAX_PATH.int32
|
|
when useWinUnicode:
|
|
var unused: WideCString = nil
|
|
@@ -2302,7 +2327,8 @@ iterator walkDir*(dir: string; relative = false, checkDir = false):
|
|
for k, v in items(staticWalkDir(dir, relative)):
|
|
yield (k, v)
|
|
else:
|
|
- when weirdTarget:
|
|
+ when fileSystemMissing: discard
|
|
+ elif weirdTarget:
|
|
for k, v in items(staticWalkDir(dir, relative)):
|
|
yield (k, v)
|
|
elif defined(windows):
|
|
@@ -2425,7 +2451,8 @@ iterator walkDirRec*(dir: string,
|
|
# Future work can provide a way to customize this and do error reporting.
|
|
|
|
proc rawRemoveDir(dir: string) {.noWeirdTarget.} =
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
wrapUnary(res, removeDirectoryW, dir)
|
|
else:
|
|
@@ -2468,7 +2495,8 @@ proc rawCreateDir(dir: string): bool {.noWeirdTarget.} =
|
|
#
|
|
# This is a thin wrapper over mkDir (or alternatives on other systems),
|
|
# so in case of a pre-existing path we don't check that it is a directory.
|
|
- when defined(solaris):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(solaris):
|
|
let res = mkdir(dir, 0o777)
|
|
if res == 0'i32:
|
|
result = true
|
|
@@ -2618,7 +2646,8 @@ proc createHardlink*(src, dest: string) {.noWeirdTarget.} =
|
|
##
|
|
## See also:
|
|
## * `createSymlink proc <#createSymlink,string,string>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
when useWinUnicode:
|
|
var wSrc = newWideCString(src)
|
|
var wDst = newWideCString(dest)
|
|
@@ -3217,7 +3246,8 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
|
|
tags: [ReadIOEffect], noWeirdTarget.} =
|
|
## Returns the file size of `file` (in bytes). ``OSError`` is
|
|
## raised in case of an error.
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var a: WIN32_FIND_DATA
|
|
var resA = findFirstFile(file, a)
|
|
if resA == -1: raiseOSError(osLastError(), file)
|
|
@@ -3234,6 +3264,10 @@ when defined(windows) or weirdTarget:
|
|
type
|
|
DeviceId* = int32
|
|
FileId* = int64
|
|
+elif fileSystemMissing:
|
|
+ type
|
|
+ DeviceId* = int
|
|
+ FileId* = int
|
|
else:
|
|
type
|
|
DeviceId* = Dev
|
|
@@ -3344,7 +3378,8 @@ proc getFileInfo*(handle: FileHandle): FileInfo {.noWeirdTarget.} =
|
|
## * `getFileInfo(path) proc <#getFileInfo,string>`_
|
|
|
|
# Done: ID, Kind, Size, Permissions, Link Count
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var rawInfo: BY_HANDLE_FILE_INFORMATION
|
|
# We have to use the super special '_get_osfhandle' call (wrapped above)
|
|
# To transform the C file descriptor to a native file handle.
|
|
@@ -3386,7 +3421,8 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noWeirdTarget.
|
|
## See also:
|
|
## * `getFileInfo(handle) proc <#getFileInfo,FileHandle>`_
|
|
## * `getFileInfo(file) proc <#getFileInfo,File>`_
|
|
- when defined(windows):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(windows):
|
|
var
|
|
handle = openHandle(path, followSymlink)
|
|
rawInfo: BY_HANDLE_FILE_INFORMATION
|
|
@@ -3484,7 +3520,8 @@ proc getCurrentProcessId*(): int {.noWeirdTarget.} =
|
|
proc setLastModificationTime*(file: string, t: times.Time) {.noWeirdTarget.} =
|
|
## Sets the `file`'s last modification time. `OSError` is raised in case of
|
|
## an error.
|
|
- when defined(posix):
|
|
+ when fileSystemMissing: discard
|
|
+ elif defined(posix):
|
|
let unixt = posix.Time(t.toUnix)
|
|
let micro = convert(Nanoseconds, Microseconds, t.nanosecond)
|
|
var timevals = [Timeval(tv_sec: unixt, tv_usec: micro),
|
|
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
|
|
index 6a0ac9a8b..0c9b5b427 100644
|
|
--- a/lib/pure/osproc.nim
|
|
+++ b/lib/pure/osproc.nim
|
|
@@ -25,7 +25,7 @@ export quoteShell, quoteShellWindows, quoteShellPosix
|
|
|
|
when defined(windows):
|
|
import winlean
|
|
-else:
|
|
+elif defined(posix):
|
|
import posix
|
|
|
|
when defined(linux) and defined(useClone):
|
|
diff --git a/lib/pure/reservedmem.nim b/lib/pure/reservedmem.nim
|
|
index 232a2b383..55e194dcb 100644
|
|
--- a/lib/pure/reservedmem.nim
|
|
+++ b/lib/pure/reservedmem.nim
|
|
@@ -79,7 +79,7 @@ when defined(windows):
|
|
if r == cast[typeof(r)](0):
|
|
raiseOSError(osLastError())
|
|
|
|
-else:
|
|
+elif defined(posix):
|
|
import posix
|
|
|
|
let allocationGranularity = sysconf(SC_PAGESIZE)
|
|
diff --git a/lib/pure/segfaults.nim b/lib/pure/segfaults.nim
|
|
index b0eac2299..b1aec8265 100644
|
|
--- a/lib/pure/segfaults.nim
|
|
+++ b/lib/pure/segfaults.nim
|
|
@@ -64,7 +64,7 @@ when defined(windows):
|
|
{.pop.}
|
|
c_signal(SIGSEGV, segfaultHandler)
|
|
|
|
-else:
|
|
+elif defined(posix):
|
|
import posix
|
|
|
|
var sa: Sigaction
|
|
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
|
|
index ec441f6da..21bef9187 100644
|
|
--- a/lib/pure/selectors.nim
|
|
+++ b/lib/pure/selectors.nim
|
|
@@ -27,7 +27,8 @@
|
|
##
|
|
## TODO: `/dev/poll`, `event ports` and filesystem events.
|
|
|
|
-import os, nativesockets
|
|
+when not defined(nimNoLibc):
|
|
+ import os, nativesockets
|
|
|
|
const hasThreadSupport = compileOption("threads") and defined(threadsafe)
|
|
|
|
@@ -232,7 +233,7 @@ when defined(nimdoc):
|
|
##
|
|
## For *poll* and *select* selectors `-1` is returned.
|
|
|
|
-else:
|
|
+elif not defined(nimNoLibc):
|
|
import strutils
|
|
when hasThreadSupport:
|
|
import locks
|
|
@@ -285,7 +286,7 @@ else:
|
|
proc setNonBlocking(fd: cint) {.inline.} =
|
|
setBlocking(fd.SocketHandle, false)
|
|
|
|
- when not defined(windows):
|
|
+ when not defined(windows) and defined(posix):
|
|
import posix
|
|
|
|
template setKey(s, pident, pevents, pparam, pdata: untyped) =
|
|
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
|
|
index 99fe7e073..cf60c8f70 100644
|
|
--- a/lib/pure/streams.nim
|
|
+++ b/lib/pure/streams.nim
|
|
@@ -1467,7 +1467,7 @@ when false:
|
|
when defined(windows):
|
|
# do not import windows as this increases compile times:
|
|
discard
|
|
- else:
|
|
+ elif defined(posix):
|
|
import posix
|
|
|
|
proc hsSetPosition(s: FileHandleStream, pos: int) =
|
|
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
|
|
index 25b1a4cdd..03b79bbee 100644
|
|
--- a/lib/pure/terminal.nim
|
|
+++ b/lib/pure/terminal.nim
|
|
@@ -247,7 +247,7 @@ when defined(windows):
|
|
let term = getTerminal()
|
|
if f == stderr: term.hStderr else: term.hStdout
|
|
|
|
-else:
|
|
+elif defined(posix):
|
|
import termios, posix, os, parseutils
|
|
|
|
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
|
|
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
|
|
index b1c01f8db..c715e12c3 100644
|
|
--- a/lib/pure/unittest.nim
|
|
+++ b/lib/pure/unittest.nim
|
|
@@ -113,7 +113,7 @@ import macros, strutils, streams, times, sets, sequtils
|
|
when declared(stdout):
|
|
import os
|
|
|
|
-const useTerminal = not defined(js)
|
|
+const useTerminal = not (defined(js) or defined(nimNoLibc))
|
|
|
|
when useTerminal:
|
|
import terminal
|
|
diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim
|
|
index ce84c2a37..49b8f766e 100644
|
|
--- a/lib/std/tempfiles.nim
|
|
+++ b/lib/std/tempfiles.nim
|
|
@@ -41,7 +41,7 @@ when defined(windows):
|
|
|
|
proc close_osfandle(fd: cint): cint {.
|
|
importc: "_close", header: "<io.h>".}
|
|
-else:
|
|
+elif defined(posix):
|
|
import posix
|
|
|
|
proc c_fdopen(
|
|
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
|
|
index 36c2c5fe1..39eb24fb0 100644
|
|
--- a/lib/system/dyncalls.nim
|
|
+++ b/lib/system/dyncalls.nim
|
|
@@ -20,15 +20,15 @@ const
|
|
proc nimLoadLibraryError(path: string) =
|
|
# carefully written to avoid memory allocation:
|
|
const prefix = "could not load: "
|
|
- cstderr.rawWrite(prefix)
|
|
- cstderr.rawWrite(path)
|
|
+ writeToStdErr(prefix)
|
|
+ writeToStdErr(path)
|
|
when not defined(nimDebugDlOpen) and not defined(windows):
|
|
- cstderr.rawWrite("\n(compile with -d:nimDebugDlOpen for more information)")
|
|
+ writeToStdErr("\n(compile with -d:nimDebugDlOpen for more information)")
|
|
when defined(windows):
|
|
const badExe = "\n(bad format; library may be wrong architecture)"
|
|
let loadError = GetLastError()
|
|
if loadError == ERROR_BAD_EXE_FORMAT:
|
|
- cstderr.rawWrite(badExe)
|
|
+ writeToStdErr(badExe)
|
|
when defined(guiapp):
|
|
# Because console output is not shown in GUI apps, display the error as a
|
|
# message box instead:
|
|
@@ -46,14 +46,14 @@ proc nimLoadLibraryError(path: string) =
|
|
if loadError == ERROR_BAD_EXE_FORMAT and msgLeft >= badExe.len:
|
|
copyMem(msg[msgIdx].addr, badExe.cstring, badExe.len)
|
|
discard MessageBoxA(nil, msg[0].addr, nil, 0)
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr("\n")
|
|
quit(1)
|
|
|
|
proc procAddrError(name: cstring) {.compilerproc, nonReloadable, hcrInline.} =
|
|
# carefully written to avoid memory allocation:
|
|
- cstderr.rawWrite("could not import: ")
|
|
- cstderr.rawWrite(name)
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr("could not import: ")
|
|
+ writeToStdErr(name)
|
|
+ writeToStdErr("\n")
|
|
quit(1)
|
|
|
|
# this code was inspired from Lua's source code:
|
|
@@ -98,8 +98,8 @@ when defined(posix):
|
|
when defined(nimDebugDlOpen):
|
|
let error = dlerror()
|
|
if error != nil:
|
|
- cstderr.rawWrite(error)
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr(error)
|
|
+ writeToStdErr("\n")
|
|
|
|
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
|
|
result = dlsym(lib, name)
|
|
@@ -176,22 +176,22 @@ elif defined(genode):
|
|
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
|
|
raiseAssert("nimGetProcAddr not implemented")
|
|
|
|
-elif defined(nintendoswitch) or defined(freertos) or defined(zephyr):
|
|
+elif defined(nintendoswitch) or defined(freertos) or defined(zephyr) or defined(nimNoLibc):
|
|
proc nimUnloadLibrary(lib: LibHandle) =
|
|
- cstderr.rawWrite("nimUnLoadLibrary not implemented")
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr("nimUnLoadLibrary not implemented")
|
|
+ writeToStdErr("\n")
|
|
quit(1)
|
|
|
|
proc nimLoadLibrary(path: string): LibHandle =
|
|
- cstderr.rawWrite("nimLoadLibrary not implemented")
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr("nimLoadLibrary not implemented")
|
|
+ writeToStdErr("\n")
|
|
quit(1)
|
|
|
|
|
|
proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
|
|
- cstderr.rawWrite("nimGetProAddr not implemented")
|
|
- cstderr.rawWrite(name)
|
|
- cstderr.rawWrite("\n")
|
|
+ writeToStdErr("nimGetProAddr not implemented")
|
|
+ writeToStdErr(name)
|
|
+ writeToStdErr("\n")
|
|
quit(1)
|
|
|
|
else:
|
|
diff --git a/lib/system/gc_common.nim b/lib/system/gc_common.nim
|
|
index ea8857ece..4fff6d50f 100644
|
|
--- a/lib/system/gc_common.nim
|
|
+++ b/lib/system/gc_common.nim
|
|
@@ -471,7 +471,7 @@ proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} =
|
|
globalMarkers[globalMarkersLen] = markerProc
|
|
inc globalMarkersLen
|
|
else:
|
|
- cstderr.rawWrite("[GC] cannot register global variable; too many global variables")
|
|
+ writeToStdErr("[GC] cannot register global variable; too many global variables")
|
|
quit 1
|
|
|
|
proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.} =
|
|
@@ -479,5 +479,5 @@ proc nimRegisterThreadLocalMarker(markerProc: GlobalMarkerProc) {.compilerproc.}
|
|
threadLocalMarkers[threadLocalMarkersLen] = markerProc
|
|
inc threadLocalMarkersLen
|
|
else:
|
|
- cstderr.rawWrite("[GC] cannot register thread local variable; too many thread local variables")
|
|
+ writeToStdErr("[GC] cannot register thread local variable; too many thread local variables")
|
|
quit 1
|
|
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
|
|
index 3317ba627..422618c0f 100644
|
|
--- a/lib/system/mmdisp.nim
|
|
+++ b/lib/system/mmdisp.nim
|
|
@@ -45,7 +45,7 @@ else:
|
|
|
|
proc raiseOutOfMem() {.noinline.} =
|
|
if outOfMemHook != nil: outOfMemHook()
|
|
- cstderr.rawWrite("out of memory\n")
|
|
+ writeToStdErr("out of memory\n")
|
|
quit(1)
|
|
|
|
when defined(boehmgc):
|
|
diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim
|
|
index 084e1db6b..2521fab9f 100644
|
|
--- a/lib/system/strmantle.nim
|
|
+++ b/lib/system/strmantle.nim
|
|
@@ -181,7 +181,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
|
|
number = sign * integer.float * powtens[slop] * powtens[absExponent-slop]
|
|
return i - start
|
|
|
|
- when defined(c_strtod):
|
|
+ when not defined(nimNoLibc):
|
|
# if failed: slow path with strtod.
|
|
var t: array[500, char] # flaviu says: 325 is the longest reasonable literal
|
|
var ti = 0
|
|
diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim
|
|
index 2f0c8b0ba..0b0324def 100644
|
|
--- a/lib/system/syslocks.nim
|
|
+++ b/lib/system/syslocks.nim
|
|
@@ -97,7 +97,7 @@ elif defined(genode):
|
|
proc broadcastSysCond(cond: var SysCond) {.
|
|
noSideEffect, importcpp.}
|
|
|
|
-else:
|
|
+elif defined(posix):
|
|
type
|
|
SysLockObj {.importc: "pthread_mutex_t", pure, final,
|
|
header: """#include <sys/types.h>
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From 11e259afe417e39fda794c83304cfd815da2dfd6 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Thu, 26 May 2022 12:52:54 -0500
|
|
Subject: [PATCH 3/8] times: Genode native time
|
|
|
|
---
|
|
lib/genode/constructibles.nim | 9 +++++++++
|
|
lib/genode/env.nim | 4 ++--
|
|
lib/genode/rtc.nim | 21 +++++++++++++++++++++
|
|
lib/pure/os.nim | 2 ++
|
|
lib/pure/times.nim | 34 +++++++++++++++++++++++++++++++---
|
|
5 files changed, 65 insertions(+), 5 deletions(-)
|
|
create mode 100644 lib/genode/constructibles.nim
|
|
create mode 100644 lib/genode/rtc.nim
|
|
|
|
diff --git a/lib/genode/constructibles.nim b/lib/genode/constructibles.nim
|
|
new file mode 100644
|
|
index 000000000..8bf6f5162
|
|
--- /dev/null
|
|
+++ b/lib/genode/constructibles.nim
|
|
@@ -0,0 +1,9 @@
|
|
+type Constructible*[T] {.
|
|
+ importcpp: "Genode::Constructible",
|
|
+ header: "<util/reconstructible.h>", byref, pure.} = object
|
|
+
|
|
+proc construct*[T](x: Constructible[T]) {.importcpp.}
|
|
+ ## Construct a constructible C++ object.
|
|
+
|
|
+proc destruct*[T](x: Constructible[T]) {.importcpp.}
|
|
+ ## Destruct a constructible C++ object.
|
|
diff --git a/lib/genode/env.nim b/lib/genode/env.nim
|
|
index ef4a25883..0c2f35a22 100644
|
|
--- a/lib/genode/env.nim
|
|
+++ b/lib/genode/env.nim
|
|
@@ -21,9 +21,9 @@ when not defined(genode):
|
|
|
|
type
|
|
GenodeEnvObj {.importcpp: "Genode::Env", header: "<base/env.h>", pure.} = object
|
|
- GenodeEnvPtr = ptr GenodeEnvObj
|
|
+ GenodeEnvPtr* = ptr GenodeEnvObj
|
|
|
|
const runtimeEnvSym = "nim_runtime_env"
|
|
|
|
when not defined(nimscript):
|
|
- var runtimeEnv {.importcpp: runtimeEnvSym.}: GenodeEnvPtr
|
|
+ var runtimeEnv* {.importcpp: runtimeEnvSym.}: GenodeEnvPtr
|
|
diff --git a/lib/genode/rtc.nim b/lib/genode/rtc.nim
|
|
new file mode 100644
|
|
index 000000000..d2f03454f
|
|
--- /dev/null
|
|
+++ b/lib/genode/rtc.nim
|
|
@@ -0,0 +1,21 @@
|
|
+import ./env, ./constructibles
|
|
+
|
|
+const rtcHeader = "<rtc_session/connection.h>"
|
|
+
|
|
+type
|
|
+ ConnectionBase {.importcpp: "Rtc::Connection", header: rtcHeader.} = object
|
|
+ Connection = Constructible[ConnectionBase]
|
|
+
|
|
+ Timestamp* {.importcpp: "Rtc::Timestamp", header: rtcHeader.} = object
|
|
+ microsecond*, second*, minute*, hour*, day*, month*, year*: cuint
|
|
+
|
|
+proc construct(c: Connection; env: GenodeEnvPtr; label: cstring) {.
|
|
+ importcpp: "#.construct(*#, @)", tags: [IOEffect].}
|
|
+
|
|
+proc timestamp*(c: Connection): Timestamp {.
|
|
+ importcpp: "#->current_time()".}
|
|
+ # There is an RPC call here but its not listed effect.
|
|
+
|
|
+proc initRtcConnection*(env: GenodeEnvPtr; label = ""): Connection =
|
|
+ ## Open a new **RTC** connection.
|
|
+ result.construct(env, label)
|
|
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
|
|
index 8674b5e05..a1f9c8451 100644
|
|
--- a/lib/pure/os.nim
|
|
+++ b/lib/pure/os.nim
|
|
@@ -62,6 +62,8 @@ elif defined(posix):
|
|
|
|
proc toTime(ts: Timespec): times.Time {.inline.} =
|
|
result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
|
|
+elif defined(genode):
|
|
+ import times
|
|
else:
|
|
{.error: "OS module not ported to your operating system!".}
|
|
|
|
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
|
|
index 113f73d2a..a18c9be4f 100644
|
|
--- a/lib/pure/times.nim
|
|
+++ b/lib/pure/times.nim
|
|
@@ -252,6 +252,11 @@ elif defined(windows):
|
|
|
|
proc localtime(a1: var CTime): ptr Tm {.importc, header: "<time.h>", sideEffect.}
|
|
|
|
+elif defined(genode):
|
|
+ # Genode without POSIX
|
|
+ import ../genode/[env, rtc]
|
|
+ var rtcConn = initRtcConnection(runtimeEnv, "times")
|
|
+
|
|
type
|
|
Month* = enum ## Represents a month. Note that the enum starts at `1`,
|
|
## so `ord(month)` will give the month number in the
|
|
@@ -894,6 +899,9 @@ proc toWinTime*(t: Time): int64 =
|
|
## since `1601-01-01T00:00:00Z`).
|
|
result = t.seconds * rateDiff + epochDiff + t.nanosecond div 100
|
|
|
|
+when defined(genode):
|
|
+ proc `+=`*(t: var Time, b: TimeInterval) {.tags: [], gcsafe.}
|
|
+
|
|
proc getTime*(): Time {.tags: [TimeEffect], benign.} =
|
|
## Gets the current time as a `Time` with up to nanosecond resolution.
|
|
when defined(js):
|
|
@@ -915,6 +923,16 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
|
|
var f {.noinit.}: FILETIME
|
|
getSystemTimeAsFileTime(f)
|
|
result = fromWinTime(rdFileTime(f))
|
|
+ elif defined(genode):
|
|
+ var ts = rtcConn.timestamp()
|
|
+ result += TimeInterval(
|
|
+ microseconds: int ts.microsecond,
|
|
+ seconds: int ts.second,
|
|
+ minutes: int ts.minute,
|
|
+ hours: int ts.hour,
|
|
+ days: int ts.day,
|
|
+ months: int ts.month,
|
|
+ years: int ts.year)
|
|
|
|
proc `-`*(a, b: Time): Duration {.operator, extern: "ntDiffTime".} =
|
|
## Computes the duration between two points in time.
|
|
@@ -1222,7 +1240,7 @@ when defined(js):
|
|
result.time = adjTime + initDuration(seconds = result.utcOffset)
|
|
result.isDst = false
|
|
|
|
-else:
|
|
+elif defined(posix):
|
|
proc toAdjUnix(tm: Tm): int64 =
|
|
let epochDay = toEpochDay(tm.tm_mday, (tm.tm_mon + 1).Month,
|
|
tm.tm_year.int + 1900)
|
|
@@ -1284,6 +1302,13 @@ else:
|
|
result.utcOffset = finalOffset
|
|
result.isDst = dst
|
|
|
|
+elif defined(genode):
|
|
+ proc localZonedTimeFromTime(time: Time): ZonedTime {.benign.} =
|
|
+ result.time = time
|
|
+
|
|
+ proc localZonedTimeFromAdjTime(adjTime: Time): ZonedTime {.benign.} =
|
|
+ result.time = adjTime
|
|
+
|
|
proc utcTzInfo(time: Time): ZonedTime =
|
|
ZonedTime(utcOffset: 0, isDst: false, time: time)
|
|
|
|
@@ -1877,9 +1902,9 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
|
|
else:
|
|
result = false
|
|
of yy:
|
|
- # Assumes current century
|
|
+ # Assumes 21st century
|
|
var year = takeInt(2..2)
|
|
- var thisCen = now().year div 100
|
|
+ var thisCen = 20
|
|
parsed.year = some(thisCen*100 + year)
|
|
result = year > 0
|
|
of yyyy:
|
|
@@ -2608,6 +2633,9 @@ proc epochTime*(): float {.tags: [TimeEffect].} =
|
|
var secs = i64 div rateDiff
|
|
var subsecs = i64 mod rateDiff
|
|
result = toFloat(int(secs)) + toFloat(int(subsecs)) * 0.0000001
|
|
+ elif defined(genode):
|
|
+ var t = now().toTime
|
|
+ result = t.seconds.toBiggestFloat + t.nanosecond.toBiggestFloat * 0.000_000_000_1
|
|
elif defined(js):
|
|
result = newDate().getTime() / 1000
|
|
else:
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From 7f3934aba501406c95d69ce271e5456c426f0ba6 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Thu, 26 May 2022 13:05:06 -0500
|
|
Subject: [PATCH 4/8] os: add support for Genode without POSIX
|
|
|
|
---
|
|
lib/pure/os.nim | 20 ++++++++++++++------
|
|
1 file changed, 14 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
|
|
index a1f9c8451..67d481e13 100644
|
|
--- a/lib/pure/os.nim
|
|
+++ b/lib/pure/os.nim
|
|
@@ -1755,6 +1755,8 @@ proc isAdmin*: bool {.noWeirdTarget.} =
|
|
if freeSid(administratorsGroup) != nil:
|
|
raiseOSError(osLastError(), "failed to free SID for Administrators group")
|
|
|
|
+ elif defined(genode): # non-POSIX
|
|
+ discard
|
|
else:
|
|
result = geteuid() == 0
|
|
|
|
@@ -3238,11 +3240,15 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noWeirdTar
|
|
## Sleeps `milsecs` milliseconds.
|
|
when defined(windows):
|
|
winlean.sleep(int32(milsecs))
|
|
- else:
|
|
+ elif defined(posix):
|
|
var a, b: Timespec
|
|
a.tv_sec = posix.Time(milsecs div 1000)
|
|
a.tv_nsec = (milsecs mod 1000) * 1000 * 1000
|
|
discard posix.nanosleep(a, b)
|
|
+ elif defined(genode):
|
|
+ raise newException(Defect, "blocking sleep not available on Genode")
|
|
+ else:
|
|
+ {.error: "sleep not ported to your operating system!".}
|
|
|
|
proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
|
|
tags: [ReadIOEffect], noWeirdTarget.} =
|
|
@@ -3266,14 +3272,14 @@ when defined(windows) or weirdTarget:
|
|
type
|
|
DeviceId* = int32
|
|
FileId* = int64
|
|
-elif fileSystemMissing:
|
|
- type
|
|
- DeviceId* = int
|
|
- FileId* = int
|
|
-else:
|
|
+elif defined(posix):
|
|
type
|
|
DeviceId* = Dev
|
|
FileId* = Ino
|
|
+else:
|
|
+ type
|
|
+ DeviceId* = int
|
|
+ FileId* = int
|
|
|
|
type
|
|
FileInfo* = object
|
|
@@ -3516,6 +3522,8 @@ proc getCurrentProcessId*(): int {.noWeirdTarget.} =
|
|
proc GetCurrentProcessId(): DWORD {.stdcall, dynlib: "kernel32",
|
|
importc: "GetCurrentProcessId".}
|
|
result = GetCurrentProcessId().int
|
|
+ elif defined(genode): # non-POSIX
|
|
+ discard
|
|
else:
|
|
result = getpid()
|
|
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From df882bfdc80e35a09c6e5c8517eda9d54e91a0c4 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Tue, 11 Oct 2022 14:31:21 -0500
|
|
Subject: [PATCH 5/8] Genode native modules
|
|
|
|
---
|
|
lib/genode/entrypoints.nim | 10 ++++
|
|
lib/genode/rtc.nim | 4 +-
|
|
lib/genode/signals.nim | 93 ++++++++++++++++++++++++++++++++++++++
|
|
lib/genode/timers.nim | 13 ++++++
|
|
lib/pure/times.nim | 2 +-
|
|
5 files changed, 119 insertions(+), 3 deletions(-)
|
|
create mode 100644 lib/genode/entrypoints.nim
|
|
create mode 100644 lib/genode/signals.nim
|
|
create mode 100644 lib/genode/timers.nim
|
|
|
|
diff --git a/lib/genode/entrypoints.nim b/lib/genode/entrypoints.nim
|
|
new file mode 100644
|
|
index 000000000..360aa274d
|
|
--- /dev/null
|
|
+++ b/lib/genode/entrypoints.nim
|
|
@@ -0,0 +1,10 @@
|
|
+type
|
|
+ EntrypointObj {.
|
|
+ importcpp: "Genode::Entrypoint",
|
|
+ header: "<base/entrypoint.h>",
|
|
+ pure.} = object
|
|
+ Entrypoint* = ptr EntrypointObj
|
|
+ ## Opaque Entrypoint object.
|
|
+
|
|
+proc ep*(env: GenodeEnvPtr): Entrypoint {.
|
|
+ importcpp: "(&#->ep())".}
|
|
diff --git a/lib/genode/rtc.nim b/lib/genode/rtc.nim
|
|
index d2f03454f..00a13049b 100644
|
|
--- a/lib/genode/rtc.nim
|
|
+++ b/lib/genode/rtc.nim
|
|
@@ -1,4 +1,4 @@
|
|
-import ./env, ./constructibles
|
|
+import ./constructibles
|
|
|
|
const rtcHeader = "<rtc_session/connection.h>"
|
|
|
|
@@ -9,7 +9,7 @@ type
|
|
Timestamp* {.importcpp: "Rtc::Timestamp", header: rtcHeader.} = object
|
|
microsecond*, second*, minute*, hour*, day*, month*, year*: cuint
|
|
|
|
-proc construct(c: Connection; env: GenodeEnvPtr; label: cstring) {.
|
|
+proc construct(c: Connection; env: GenodeEnv; label: cstring) {.
|
|
importcpp: "#.construct(*#, @)", tags: [IOEffect].}
|
|
|
|
proc timestamp*(c: Connection): Timestamp {.
|
|
diff --git a/lib/genode/signals.nim b/lib/genode/signals.nim
|
|
new file mode 100644
|
|
index 000000000..0e59db59c
|
|
--- /dev/null
|
|
+++ b/lib/genode/signals.nim
|
|
@@ -0,0 +1,93 @@
|
|
+import ./entrypoints, ./constructibles
|
|
+
|
|
+type SignalContextCapability* {.
|
|
+ importcpp: "Genode::Signal_context_capability",
|
|
+ header: "<base/signal.h>", pure.} = object
|
|
+ ## Capability to an asynchronous signal context.
|
|
+
|
|
+proc isValid*(cap: SignalContextCapability): bool {.
|
|
+ importcpp: "#.valid()", tags: [IOEffect].}
|
|
+
|
|
+{.emit: """
|
|
+#include <libc/component.h>
|
|
+#include <base/signal.h>
|
|
+#include <util/reconstructible.h>
|
|
+
|
|
+/* Symbol for calling back into Nim */
|
|
+extern "C" void nimHandleSignal(void *arg);
|
|
+
|
|
+namespace Nim { struct SignalDispatcher; }
|
|
+
|
|
+struct Nim::SignalDispatcher
|
|
+{
|
|
+ /**
|
|
+ * Pointer to a Nim type
|
|
+ */
|
|
+ void *arg;
|
|
+
|
|
+ /**
|
|
+ * Call Nim with dispatcher argument
|
|
+ */
|
|
+ void handle_signal() {
|
|
+ Libc::with_libc([this] () { nimHandleSignal(arg); }); }
|
|
+
|
|
+ Genode::Signal_handler<SignalDispatcher> handler;
|
|
+
|
|
+ SignalDispatcher(Genode::Entrypoint *ep, void *arg)
|
|
+ : arg(arg), handler(*ep, *this, &SignalDispatcher::handle_signal) { }
|
|
+
|
|
+ Genode::Signal_context_capability cap() {
|
|
+ return handler; }
|
|
+};
|
|
+
|
|
+""".}
|
|
+
|
|
+
|
|
+type
|
|
+ HandlerProc = proc () {.closure, gcsafe.}
|
|
+
|
|
+ SignalDispatcherBase {.
|
|
+ importcpp: "Nim::SignalDispatcher", pure.} = object
|
|
+
|
|
+ SignalDispatcherCpp = Constructible[SignalDispatcherBase]
|
|
+
|
|
+ SignalDispatcherObj = object
|
|
+ cpp: SignalDispatcherCpp
|
|
+ cb: HandlerProc
|
|
+ ## Signal handling procedure called during dispatch.
|
|
+
|
|
+ SignalHandler* = ref SignalDispatcherObj
|
|
+ ## Nim object enclosing a Genode signal handler.
|
|
+
|
|
+{.deprecated: [SignalDispatcher: SignalHandler].}
|
|
+
|
|
+proc construct(cpp: SignalDispatcherCpp; ep: Entrypoint; sh: SignalHandler) {.importcpp.}
|
|
+
|
|
+proc cap(cpp: SignalDispatcherCpp): SignalContextCapability {.
|
|
+ importcpp: "#->cap()".}
|
|
+
|
|
+proc newSignalHandler*(ep: Entrypoint; cb: HandlerProc): SignalHandler =
|
|
+ ## Create a new signal handler. A label is recommended for
|
|
+ ## debugging purposes. A signal handler will not be garbage
|
|
+ ## collected until after it has been dissolved.
|
|
+ assert(not cb.isNil)
|
|
+ result = SignalHandler(cb: cb)
|
|
+ result.cpp.construct(ep, result)
|
|
+ GCref result
|
|
+ assert(not result.cb.isNil)
|
|
+
|
|
+proc dissolve*(sig: SignalHandler) =
|
|
+ ## Dissolve signal dispatcher from entrypoint.
|
|
+ destruct sig.cpp
|
|
+ GCunref sig
|
|
+
|
|
+proc cap*(sig: SignalHandler): SignalContextCapability =
|
|
+ ## Signal context capability. Can be delegated to external components.
|
|
+ assert(not sig.cb.isNil)
|
|
+ sig.cpp.cap
|
|
+
|
|
+proc nimHandleSignal(p: pointer) {.exportc.} =
|
|
+ ## C symbol invoked by entrypoint during signal dispatch.
|
|
+ let dispatch = cast[SignalDispatcher](p)
|
|
+ doAssert(not dispatch.cb.isNil)
|
|
+ dispatch.cb()
|
|
diff --git a/lib/genode/timers.nim b/lib/genode/timers.nim
|
|
new file mode 100644
|
|
index 000000000..d74643dde
|
|
--- /dev/null
|
|
+++ b/lib/genode/timers.nim
|
|
@@ -0,0 +1,13 @@
|
|
+import ./constructibles, ./signals
|
|
+
|
|
+const timerHeader = "<timer_session/connection.h>"
|
|
+
|
|
+type
|
|
+ ConnectionBase {.importcpp: "Timer::Connection", header: timerHeader.} = object
|
|
+ TimerConnection* = Constructible[ConnectionBase]
|
|
+
|
|
+proc construct*(conn: TimerConnection; env: GenodeEnvPtr; label: cstring) {.
|
|
+ importcpp: "#.construct(*#, @)", tags: [IOEffect].}
|
|
+
|
|
+proc sigh*(conn: TimerConnection; sigCap: SignalContextCapability) {.
|
|
+ importcpp: "#->sigh(#)", tags: [IOEffect].}
|
|
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
|
|
index a18c9be4f..33074cf0c 100644
|
|
--- a/lib/pure/times.nim
|
|
+++ b/lib/pure/times.nim
|
|
@@ -254,7 +254,7 @@ elif defined(windows):
|
|
|
|
elif defined(genode):
|
|
# Genode without POSIX
|
|
- import ../genode/[env, rtc]
|
|
+ import ../genode/rtc
|
|
var rtcConn = initRtcConnection(runtimeEnv, "times")
|
|
|
|
type
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From 8a6ded41fffe06befdd7236b8c87ebb770172239 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Wed, 12 Oct 2022 16:35:57 -0500
|
|
Subject: [PATCH 6/8] asyncdispatch: milliseconds to Duration
|
|
|
|
Use the Duration type to avoid mismatches with schedulers that use
|
|
units of time other than the millisecond.
|
|
---
|
|
lib/pure/asyncdispatch.nim | 70 ++++++++++++++++++++++----------------
|
|
1 file changed, 40 insertions(+), 30 deletions(-)
|
|
|
|
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
|
|
index 04dbf4e4a..3d0e374ff 100644
|
|
--- a/lib/pure/asyncdispatch.nim
|
|
+++ b/lib/pure/asyncdispatch.nim
|
|
@@ -213,7 +213,7 @@ type
|
|
|
|
proc processTimers(
|
|
p: PDispatcherBase, didSomeWork: var bool
|
|
-): Option[int] {.inline.} =
|
|
+): Option[Duration] {.inline.} =
|
|
# Pop the timers in the order in which they will expire (smaller `finishAt`).
|
|
var count = p.timers.len
|
|
let t = getMonoTime()
|
|
@@ -222,11 +222,11 @@ proc processTimers(
|
|
dec count
|
|
didSomeWork = true
|
|
|
|
- # Return the number of milliseconds in which the next timer will expire.
|
|
+ # Return the duration in which the next timer will expire.
|
|
if p.timers.len == 0: return
|
|
|
|
- let millisecs = (p.timers[0].finishAt - getMonoTime()).inMilliseconds
|
|
- return some(millisecs.int + 1)
|
|
+ let timeout = p.timers[0].finishAt - getMonoTime()
|
|
+ return some(timeout)
|
|
|
|
proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) =
|
|
while p.callbacks.len > 0:
|
|
@@ -235,16 +235,17 @@ proc processPendingCallbacks(p: PDispatcherBase; didSomeWork: var bool) =
|
|
didSomeWork = true
|
|
|
|
proc adjustTimeout(
|
|
- p: PDispatcherBase, pollTimeout: int, nextTimer: Option[int]
|
|
-): int {.inline.} =
|
|
- if p.callbacks.len != 0:
|
|
- return 0
|
|
+ p: PDispatcherBase, pollTimeout: Duration, nextTimer: Option[Duration]
|
|
+): Duration {.inline.} =
|
|
+ if p.callbacks.len == 0:
|
|
+ if nextTimer.isNone() or pollTimeout < result:
|
|
+ return pollTimeout
|
|
|
|
- if nextTimer.isNone() or pollTimeout == -1:
|
|
- return pollTimeout
|
|
+ result = max(nextTimer.get(), Duration())
|
|
+ result = min(pollTimeout, result)
|
|
|
|
- result = max(nextTimer.get(), 0)
|
|
- result = min(pollTimeout, result)
|
|
+proc roundToMilliseconds(dur: Duration): int64 {.used.} =
|
|
+ inMilliseconds(dur + initDuration(microseconds = 500))
|
|
|
|
proc callSoon*(cbproc: proc () {.gcsafe.}) {.gcsafe.}
|
|
## Schedule `cbproc` to be called as soon as possible.
|
|
@@ -355,7 +356,7 @@ when defined(windows) or defined(nimdoc):
|
|
let p = getGlobalDispatcher()
|
|
p.handles.len != 0 or p.timers.len != 0 or p.callbacks.len != 0
|
|
|
|
- proc runOnce(timeout = 500): bool =
|
|
+ proc runOnce(timeout: Duration): bool =
|
|
let p = getGlobalDispatcher()
|
|
if p.handles.len == 0 and p.timers.len == 0 and p.callbacks.len == 0:
|
|
raise newException(ValueError,
|
|
@@ -365,8 +366,8 @@ when defined(windows) or defined(nimdoc):
|
|
let nextTimer = processTimers(p, result)
|
|
let at = adjustTimeout(p, timeout, nextTimer)
|
|
var llTimeout =
|
|
- if at == -1: winlean.INFINITE
|
|
- else: at.int32
|
|
+ if at < Duration(): winlean.INFINITE
|
|
+ else: at.roundToMilliseconds.int32
|
|
|
|
var lpNumberOfBytesTransferred: DWORD
|
|
var lpCompletionKey: ULONG_PTR
|
|
@@ -1337,7 +1338,7 @@ else:
|
|
)
|
|
|
|
|
|
- proc runOnce(timeout = 500): bool =
|
|
+ proc runOnce(timeout: Duration): bool =
|
|
let p = getGlobalDispatcher()
|
|
if p.selector.isEmpty() and p.timers.len == 0 and p.callbacks.len == 0:
|
|
raise newException(ValueError,
|
|
@@ -1347,7 +1348,7 @@ else:
|
|
var keys: array[64, ReadyKey]
|
|
let nextTimer = processTimers(p, result)
|
|
var count =
|
|
- p.selector.selectInto(adjustTimeout(p, timeout, nextTimer), keys)
|
|
+ p.selector.selectInto(adjustTimeout(p, timeout, nextTimer).roundToMilliseconds.int, keys)
|
|
for i in 0..<count:
|
|
let fd = keys[i].fd.AsyncFD
|
|
let events = keys[i].events
|
|
@@ -1634,7 +1635,7 @@ else:
|
|
data.readList.add(cb)
|
|
p.selector.registerEvent(SelectEvent(ev), data)
|
|
|
|
-proc drain*(timeout = 500) =
|
|
+proc drain*(timeout: Duration) =
|
|
## Waits for completion of **all** events and processes them. Raises `ValueError`
|
|
## if there are no pending operations. In contrast to `poll` this
|
|
## processes as many events as are available until the timeout has elapsed.
|
|
@@ -1642,16 +1643,20 @@ proc drain*(timeout = 500) =
|
|
let start = now()
|
|
while hasPendingOperations():
|
|
discard runOnce(curTimeout)
|
|
- curTimeout -= (now() - start).inMilliseconds.int
|
|
- if curTimeout < 0:
|
|
+ curTimeout -= now() - start
|
|
+ if curTimeout < Duration():
|
|
break
|
|
|
|
-proc poll*(timeout = 500) =
|
|
+proc drain*(timeoutMs = 500) {.inline.} = drain(initDuration(milliseconds = timeoutMs))
|
|
+
|
|
+proc poll*(timeout: Duration) =
|
|
## Waits for completion events and processes them. Raises `ValueError`
|
|
## if there are no pending operations. This runs the underlying OS
|
|
## `epoll`:idx: or `kqueue`:idx: primitive only once.
|
|
discard runOnce(timeout)
|
|
|
|
+proc poll*(timeoutMs = 500) {.inline.} = poll(initDuration(milliseconds = timeoutMs))
|
|
+
|
|
template createAsyncNativeSocketImpl(domain, sockType, protocol: untyped,
|
|
inheritable = defined(nimInheritHandles)) =
|
|
let handle = createNativeSocket(domain, sockType, protocol, inheritable)
|
|
@@ -1856,19 +1861,24 @@ proc connect*(socket: AsyncFD, address: string, port: Port,
|
|
socket.SocketHandle.bindToDomain(domain)
|
|
asyncAddrInfoLoop(aiList, socket)
|
|
|
|
-proc sleepAsync*(ms: int | float): owned(Future[void]) =
|
|
- ## Suspends the execution of the current async procedure for the next
|
|
- ## `ms` milliseconds.
|
|
+proc sleepAsync*(timeout: Duration): owned(Future[void]) =
|
|
+ ## Suspends the execution of the current async procedure for the given
|
|
+ ## duration.
|
|
var retFuture = newFuture[void]("sleepAsync")
|
|
let p = getGlobalDispatcher()
|
|
+ let deadline: Monotime = getMonoTime() + timeout
|
|
+ p.timers.push((deadline, retFuture))
|
|
+ return retFuture
|
|
+
|
|
+proc sleepAsync*(ms: int | float): owned(Future[void]) {.inline.} =
|
|
+ ## Suspends the execution of the current async procedure for the next
|
|
+ ## `ms` milliseconds.
|
|
when ms is int:
|
|
- p.timers.push((getMonoTime() + initDuration(milliseconds = ms), retFuture))
|
|
+ sleepAsync(initDuration(milliseconds = ms))
|
|
elif ms is float:
|
|
- let ns = (ms * 1_000_000).int64
|
|
- p.timers.push((getMonoTime() + initDuration(nanoseconds = ns), retFuture))
|
|
- return retFuture
|
|
+ sleepAsync(initDuration(nanoseconds = (ms * 1_000_000).int64))
|
|
|
|
-proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) =
|
|
+proc withTimeout*[T](fut: Future[T], timeoutMs: int): owned(Future[bool]) =
|
|
## Returns a future which will complete once `fut` completes or after
|
|
## `timeout` milliseconds has elapsed.
|
|
##
|
|
@@ -1877,7 +1887,7 @@ proc withTimeout*[T](fut: Future[T], timeout: int): owned(Future[bool]) =
|
|
## future will hold false.
|
|
|
|
var retFuture = newFuture[bool]("asyncdispatch.`withTimeout`")
|
|
- var timeoutFuture = sleepAsync(timeout)
|
|
+ var timeoutFuture = sleepAsync(initDuration(milliseconds = timeoutMs))
|
|
fut.callback =
|
|
proc () =
|
|
if not retFuture.finished:
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From dd9fea0775173ccc35c093bb307e18141ec93f45 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Wed, 12 Oct 2022 15:42:31 -0500
|
|
Subject: [PATCH 7/8] Genode: native (non-POSIX) asyndispatch
|
|
|
|
---
|
|
lib/genode/entrypoints.nim | 4 +
|
|
lib/genode/timers.nim | 21 +++
|
|
lib/genode_cpp/timeouts.h | 44 +++++
|
|
lib/pure/asyncdispatch.nim | 366 ++++++++++++++++++++++---------------
|
|
lib/pure/selectors.nim | 1 +
|
|
5 files changed, 292 insertions(+), 144 deletions(-)
|
|
create mode 100644 lib/genode_cpp/timeouts.h
|
|
|
|
diff --git a/lib/genode/entrypoints.nim b/lib/genode/entrypoints.nim
|
|
index 360aa274d..cdd90d083 100644
|
|
--- a/lib/genode/entrypoints.nim
|
|
+++ b/lib/genode/entrypoints.nim
|
|
@@ -8,3 +8,7 @@ type
|
|
|
|
proc ep*(env: GenodeEnvPtr): Entrypoint {.
|
|
importcpp: "(&#->ep())".}
|
|
+
|
|
+proc wait_and_dispatch_one_io_signal*(ep: Entrypoint) {.importcpp.}
|
|
+
|
|
+proc dispatch_pending_io_signal*(ep: Entrypoint): bool {.importcpp.}
|
|
diff --git a/lib/genode/timers.nim b/lib/genode/timers.nim
|
|
index d74643dde..0922a4d2b 100644
|
|
--- a/lib/genode/timers.nim
|
|
+++ b/lib/genode/timers.nim
|
|
@@ -1,4 +1,5 @@
|
|
import ./constructibles, ./signals
|
|
+from times import Duration
|
|
|
|
const timerHeader = "<timer_session/connection.h>"
|
|
|
|
@@ -11,3 +12,23 @@ proc construct*(conn: TimerConnection; env: GenodeEnvPtr; label: cstring) {.
|
|
|
|
proc sigh*(conn: TimerConnection; sigCap: SignalContextCapability) {.
|
|
importcpp: "#->sigh(#)", tags: [IOEffect].}
|
|
+
|
|
+type
|
|
+ TimeoutCallback*[T] = proc (state: T; us: uint64) {.cdecl.}
|
|
+ ## Callback type that accepts at state parameter and the elapsed timout duration in microseconds.
|
|
+ TimeoutHandler*[T] {.
|
|
+ importcpp: "Nim::Constructible_timeout_handler<T>",
|
|
+ header: "genode_cpp/timeouts.h"
|
|
+ .} = object
|
|
+
|
|
+proc construct*[T](handler: TimeoutHandler[T]; timer: TimerConnection; state: T; cb: TimeoutCallback) {.
|
|
+ importcpp: "#.construct(*#, @)".}
|
|
+ ## Construct a `TimeoutHandler` with a `TimerConnection` and a callback.
|
|
+
|
|
+proc schedule_us[T](handler: TimeoutHandler[T]; timeout: uint64) {.importcpp.}
|
|
+
|
|
+proc schedule*[T](handler: TimeoutHandler[T]; timeout: Duration) {.inline.} =
|
|
+ ## Schedule the handler to be invoked after a timeout.
|
|
+ let us = timeout.inMicroseconds
|
|
+ assert(us > 0, "Timeout cannot be less than 1 µs")
|
|
+ schedule_us(handler, uint64 us)
|
|
diff --git a/lib/genode_cpp/timeouts.h b/lib/genode_cpp/timeouts.h
|
|
new file mode 100644
|
|
index 000000000..1af4ca48d
|
|
--- /dev/null
|
|
+++ b/lib/genode_cpp/timeouts.h
|
|
@@ -0,0 +1,44 @@
|
|
+/*
|
|
+ *
|
|
+ * Nim's Runtime Library
|
|
+ * (c) Copyright 2022 Emery Hemingway
|
|
+ *
|
|
+ * See the file "copying.txt", included in this
|
|
+ * distribution, for details about the copyright.
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _GENODE_CPP__TIMEOUTS_H_
|
|
+#define _GENODE_CPP__TIMEOUTS_H_
|
|
+
|
|
+/* Genode includes */
|
|
+#include <timer_session/connection.h>
|
|
+
|
|
+namespace Nim {
|
|
+
|
|
+ /**
|
|
+ * Class for calling a Nim callback from a Genode timer.
|
|
+ */
|
|
+ template <typename STATE>
|
|
+ struct Timeout_handler
|
|
+ {
|
|
+ Timer::One_shot_timeout<Timeout_handler> _timeout;
|
|
+ STATE _state;
|
|
+ void(*)(STATE, uint64_t) _callback;
|
|
+
|
|
+ Timeout_handler(Timer::Connection *timer, STATE _state, void(*callback)(STATE, uint64_t))
|
|
+ : _timeout(*timer, *this, &Timeout_handler::_handle_timeout)
|
|
+ , _state(state), _callback(callback)
|
|
+ { }
|
|
+
|
|
+ void _handle_timeout(Duration dur) { _callback(_state, dur.trunc_to_plain_us().value); }
|
|
+
|
|
+ void schedule_us(uint64_t us) { schedule(Duration(Microseconds(us))); }
|
|
+ };
|
|
+
|
|
+ template <typename STATE>
|
|
+ typedef Constructible<Nim::Timeout_handler<STATE>> Nim::Constructible_timeout_handler
|
|
+
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
|
|
index 3d0e374ff..2e1d7b4f8 100644
|
|
--- a/lib/pure/asyncdispatch.nim
|
|
+++ b/lib/pure/asyncdispatch.nim
|
|
@@ -194,13 +194,18 @@
|
|
## ``none`` can be used when a library supports both a synchronous and
|
|
## asynchronous API, to disable the latter.
|
|
|
|
-import os, tables, strutils, times, heapqueue, options, asyncstreams
|
|
+import os, tables, strutils, times, heapqueue, options, asyncstreams, deques
|
|
import options, math, std/monotimes
|
|
import asyncfutures except callSoon
|
|
|
|
-import nativesockets, net, deques
|
|
+const socketsMissing = defined(genode) and not defined(posix)
|
|
+when not socketsMissing:
|
|
+ import nativesockets, net
|
|
+
|
|
+when not socketsMissing:
|
|
+ export Port, SocketFlag
|
|
+
|
|
|
|
-export Port, SocketFlag
|
|
export asyncfutures except callSoon
|
|
export asyncstreams
|
|
|
|
@@ -1129,6 +1134,75 @@ when defined(windows) or defined(nimdoc):
|
|
ev.hWaiter = pcd.waitFd
|
|
|
|
initAll()
|
|
+elif defined(genode) and not defined(posix):
|
|
+ import genode/[entrypoints, timers]
|
|
+ type PDispatcher* = ref object of PDispatcherBase
|
|
+ timer: TimerConnection
|
|
+ timeoutHandler: TimeoutHandler[PDispatcher]
|
|
+ progress: bool
|
|
+
|
|
+ proc asyncdispatch_timeout_callback(disp: PDispatcher; us: uint64) {.cdecl.} =
|
|
+ let nextTimer = processTimers(disp, disp.progress)
|
|
+ if nextTimer.isSome:
|
|
+ disp.timeoutHandler.schedule(get(nextTimer))
|
|
+ processPendingCallbacks(disp, disp.progress)
|
|
+
|
|
+ var gDisp: owned PDispatcher ## Global dispatcher
|
|
+
|
|
+ proc getGlobalDispatcher*(): PDispatcher =
|
|
+ if gDisp.isNil:
|
|
+ new gDisp
|
|
+ construct(gDisp.timer, runtimeEnv, "asyncdispatch")
|
|
+ construct(gDisp.timeoutHandler, gDisp.timer, gDisp, asyncdispatch_timeout_callback)
|
|
+ gDisp
|
|
+
|
|
+ proc hasPendingOperations*(): bool =
|
|
+ var p = getGlobalDispatcher()
|
|
+ p.timers.len != 0 or p.callbacks.len != 0
|
|
+
|
|
+ proc runOnce(timeout: Duration): bool =
|
|
+ var disp = getGlobalDispatcher()
|
|
+ if disp.timers.len == 0 and disp.callbacks.len == 0:
|
|
+ raise newException(Defect, "No timers registered in dispatcher.")
|
|
+ let nextTimeout = processTimers(disp, result)
|
|
+ processPendingCallbacks(disp, result)
|
|
+ if nextTimeout.isSome:
|
|
+ if result:
|
|
+ # schedule the next pending timer
|
|
+ disp.timeoutHandler.schedule(get nextTimeout)
|
|
+ else:
|
|
+ # schedule the next pender timer or timeout, whichever is earlier
|
|
+ disp.timeoutHandler.schedule(min(timeout, get nextTimeout))
|
|
+ elif not result:
|
|
+ # schedule the run timeout and dispatch I/O signals until something happens
|
|
+ disp.timeoutHandler.schedule(timeout)
|
|
+ let ioDeadline = getMonoTime() + timeout
|
|
+ disp.progress = false
|
|
+ while true:
|
|
+ runtimeEnv.ep.wait_and_dispatch_one_io_signal()
|
|
+ # wait for asyncdispatch_timeout_callback to be trigger by a signal
|
|
+ if disp.progress or getMonoTime() >= ioDeadline:
|
|
+ result = disp.progress
|
|
+ break
|
|
+
|
|
+ proc runOnce(timeout: int): bool {.inline} = runOnce(initDuration(milliseconds = timeout))
|
|
+
|
|
+ proc addTimer*(timeout: Duration, oneshot: bool, cb: proc() {.gcsafe.}) =
|
|
+ var
|
|
+ disp = getGlobalDispatcher()
|
|
+ fut = newFuture[void]("addTimer")
|
|
+ if oneshot:
|
|
+ fut.addCallback(cb)
|
|
+ else:
|
|
+ fut.addCallback:
|
|
+ cb()
|
|
+ addTimer(timeout, oneshot, cb)
|
|
+ # TODO: reuse the future?
|
|
+ disp.timers.push((getMonoTime() + timeout, fut))
|
|
+
|
|
+ proc addTimer*(timeout: int, oneshot: bool, cb: proc() {.gcsafe.}) {.inline.} =
|
|
+ addTimer(initDuration(milliseconds = timeout), oneshot, cb)
|
|
+
|
|
else:
|
|
import selectors
|
|
from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK,
|
|
@@ -1668,16 +1742,17 @@ template createAsyncNativeSocketImpl(domain, sockType, protocol: untyped,
|
|
result = handle.AsyncFD
|
|
register(result)
|
|
|
|
-proc createAsyncNativeSocket*(domain: cint, sockType: cint,
|
|
- protocol: cint,
|
|
- inheritable = defined(nimInheritHandles)): AsyncFD =
|
|
- createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
|
|
+when not socketsMissing:
|
|
+ proc createAsyncNativeSocket*(domain: cint, sockType: cint,
|
|
+ protocol: cint,
|
|
+ inheritable = defined(nimInheritHandles)): AsyncFD =
|
|
+ createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
|
|
|
|
-proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
|
|
- sockType: SockType = SOCK_STREAM,
|
|
- protocol: Protocol = IPPROTO_TCP,
|
|
- inheritable = defined(nimInheritHandles)): AsyncFD =
|
|
- createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
|
|
+ proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
|
|
+ sockType: SockType = SOCK_STREAM,
|
|
+ protocol: Protocol = IPPROTO_TCP,
|
|
+ inheritable = defined(nimInheritHandles)): AsyncFD =
|
|
+ createAsyncNativeSocketImpl(domain, sockType, protocol, inheritable)
|
|
|
|
when defined(windows) or defined(nimdoc):
|
|
proc bindToDomain(handle: SocketHandle, domain: Domain) =
|
|
@@ -1727,7 +1802,7 @@ when defined(windows) or defined(nimdoc):
|
|
# and the future will be completed/failed there, too.
|
|
GC_unref(ol)
|
|
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
|
-else:
|
|
+elif not socketsMissing:
|
|
proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): owned(Future[void]) =
|
|
let retFuture = newFuture[void]("doConnect")
|
|
result = retFuture
|
|
@@ -1759,107 +1834,108 @@ else:
|
|
else:
|
|
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
|
|
|
-template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
|
|
- protocol: Protocol = IPPROTO_RAW) =
|
|
- ## Iterates through the AddrInfo linked list asynchronously
|
|
- ## until the connection can be established.
|
|
- const shouldCreateFd = not declared(fd)
|
|
-
|
|
- when shouldCreateFd:
|
|
- let sockType = protocol.toSockType()
|
|
+when not socketsMissing:
|
|
+ template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
|
|
+ protocol: Protocol = IPPROTO_RAW) =
|
|
+ ## Iterates through the AddrInfo linked list asynchronously
|
|
+ ## until the connection can be established.
|
|
+ const shouldCreateFd = not declared(fd)
|
|
+
|
|
+ when shouldCreateFd:
|
|
+ let sockType = protocol.toSockType()
|
|
+
|
|
+ var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD]
|
|
+ for i in low(fdPerDomain)..high(fdPerDomain):
|
|
+ fdPerDomain[i] = osInvalidSocket.AsyncFD
|
|
+ template closeUnusedFds(domainToKeep = -1) {.dirty.} =
|
|
+ for i, fd in fdPerDomain:
|
|
+ if fd != osInvalidSocket.AsyncFD and i != domainToKeep:
|
|
+ fd.closeSocket()
|
|
+
|
|
+ var lastException: ref Exception
|
|
+ var curAddrInfo = addrInfo
|
|
+ var domain: Domain
|
|
+ when shouldCreateFd:
|
|
+ var curFd: AsyncFD
|
|
+ else:
|
|
+ var curFd = fd
|
|
+ proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} =
|
|
+ if fut == nil or fut.failed:
|
|
+ if fut != nil:
|
|
+ lastException = fut.readError()
|
|
+
|
|
+ while curAddrInfo != nil:
|
|
+ let domainOpt = curAddrInfo.ai_family.toKnownDomain()
|
|
+ if domainOpt.isSome:
|
|
+ domain = domainOpt.unsafeGet()
|
|
+ break
|
|
+ curAddrInfo = curAddrInfo.ai_next
|
|
+
|
|
+ if curAddrInfo == nil:
|
|
+ freeAddrInfo(addrInfo)
|
|
+ when shouldCreateFd:
|
|
+ closeUnusedFds()
|
|
+ if lastException != nil:
|
|
+ retFuture.fail(lastException)
|
|
+ else:
|
|
+ retFuture.fail(newException(
|
|
+ IOError, "Couldn't resolve address: " & address))
|
|
+ return
|
|
|
|
- var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD]
|
|
- for i in low(fdPerDomain)..high(fdPerDomain):
|
|
- fdPerDomain[i] = osInvalidSocket.AsyncFD
|
|
- template closeUnusedFds(domainToKeep = -1) {.dirty.} =
|
|
- for i, fd in fdPerDomain:
|
|
- if fd != osInvalidSocket.AsyncFD and i != domainToKeep:
|
|
- fd.closeSocket()
|
|
-
|
|
- var lastException: ref Exception
|
|
- var curAddrInfo = addrInfo
|
|
- var domain: Domain
|
|
- when shouldCreateFd:
|
|
- var curFd: AsyncFD
|
|
- else:
|
|
- var curFd = fd
|
|
- proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} =
|
|
- if fut == nil or fut.failed:
|
|
- if fut != nil:
|
|
- lastException = fut.readError()
|
|
-
|
|
- while curAddrInfo != nil:
|
|
- let domainOpt = curAddrInfo.ai_family.toKnownDomain()
|
|
- if domainOpt.isSome:
|
|
- domain = domainOpt.unsafeGet()
|
|
- break
|
|
+ when shouldCreateFd:
|
|
+ curFd = fdPerDomain[ord(domain)]
|
|
+ if curFd == osInvalidSocket.AsyncFD:
|
|
+ try:
|
|
+ curFd = createAsyncNativeSocket(domain, sockType, protocol)
|
|
+ except:
|
|
+ freeAddrInfo(addrInfo)
|
|
+ closeUnusedFds()
|
|
+ raise getCurrentException()
|
|
+ when defined(windows):
|
|
+ curFd.SocketHandle.bindToDomain(domain)
|
|
+ fdPerDomain[ord(domain)] = curFd
|
|
+
|
|
+ doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo
|
|
curAddrInfo = curAddrInfo.ai_next
|
|
-
|
|
- if curAddrInfo == nil:
|
|
+ else:
|
|
freeAddrInfo(addrInfo)
|
|
when shouldCreateFd:
|
|
- closeUnusedFds()
|
|
- if lastException != nil:
|
|
- retFuture.fail(lastException)
|
|
+ closeUnusedFds(ord(domain))
|
|
+ retFuture.complete(curFd)
|
|
else:
|
|
- retFuture.fail(newException(
|
|
- IOError, "Couldn't resolve address: " & address))
|
|
- return
|
|
-
|
|
- when shouldCreateFd:
|
|
- curFd = fdPerDomain[ord(domain)]
|
|
- if curFd == osInvalidSocket.AsyncFD:
|
|
- try:
|
|
- curFd = createAsyncNativeSocket(domain, sockType, protocol)
|
|
- except:
|
|
- freeAddrInfo(addrInfo)
|
|
- closeUnusedFds()
|
|
- raise getCurrentException()
|
|
- when defined(windows):
|
|
- curFd.SocketHandle.bindToDomain(domain)
|
|
- fdPerDomain[ord(domain)] = curFd
|
|
-
|
|
- doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo
|
|
- curAddrInfo = curAddrInfo.ai_next
|
|
- else:
|
|
- freeAddrInfo(addrInfo)
|
|
- when shouldCreateFd:
|
|
- closeUnusedFds(ord(domain))
|
|
- retFuture.complete(curFd)
|
|
- else:
|
|
- retFuture.complete()
|
|
-
|
|
- tryNextAddrInfo(nil)
|
|
+ retFuture.complete()
|
|
|
|
-proc dial*(address: string, port: Port,
|
|
- protocol: Protocol = IPPROTO_TCP): owned(Future[AsyncFD]) =
|
|
- ## Establishes connection to the specified `address`:`port` pair via the
|
|
- ## specified protocol. The procedure iterates through possible
|
|
- ## resolutions of the `address` until it succeeds, meaning that it
|
|
- ## seamlessly works with both IPv4 and IPv6.
|
|
- ## Returns the async file descriptor, registered in the dispatcher of
|
|
- ## the current thread, ready to send or receive data.
|
|
- let retFuture = newFuture[AsyncFD]("dial")
|
|
- result = retFuture
|
|
- let sockType = protocol.toSockType()
|
|
+ tryNextAddrInfo(nil)
|
|
+
|
|
+ proc dial*(address: string, port: Port,
|
|
+ protocol: Protocol = IPPROTO_TCP): owned(Future[AsyncFD]) =
|
|
+ ## Establishes connection to the specified `address`:`port` pair via the
|
|
+ ## specified protocol. The procedure iterates through possible
|
|
+ ## resolutions of the `address` until it succeeds, meaning that it
|
|
+ ## seamlessly works with both IPv4 and IPv6.
|
|
+ ## Returns the async file descriptor, registered in the dispatcher of
|
|
+ ## the current thread, ready to send or receive data.
|
|
+ let retFuture = newFuture[AsyncFD]("dial")
|
|
+ result = retFuture
|
|
+ let sockType = protocol.toSockType()
|
|
|
|
- let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol)
|
|
- asyncAddrInfoLoop(aiList, noFD, protocol)
|
|
+ let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol)
|
|
+ asyncAddrInfoLoop(aiList, noFD, protocol)
|
|
|
|
-proc connect*(socket: AsyncFD, address: string, port: Port,
|
|
- domain = Domain.AF_INET): owned(Future[void]) =
|
|
- let retFuture = newFuture[void]("connect")
|
|
- result = retFuture
|
|
+ proc connect*(socket: AsyncFD, address: string, port: Port,
|
|
+ domain = Domain.AF_INET): owned(Future[void]) =
|
|
+ let retFuture = newFuture[void]("connect")
|
|
+ result = retFuture
|
|
|
|
- when defined(windows):
|
|
- verifyPresence(socket)
|
|
- else:
|
|
- assert getSockDomain(socket.SocketHandle) == domain
|
|
+ when defined(windows):
|
|
+ verifyPresence(socket)
|
|
+ else:
|
|
+ assert getSockDomain(socket.SocketHandle) == domain
|
|
|
|
- let aiList = getAddrInfo(address, port, domain)
|
|
- when defined(windows):
|
|
- socket.SocketHandle.bindToDomain(domain)
|
|
- asyncAddrInfoLoop(aiList, socket)
|
|
+ let aiList = getAddrInfo(address, port, domain)
|
|
+ when defined(windows):
|
|
+ socket.SocketHandle.bindToDomain(domain)
|
|
+ asyncAddrInfoLoop(aiList, socket)
|
|
|
|
proc sleepAsync*(timeout: Duration): owned(Future[void]) =
|
|
## Suspends the execution of the current async procedure for the given
|
|
@@ -1900,48 +1976,49 @@ proc withTimeout*[T](fut: Future[T], timeoutMs: int): owned(Future[bool]) =
|
|
if not retFuture.finished: retFuture.complete(false)
|
|
return retFuture
|
|
|
|
-proc accept*(socket: AsyncFD,
|
|
- flags = {SocketFlag.SafeDisconn},
|
|
- inheritable = defined(nimInheritHandles)): owned(Future[AsyncFD]) =
|
|
- ## Accepts a new connection. Returns a future containing the client socket
|
|
- ## corresponding to that connection.
|
|
- ##
|
|
- ## If `inheritable` is false (the default), the resulting client socket
|
|
- ## will not be inheritable by child processes.
|
|
- ##
|
|
- ## The future will complete when the connection is successfully accepted.
|
|
- var retFut = newFuture[AsyncFD]("accept")
|
|
- var fut = acceptAddr(socket, flags, inheritable)
|
|
- fut.callback =
|
|
- proc (future: Future[tuple[address: string, client: AsyncFD]]) =
|
|
- assert future.finished
|
|
- if future.failed:
|
|
- retFut.fail(future.error)
|
|
- else:
|
|
- retFut.complete(future.read.client)
|
|
- return retFut
|
|
-
|
|
-proc keepAlive(x: string) =
|
|
- discard "mark 'x' as escaping so that it is put into a closure for us to keep the data alive"
|
|
-
|
|
-proc send*(socket: AsyncFD, data: string,
|
|
- flags = {SocketFlag.SafeDisconn}): owned(Future[void]) =
|
|
- ## Sends `data` to `socket`. The returned future will complete once all
|
|
- ## data has been sent.
|
|
- var retFuture = newFuture[void]("send")
|
|
- if data.len > 0:
|
|
- let sendFut = socket.send(unsafeAddr data[0], data.len, flags)
|
|
- sendFut.callback =
|
|
- proc () =
|
|
- keepAlive(data)
|
|
- if sendFut.failed:
|
|
- retFuture.fail(sendFut.error)
|
|
+when not socketsMissing:
|
|
+ proc accept*(socket: AsyncFD,
|
|
+ flags = {SocketFlag.SafeDisconn},
|
|
+ inheritable = defined(nimInheritHandles)): owned(Future[AsyncFD]) =
|
|
+ ## Accepts a new connection. Returns a future containing the client socket
|
|
+ ## corresponding to that connection.
|
|
+ ##
|
|
+ ## If `inheritable` is false (the default), the resulting client socket
|
|
+ ## will not be inheritable by child processes.
|
|
+ ##
|
|
+ ## The future will complete when the connection is successfully accepted.
|
|
+ var retFut = newFuture[AsyncFD]("accept")
|
|
+ var fut = acceptAddr(socket, flags, inheritable)
|
|
+ fut.callback =
|
|
+ proc (future: Future[tuple[address: string, client: AsyncFD]]) =
|
|
+ assert future.finished
|
|
+ if future.failed:
|
|
+ retFut.fail(future.error)
|
|
else:
|
|
- retFuture.complete()
|
|
- else:
|
|
- retFuture.complete()
|
|
+ retFut.complete(future.read.client)
|
|
+ return retFut
|
|
|
|
- return retFuture
|
|
+ proc keepAlive(x: string) =
|
|
+ discard "mark 'x' as escaping so that it is put into a closure for us to keep the data alive"
|
|
+
|
|
+ proc send*(socket: AsyncFD, data: string,
|
|
+ flags = {SocketFlag.SafeDisconn}): owned(Future[void]) =
|
|
+ ## Sends `data` to `socket`. The returned future will complete once all
|
|
+ ## data has been sent.
|
|
+ var retFuture = newFuture[void]("send")
|
|
+ if data.len > 0:
|
|
+ let sendFut = socket.send(unsafeAddr data[0], data.len, flags)
|
|
+ sendFut.callback =
|
|
+ proc () =
|
|
+ keepAlive(data)
|
|
+ if sendFut.failed:
|
|
+ retFuture.fail(sendFut.error)
|
|
+ else:
|
|
+ retFuture.complete()
|
|
+ else:
|
|
+ retFuture.complete()
|
|
+
|
|
+ return retFuture
|
|
|
|
# -- Await Macro
|
|
include asyncmacro
|
|
@@ -1977,6 +2054,7 @@ proc activeDescriptors*(): int {.inline.} =
|
|
## event loop. This is a cheap operation that does not involve a system call.
|
|
when defined(windows):
|
|
result = getGlobalDispatcher().handles.len
|
|
+ elif defined(genode): -1
|
|
elif not defined(nimdoc):
|
|
result = getGlobalDispatcher().selector.count
|
|
|
|
diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim
|
|
index 21bef9187..b1edff636 100644
|
|
--- a/lib/pure/selectors.nim
|
|
+++ b/lib/pure/selectors.nim
|
|
@@ -350,6 +350,7 @@ elif not defined(nimNoLibc):
|
|
elif defined(solaris):
|
|
include ioselects/ioselectors_poll # need to replace it with event ports
|
|
elif defined(genode):
|
|
+ when not defined(posix): {.error: "do not import this module without POSIX support".}
|
|
include ioselects/ioselectors_select # TODO: use the native VFS layer
|
|
elif defined(nintendoswitch):
|
|
include ioselects/ioselectors_select
|
|
--
|
|
2.37.2
|
|
|
|
|
|
From 0e45ef5201ba41bfa971d28f859ad7efcdd58549 Mon Sep 17 00:00:00 2001
|
|
From: Emery Hemingway <ehmry@posteo.net>
|
|
Date: Wed, 12 Oct 2022 18:49:08 -0500
|
|
Subject: [PATCH 8/8] Genode: do no enter libc when posix not defined
|
|
|
|
---
|
|
compiler/ccgexprs.nim | 2 +-
|
|
compiler/cgen.nim | 23 ++++++++++++++++++++---
|
|
2 files changed, 21 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
|
|
index d6057fcfb..cb90c8e85 100644
|
|
--- a/compiler/ccgexprs.nim
|
|
+++ b/compiler/ccgexprs.nim
|
|
@@ -1155,7 +1155,7 @@ proc genEcho(p: BProc, n: PNode) =
|
|
# this unusual way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
|
# is threadsafe.
|
|
internalAssert p.config, n.kind == nkBracket
|
|
- if p.config.target.targetOS == osGenode:
|
|
+ if p.config.target.targetOS == osGenode and not p.config.isDefined("posix"):
|
|
# echo directly to the Genode LOG session
|
|
var args: Rope = nil
|
|
var a: TLoc
|
|
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
|
|
index 03999db62..03dbaa30b 100644
|
|
--- a/compiler/cgen.nim
|
|
+++ b/compiler/cgen.nim
|
|
@@ -1464,6 +1464,16 @@ proc genMainProc(m: BModule) =
|
|
NimMainBody
|
|
|
|
ComponentConstruct =
|
|
+ "void Component::construct(Genode::Env &env) {$N" &
|
|
+ "\t// Set Env used during runtime initialization$N" &
|
|
+ "\tnim_runtime_env = &env;$N" &
|
|
+ "\t// Initialize runtime and globals$N" &
|
|
+ MainProcs &
|
|
+ "\t// Call application construct$N" &
|
|
+ "\tnim_component_construct(&env);$N" &
|
|
+ "}$N$N"
|
|
+
|
|
+ LibcComponentConstruct =
|
|
"void Libc::Component::construct(Libc::Env &env) {$N" &
|
|
"\t// Set Env used during runtime initialization$N" &
|
|
"\tnim_runtime_env = &env;$N" &
|
|
@@ -1479,7 +1489,10 @@ proc genMainProc(m: BModule) =
|
|
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
|
m.includeHeader("<windows.h>")
|
|
elif m.config.target.targetOS == osGenode:
|
|
- m.includeHeader("<libc/component.h>")
|
|
+ if m.config.isDefined("posix"):
|
|
+ m.includeHeader("<libc/component.h>")
|
|
+ else:
|
|
+ m.includeHeader("<base/component.h>")
|
|
|
|
let initStackBottomCall =
|
|
if m.config.target.targetOS == osStandalone or m.config.selectedGC in {gcNone, gcArc, gcOrc}: "".rope
|
|
@@ -1535,8 +1548,12 @@ proc genMainProc(m: BModule) =
|
|
const otherMain = WinCDllMain
|
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
|
elif m.config.target.targetOS == osGenode:
|
|
- const otherMain = ComponentConstruct
|
|
- appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
|
+ if m.config.isDefined("posix"):
|
|
+ const otherMain = LibcComponentConstruct
|
|
+ appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
|
+ else:
|
|
+ const otherMain = ComponentConstruct
|
|
+ appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
|
elif optGenDynLib in m.config.globalOptions:
|
|
const otherMain = PosixCDllMain
|
|
appcg(m, m.s[cfsProcs], otherMain, [m.config.nimMainPrefix])
|
|
--
|
|
2.37.2
|
|
|