From 23ccb0a30c1c41d7b809e5104fefd73175a89504 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Thu, 20 Oct 2022 14:26:31 -0500 Subject: [PATCH] Update Nixpkgs input for Nim updates --- flake.lock | 6 +- overlay/nim.patch | 2253 --------------------------------------------- 2 files changed, 3 insertions(+), 2256 deletions(-) delete mode 100644 overlay/nim.patch diff --git a/flake.lock b/flake.lock index 5377c5a..951b41f 100644 --- a/flake.lock +++ b/flake.lock @@ -43,11 +43,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1665079737, - "narHash": "sha256-mbi/+D73l2VXmiIJzh1oNjohrh+o2MrPblEGzaR7IiI=", + "lastModified": 1666290634, + "narHash": "sha256-k39/nAXfpbDp9rrbxSEGf+evCbmoMUC8YnqM7Re46CE=", "owner": "ehmry", "repo": "nixpkgs", - "rev": "f971220848e4f9efe39667bc986f10e378a8b877", + "rev": "32751f50996939c2ac11229ecd0ce2ec68d05ac6", "type": "github" }, "original": { diff --git a/overlay/nim.patch b/overlay/nim.patch deleted file mode 100644 index dfd6111..0000000 --- a/overlay/nim.patch +++ /dev/null @@ -1,2253 +0,0 @@ -From b50326bf9b53f02d7a1244dbf12a00b35a0ff71e Mon Sep 17 00:00:00 2001 -From: Emery Hemingway -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: "".} - 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: "", - 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: "", 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: "", -- importc: "sprintf", varargs, noSideEffect.} -+when not defined(nimNoLibc): -+ proc c_sprintf(buf, frmt: cstring): cint {.header: "", -+ 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: "", noSideEffect.} -+when not defined(nimNoLibc): -+ proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {. -+ importc: "strtod", header: "", 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 -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 `_ - ## * `getProjectPath proc `_ -- 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: "".} --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 --- -2.37.2 - - -From 11e259afe417e39fda794c83304cfd815da2dfd6 Mon Sep 17 00:00:00 2001 -From: Emery Hemingway -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: "", 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: "", 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 = "" -+ -+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: "", 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 -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 -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: "", -+ 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 = "" - -@@ -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: "", pure.} = object -+ ## Capability to an asynchronous signal context. -+ -+proc isValid*(cap: SignalContextCapability): bool {. -+ importcpp: "#.valid()", tags: [IOEffect].} -+ -+{.emit: """ -+#include -+#include -+#include -+ -+/* 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 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 = "" -+ -+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 -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.. -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 = "" - -@@ -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", -+ 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 -+ -+namespace Nim { -+ -+ /** -+ * Class for calling a Nim callback from a Genode timer. -+ */ -+ template -+ struct Timeout_handler -+ { -+ Timer::One_shot_timeout _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 -+ typedef Constructible> 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 -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("") - elif m.config.target.targetOS == osGenode: -- m.includeHeader("") -+ if m.config.isDefined("posix"): -+ m.includeHeader("") -+ else: -+ m.includeHeader("") - - 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 -