diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/genode_cpp/syslocks.h | 78 | ||||
-rw-r--r-- | lib/genode_cpp/threads.h | 69 | ||||
-rw-r--r-- | lib/nimbase.h | 5 | ||||
-rw-r--r-- | lib/posix/posix.nim | 18 | ||||
-rw-r--r-- | lib/pure/concurrency/cpuinfo.nim | 7 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 4 | ||||
-rw-r--r-- | lib/pure/os.nim | 16 | ||||
-rw-r--r-- | lib/system.nim | 47 | ||||
-rw-r--r-- | lib/system/dyncalls.nim | 11 | ||||
-rw-r--r-- | lib/system/osalloc.nim | 13 | ||||
-rw-r--r-- | lib/system/reprjs.nim | 272 | ||||
-rw-r--r-- | lib/system/syslocks.nim | 22 | ||||
-rw-r--r-- | lib/system/threads.nim | 75 |
13 files changed, 592 insertions, 45 deletions
diff --git a/lib/genode_cpp/syslocks.h b/lib/genode_cpp/syslocks.h new file mode 100644 index 000000000..8ba39abc2 --- /dev/null +++ b/lib/genode_cpp/syslocks.h @@ -0,0 +1,78 @@ +/* + * + * Nim's Runtime Library + * (c) Copyright 2017 Emery Hemingway + * + * See the file "copying.txt", included in this + * distribution, for details about the copyright. + * + */ + +#ifndef _GENODE_CPP__SYSLOCKS_H_ +#define _GENODE_CPP__SYSLOCKS_H_ + +/* Genode includes */ +#include <base/semaphore.h> +#include <base/lock.h> + +namespace Nim { + struct SysLock; + struct SysCond; +} + +struct Nim::SysLock +{ + Genode::Lock _lock_a, _lock_b; + bool _locked; + + void acquireSys() + { + _lock_a.lock(); + _locked = true; + _lock_a.unlock(); + _lock_b.lock(); + } + + bool tryAcquireSys() + { + if (_locked) + return false; + + _lock_a.lock(); + if (_locked) { + _lock_a.unlock(); + return false; + } else { + _locked = true; + _lock_b.lock(); + _lock_a.unlock(); + return true; + } + } + + void releaseSys() + { + _locked = false; + _lock_a.unlock(); + _lock_b.unlock(); + } +}; + +struct Nim::SysCond +{ + Genode::Semaphore _semaphore; + + void waitSysCond(SysLock &syslock) + { + syslock.releaseSys(); + _semaphore.down(); + syslock.acquireSys(); + } + + void signalSysCond() + { + _semaphore.up(); + } +}; + +#endif diff --git a/lib/genode_cpp/threads.h b/lib/genode_cpp/threads.h new file mode 100644 index 000000000..a1cd61cd2 --- /dev/null +++ b/lib/genode_cpp/threads.h @@ -0,0 +1,69 @@ +/* + * + * Nim's Runtime Library + * (c) Copyright 2017 Emery Hemingway + * + * See the file "copying.txt", included in this + * distribution, for details about the copyright. + * + */ + + +#ifndef _GENODE_CPP__THREAD_H_ +#define _GENODE_CPP__THREAD_H_ + +#include <base/thread.h> +#include <util/avl_tree.h> +#include <util/reconstructible.h> + +namespace Nim { struct SysThread; } + +struct Nim::SysThread +{ + typedef void (Entry)(void*); + + struct Thread : Genode::Thread + { + void *_tls; + + Entry *_func; + void *_arg; + + void entry() override { + (_func)(_arg); } + + Thread(Genode::Env &env, Genode::size_t stack_size, Entry func, void *arg) + : Genode::Thread(env, "nim-thread", stack_size), _func(func), _arg(arg) + { + Genode::Thread::start(); + } + }; + + Genode::Constructible<Thread> _thread; + + void initThread(Genode::Env *env, Genode::size_t stack_size, Entry func, void *arg) { + _thread.construct(*env, stack_size, func, arg); } + + void joinThread() { + _thread->join(); } + + static bool offMainThread() { + return dynamic_cast<SysThread::Thread*>(Genode::Thread::myself()); } + + static void *threadVarGetValue() + { + SysThread::Thread *thr = + static_cast<SysThread::Thread*>(Genode::Thread::myself()); + return thr->_tls; + } + + static void threadVarSetValue(void *value) + { + SysThread::Thread *thr = + static_cast<SysThread::Thread*>(Genode::Thread::myself()); + thr->_tls = value; + } + +}; + +#endif diff --git a/lib/nimbase.h b/lib/nimbase.h index a535d0da9..714623d4e 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -498,6 +498,11 @@ typedef int Nim_and_C_compiler_disagree_on_target_architecture[sizeof(NI) == siz # include <sys/types.h> #endif +#if defined(__GENODE__) +#include <libc/component.h> +extern Libc::Env *genodeEnv; +#endif + /* Compile with -d:checkAbi and a sufficiently C11:ish compiler to enable */ #define NIM_CHECK_SIZE(typ, sz) \ _Static_assert(sizeof(typ) == sz, "Nim & C disagree on type size") diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index b29f43eb4..1ff861534 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1862,10 +1862,10 @@ when hasAioH: a4: ptr SigEvent): cint {.importc, header: "<aio.h>".} # arpa/inet.h -proc htonl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".} -proc htons*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".} -proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".} -proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".} +proc htonl*(a1: uint32): uint32 {.importc, header: "<arpa/inet.h>".} +proc htons*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".} +proc ntohl*(a1: uint32): uint32 {.importc, header: "<arpa/inet.h>".} +proc ntohs*(a1: uint16): uint16 {.importc, header: "<arpa/inet.h>".} proc inet_addr*(a1: cstring): InAddrT {.importc, header: "<arpa/inet.h>".} proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".} @@ -2423,11 +2423,15 @@ proc sigset*(a1: int, a2: proc (x: cint) {.noconv.}) {. proc sigsuspend*(a1: var Sigset): cint {.importc, header: "<signal.h>".} when defined(android): - proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, - a3: var Timespec, sigsetsize: csize = sizeof(culong)*2): cint {.importc: "__rt_sigtimedwait", header:"<signal.h>".} + proc syscall(arg: clong): clong {.varargs, importc: "syscall", header: "<unistd.h>".} + var NR_rt_sigtimedwait {.importc: "__NR_rt_sigtimedwait", header: "<sys/syscall.h>".}: clong + var NSIGMAX {.importc: "NSIG", header: "<signal.h>".}: clong + + proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, a3: var Timespec): cint = + result = cint(syscall(NR_rt_sigtimedwait, addr(a1), addr(a2), addr(a3), NSIGMAX div 8)) else: proc sigtimedwait*(a1: var Sigset, a2: var SigInfo, - a3: var Timespec): cint {.importc, header: "<signal.h>".} + a3: var Timespec): cint {.importc, header: "<signal.h>".} proc sigwait*(a1: var Sigset, a2: var cint): cint {. importc, header: "<signal.h>".} diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index 8c87c77df..c3390573a 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -37,6 +37,10 @@ when defined(macosx) or defined(bsd): a: var csize, b: pointer, c: int): cint {. importc: "sysctl", nodecl.} +when defined(genode): + proc affinitySpaceTotal(): cuint {. + importcpp: "genodeEnv->cpu().affinity_space().total()".} + proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = ## returns the numer of the processors/cores the machine has. ## Returns 0 if it cannot be detected. @@ -61,7 +65,8 @@ proc countProcessors*(): int {.rtl, extern: "ncpi$1".} = elif defined(irix): var SC_NPROC_ONLN {.importc: "_SC_NPROC_ONLN", header: "<unistd.h>".}: cint result = sysconf(SC_NPROC_ONLN) + elif defined(genode): + result = affinitySpaceTotal().int else: result = sysconf(SC_NPROCESSORS_ONLN) if result <= 0: result = 1 - diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 7f666fb35..62c7e2067 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -320,7 +320,7 @@ proc parseResponse(s: Socket, getBody: bool, timeout: int): Response = if line[linei] != ':': httpError("invalid headers") inc(linei) # Skip : - result.headers[name] = line[linei.. ^1].strip() + result.headers.add(name, line[linei.. ^1].strip()) # Ensure the server isn't trying to DoS us. if result.headers.len > headerLimit: httpError("too many headers") @@ -1010,7 +1010,7 @@ proc parseResponse(client: HttpClient | AsyncHttpClient, if line[linei] != ':': httpError("invalid headers") inc(linei) # Skip : - result.headers[name] = line[linei.. ^1].strip() + result.headers.add(name, line[linei.. ^1].strip()) if result.headers.len > headerLimit: httpError("too many headers") diff --git a/lib/pure/os.nim b/lib/pure/os.nim index a7f7116ef..82acb2a59 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -825,16 +825,16 @@ proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = else: add environment, (key & '=' & val) indx = high(environment) - when defined(unix): - if c_putenv(environment[indx]) != 0'i32: - raiseOSError(osLastError()) - else: + when defined(windows): when useWinUnicode: var k = newWideCString(key) var v = newWideCString(val) if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) else: if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) + else: + if c_putenv(environment[indx]) != 0'i32: + raiseOSError(osLastError()) iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = ## Iterate over all `environments variables`:idx:. In the first component @@ -1091,7 +1091,7 @@ proc rawCreateDir(dir: string): bool = result = false else: raiseOSError(osLastError()) - elif defined(unix): + elif defined(posix): let res = mkdir(dir, 0o777) if res == 0'i32: result = true @@ -1452,7 +1452,9 @@ elif defined(windows): if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) return TaintedString(ownArgv[i]) -elif not defined(createNimRtl) and not(defined(posix) and appType == "lib"): +elif not defined(createNimRtl) and + not(defined(posix) and appType == "lib") and + not defined(genode): # On Posix, there is no portable way to get the command line from a DLL. var cmdCount {.importc: "cmdCount".}: cint @@ -1606,6 +1608,8 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = result = getApplAux("/proc/self/exe") elif defined(solaris): result = getApplAux("/proc/" & $getpid() & "/path/a.out") + elif defined(genode): + raiseOSError("POSIX command line not supported") elif defined(freebsd) or defined(dragonfly): result = getApplFreebsd() # little heuristic that may work on other POSIX-like systems: diff --git a/lib/system.nim b/lib/system.nim index 371cf8544..f6133b741 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1384,25 +1384,34 @@ var programResult* {.exportc: "nim_program_result".}: int ## under normal circumstances. When the program is terminated ## prematurely using ``quit``, this value is ignored. -proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.} - ## Stops the program immediately with an exit code. - ## - ## Before stopping the program the "quit procedures" are called in the - ## opposite order they were added with `addQuitProc <#addQuitProc>`_. - ## ``quit`` never returns and ignores any exception that may have been raised - ## by the quit procedures. It does *not* call the garbage collector to free - ## all the memory, unless a quit procedure calls `GC_fullCollect - ## <#GC_fullCollect>`_. - ## - ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim - ## program finishes without incident. A raised unhandled exception is - ## equivalent to calling ``quit(QuitFailure)``. - ## - ## Note that this is a *runtime* call and using ``quit`` inside a macro won't - ## have any compile time effect. If you need to stop the compiler inside a - ## macro, use the `error <manual.html#error-pragma>`_ or `fatal - ## <manual.html#fatal-pragma>`_ pragmas. +when defined(nimdoc): + proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.} + ## Stops the program immediately with an exit code. + ## + ## Before stopping the program the "quit procedures" are called in the + ## opposite order they were added with `addQuitProc <#addQuitProc>`_. + ## ``quit`` never returns and ignores any exception that may have been raised + ## by the quit procedures. It does *not* call the garbage collector to free + ## all the memory, unless a quit procedure calls `GC_fullCollect + ## <#GC_fullCollect>`_. + ## + ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim + ## program finishes without incident. A raised unhandled exception is + ## equivalent to calling ``quit(QuitFailure)``. + ## + ## Note that this is a *runtime* call and using ``quit`` inside a macro won't + ## have any compile time effect. If you need to stop the compiler inside a + ## macro, use the `error <manual.html#error-pragma>`_ or `fatal + ## <manual.html#fatal-pragma>`_ pragmas. + + +elif defined(genode): + proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn, + importcpp: "genodeEnv->parent().exit(@)", header: "<base/env.h>".} + +else: + proc quit*(errorcode: int = QuitSuccess) {. + magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.} template sysAssert(cond: bool, msg: string) = when defined(useSysAssert): diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index be6275338..2b86ddf25 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -146,6 +146,17 @@ elif defined(windows) or defined(dos): if result != nil: return procAddrError(name) +elif defined(genode): + + proc nimUnloadLibrary(lib: LibHandle) {. + error: "nimUnloadLibrary not implemented".} + + proc nimLoadLibrary(path: string): LibHandle {. + error: "nimLoadLibrary not implemented".} + + proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr {. + error: "nimGetProcAddr not implemented".} + else: {.error: "no implementation for dyncalls".} diff --git a/lib/system/osalloc.nim b/lib/system/osalloc.nim index a57a88e8f..65a057772 100644 --- a/lib/system/osalloc.nim +++ b/lib/system/osalloc.nim @@ -77,6 +77,19 @@ when defined(emscripten): var mmapDescr = cast[EmscriptenMMapBlock](mmapDescrPos) munmap(mmapDescr.realPointer, mmapDescr.realSize) +elif defined(genode): + + proc osAllocPages(size: int): pointer {. + importcpp: "genodeEnv->rm().attach(genodeEnv->ram().alloc(@))".} + + proc osTryAllocPages(size: int): pointer = + {.emit: """try {""".} + result = osAllocPages size + {.emit: """} catch (...) { }""".} + + proc osDeallocPages(p: pointer, size: int) {. + importcpp: "genodeEnv->rm().detach(#)".} + elif defined(posix): const PROT_READ = 1 # page can be read diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index 57237cfff..6b0e32191 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -6,18 +6,272 @@ # See the file "copying.txt", included in this # distribution, for details about the copyright. # +# The generic ``repr`` procedure for the javascript backend. proc reprInt(x: int64): string {.compilerproc.} = return $x +proc reprFloat(x: float): string {.compilerproc.} = + # Js toString doesn't differentiate between 1.0 and 1, + # but we do. + if $x == $(x.int): $x & ".0" + else: $x + +proc reprPointer(p: pointer): string {.compilerproc.} = + # Do we need to generate the full 8bytes ? In js a pointer is an int anyway + var tmp: int + {. emit: """ + if (`p`_Idx == null) { + `tmp` = 0; + } else { + `tmp` = `p`_Idx; + } + """ .} + result = $tmp + +proc reprBool(x: bool): string {.compilerRtl.} = + if x: result = "true" + else: result = "false" + +proc isUndefined[T](x: T): bool {.inline.} = {.emit: "`result` = `x` === undefined;"} proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = - if ntfEnumHole notin typ.flags: - if e <% typ.node.len: - return $typ.node.sons[e].name + if not typ.node.sons[e].isUndefined: + result = $typ.node.sons[e].name + else: + result = $e & " (invalid data!)" + +proc reprChar(x: char): string {.compilerRtl.} = + result = "\'" + case x + of '"': add(result, "\\\"") + of '\\': add(result, "\\\\") + of '\128'..'\255', '\0'..'\31': add( result, "\\" & reprInt(ord(x)) ) + else: add(result, x) + add(result, "\'") + +proc reprStrAux(result: var string, s: cstring, len: int) = + add(result, "\"") + for i in 0 .. <len: + let c = s[i] + case c + of '"': add(result, "\\\"") + of '\\': add(result, "\\\\") + of '\10': add(result, "\\10\"\n\"") + of '\128'..'\255', '\0'..'\9', '\11'..'\31': + add( result, "\\" & reprInt(ord(c)) ) + else: + add( result, reprInt(ord(c)) ) # Not sure about this. + add(result, "\"") + +proc reprStr(s: string): string {.compilerRtl.} = + result = "" + if cast[pointer](s).isNil: + # Handle nil strings here because they don't have a length field in js + # TODO: check for null/undefined before generating call to length in js? + # Also: c backend repr of a nil string is <pointer>"", but repr of an + # array of string that is not initialized is [nil, nil, ...] ?? + add(result, "nil") + else: + reprStrAux(result, s, s.len) + +proc addSetElem(result: var string, elem: int, typ: PNimType) = + # Dispatch each set element to the correct repr<Type> proc + case typ.kind: + of tyEnum: add(result, reprEnum(elem, typ)) + of tyBool: add(result, reprBool(bool(elem))) + of tyChar: add(result, reprChar(chr(elem))) + of tyRange: addSetElem(result, elem, typ.base) # Note the base to advance towards the element type + of tyInt..tyInt64, tyUInt8, tyUInt16: add result, reprInt(elem) + else: # data corrupt --> inform the user + add(result, " (invalid data!)") + +iterator setKeys(s: int): int {.inline.} = + # The type of s is a lie, but it's expected to be a set. + # Iterate over the JS object representing a set + # and returns the keys as int. + var len: int + var yieldRes: int + var i: int = 0 + {. emit: """ + var setObjKeys = Object.getOwnPropertyNames(`s`); + `len` = setObjKeys.length; + """ .} + while i < len: + {. emit: "`yieldRes` = parseInt(setObjKeys[`i`],10);\n" .} + yield yieldRes + inc i + +proc reprSetAux(result: var string, s: int, typ: PNimType) = + add(result, "{") + var first: bool = true + for el in setKeys(s): + if first: + first = false + else: + add(result, ", ") + addSetElem(result, el, typ.base) + add(result, "}") + +proc reprSet(e: int, typ: PNimType): string {.compilerRtl.} = + result = "" + reprSetAux(result, e, typ) + +type + ReprClosure {.final.} = object + recDepth: int # do not recurse endlessly + indent: int # indentation + +proc initReprClosure(cl: var ReprClosure) = + cl.recDepth = -1 # default is to display everything! + cl.indent = 0 + +proc reprAux(result: var string, p: pointer, typ: PNimType, cl: var ReprClosure) + +proc reprArray(a: pointer, typ: PNimType, + cl: var ReprClosure): string {.compilerRtl.} = + var isNilArrayOrSeq: bool + # isnil is not enough here as it would try to deref `a` without knowing what's inside + {. emit: """ + if (`a` == null) { + `isNilArrayOrSeq` = true; + } else if (`a`[0] == null) { + `isNilArrayOrSeq` = true; + } else { + `isNilArrayOrSeq` = false; + }; + """ .} + if typ.kind == tySequence and isNilArrayOrSeq: + return "nil" + + # We prepend @ to seq, the C backend prepends the pointer to the seq. + result = if typ.kind == tySequence: "@[" else: "[" + var len: int = 0 + var i: int = 0 + + {. emit: "`len` = `a`.length;\n" .} + var dereffed: pointer = a + for i in 0 .. < len: + if i > 0 : + add(result, ", ") + # advance pointer and point to element at index + {. emit: """ + `dereffed`_Idx = `i`; + `dereffed` = `a`[`dereffed`_Idx]; + """ .} + reprAux(result, dereffed, typ.base, cl) + + add(result, "]") + +proc isPointedToNil(p: pointer): bool {.inline.}= + {. emit: "if (`p` === null) {`result` = true};\n" .} + +proc reprRef(result: var string, p: pointer, typ: PNimType, + cl: var ReprClosure) = + if p.isPointedToNil: + add(result , "nil") + return + add( result, "ref " & reprPointer(p) ) + add(result, " --> ") + if typ.base.kind != tyArray: + {. emit: """ + if (`p` != null && `p`.length > 0) { + `p` = `p`[`p`_Idx]; + } + """ .} + reprAux(result, p, typ.base, cl) + +proc reprRecordAux(result: var string, o: pointer, typ: PNimType, cl: var ReprClosure) = + add(result, "[") + + var first: bool = true + var val: pointer = o + if typ.node.len == 0: + # if the object has only one field, len is 0 and sons is nil, the field is in node + let key: cstring = typ.node.name + add(result, $key & " = ") + {. emit: "`val` = `o`[`key`];\n" .} + reprAux(result, val, typ.node.typ, cl) + else: + # if the object has more than one field, sons is not nil and contains the fields. + for i in 0 .. <typ.node.len: + if first: first = false + else: add(result, ",\n") + + let key: cstring = typ.node.sons[i].name + add(result, $key & " = ") + {. emit: "`val` = `o`[`key`];\n" .} # access the field by name + reprAux(result, val, typ.node.sons[i].typ, cl) + add(result, "]") + +proc reprRecord(o: pointer, typ: PNimType, cl: var ReprClosure): string {.compilerRtl.} = + result = "" + reprRecordAux(result, o, typ,cl) + + +proc reprJSONStringify(p: int): string {.compilerRtl.} = + # As a last resort, use stringify + # We use this for tyOpenArray, tyVarargs while genTypeInfo is not implemented + var tmp: cstring + {. emit: "`tmp` = JSON.stringify(`p`);\n" .} + result = $tmp + +proc reprAux(result: var string, p: pointer, typ: PNimType, + cl: var ReprClosure) = + if cl.recDepth == 0: + add(result, "...") + return + dec(cl.recDepth) + case typ.kind + of tyInt..tyInt64, tyUInt..tyUInt64: + add( result, reprInt(cast[int](p)) ) + of tyChar: + add( result, reprChar(cast[char](p)) ) + of tyBool: + add( result, reprBool(cast[bool](p)) ) + of tyFloat..tyFloat128: + add( result, reprFloat(cast[float](p)) ) + of tyString: + var fp: int + {. emit: "`fp` = `p`;\n" .} + if cast[string](fp).isNil: + add(result, "nil") + else: + add( result, reprStr(cast[string](p)) ) + of tyCString: + var fp: cstring + {. emit: "`fp` = `p`;\n" .} + if fp.isNil: + add(result, "nil") + else: + reprStrAux(result, fp, fp.len) + of tyEnum, tyOrdinal: + var fp: int + {. emit: "`fp` = `p`;\n" .} + add(result, reprEnum(fp, typ)) + of tySet: + var fp: int + {. emit: "`fp` = `p`;\n" .} + add(result, reprSet(fp, typ)) + of tyRange: reprAux(result, p, typ.base, cl) + of tyObject, tyTuple: + add(result, reprRecord(p, typ, cl)) + of tyArray, tyArrayConstr, tySequence: + add(result, reprArray(p, typ, cl)) + of tyPointer: + add(result, reprPointer(p)) + of tyPtr, tyRef: + reprRef(result, p, typ, cl) + of tyProc: + if p.isPointedToNil: + add(result, "nil") + else: + add(result, reprPointer(p)) else: - # ugh we need a slow linear search: - var n = typ.node - var s = n.sons - for i in 0 .. n.len-1: - if s[i].offset == e: return $s[i].name - result = $e & " (invalid data!)" + add( result, "(invalid data!)" & reprJsonStringify(cast[int](p)) ) + inc(cl.recDepth) +proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} = + var cl: ReprClosure + initReprClosure(cl) + result = "" + reprAux(result, p, typ, cl) + add(result, "\n") \ No newline at end of file diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index c3e23052b..9d056611f 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -75,6 +75,28 @@ when defined(Windows): proc waitSysCondWindows(cond: var SysCond) = discard waitForSingleObject(cond, -1'i32) +elif defined(genode): + const + Header = "genode_cpp/syslocks.h" + type + SysLock {.importcpp: "Nim::SysLock", pure, final, + header: Header.} = object + SysCond {.importcpp: "Nim::SysCond", pure, final, + header: Header.} = object + + proc initSysLock(L: var SysLock) = discard + proc deinitSys(L: var SysLock) = discard + proc acquireSys(L: var SysLock) {.noSideEffect, importcpp.} + proc tryAcquireSys(L: var SysLock): bool {.noSideEffect, importcpp.} + proc releaseSys(L: var SysLock) {.noSideEffect, importcpp.} + + proc initSysCond(L: var SysCond) = discard + proc deinitSysCond(L: var SysCond) = discard + proc waitSysCond(cond: var SysCond, lock: var SysLock) {. + noSideEffect, importcpp.} + proc signalSysCond(cond: var SysCond) {. + noSideEffect, importcpp.} + else: type SysLock {.importc: "pthread_mutex_t", pure, final, diff --git a/lib/system/threads.nim b/lib/system/threads.nim index dc9cc9656..4855a2b93 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -46,7 +46,11 @@ const maxRegisters = 256 # don't think there is an arch with more registers useStackMaskHack = false ## use the stack mask hack for better performance StackGuardSize = 4096 - ThreadStackMask = 1024*256*sizeof(int)-1 + ThreadStackMask = + when defined(genode): + 1024*64*sizeof(int)-1 + else: + 1024*256*sizeof(int)-1 ThreadStackSize = ThreadStackMask+1 - StackGuardSize when defined(windows): @@ -115,6 +119,49 @@ when defined(windows): ## get the ID of the currently running thread. result = int(getCurrentThreadId()) +elif defined(genode): + const + GenodeHeader = "genode_cpp/threads.h" + type + SysThread* {.importcpp: "Nim::SysThread", + header: GenodeHeader, final, pure.} = object + GenodeThreadProc = proc (x: pointer) {.noconv.} + ThreadVarSlot = int + + proc initThread(s: var SysThread, + stackSize: culonglong, + entry: GenodeThreadProc, + arg: pointer) {. + importcpp: "#.initThread(genodeEnv, @)".} + + proc threadVarAlloc(): ThreadVarSlot = 0 + + proc offMainThread(): bool {. + importcpp: "Nim::SysThread::offMainThread", + header: GenodeHeader.} + + proc threadVarSetValue(value: pointer) {. + importcpp: "Nim::SysThread::threadVarSetValue(@)", + header: GenodeHeader.} + + proc threadVarGetValue(): pointer {. + importcpp: "Nim::SysThread::threadVarGetValue()", + header: GenodeHeader.} + + var mainTls: pointer + + proc threadVarSetValue(s: ThreadVarSlot, value: pointer) {.inline.} = + if offMainThread(): + threadVarSetValue(value); + else: + mainTls = value + + proc threadVarGetValue(s: ThreadVarSlot): pointer {.inline.} = + if offMainThread(): + threadVarGetValue(); + else: + mainTls + else: when not defined(macosx): {.passL: "-pthread".} @@ -451,6 +498,9 @@ when defined(windows): proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} = threadProcWrapperBody(closure) # implicitly return 0 +elif defined(genode): + proc threadProcWrapper[TArg](closure: pointer) {.noconv.} = + threadProcWrapperBody(closure) else: proc threadProcWrapper[TArg](closure: pointer): pointer {.noconv.} = threadProcWrapperBody(closure) @@ -482,6 +532,14 @@ when hostOS == "windows": cast[ptr SysThread](addr(a)), 1, -1) inc(k, MAXIMUM_WAIT_OBJECTS) +elif defined(genode): + proc joinThread*[TArg](t: Thread[TArg]) {.importcpp.} + ## waits for the thread `t` to finish. + + proc joinThreads*[TArg](t: varargs[Thread[TArg]]) = + ## waits for every thread in `t` to finish. + for i in 0..t.high: joinThread(t[i]) + else: proc joinThread*[TArg](t: Thread[TArg]) {.inline.} = ## waits for the thread `t` to finish. @@ -531,6 +589,21 @@ when hostOS == "windows": ## shouldn't use this proc. setThreadAffinityMask(t.sys, uint(1 shl cpu)) +elif defined(genode): + proc createThread*[TArg](t: var Thread[TArg], + tp: proc (arg: TArg) {.thread, nimcall.}, + param: TArg) = + when TArg isnot void: t.data = param + t.dataFn = tp + when hasSharedHeap: t.stackSize = ThreadStackSize + t.sys.initThread( + ThreadStackSize.culonglong, + threadProcWrapper[TArg], addr(t)) + + proc pinToCpu*[Arg](t: var Thread[Arg]; cpu: Natural) = + {.hint: "cannot change Genode thread CPU affinity after initialization".} + discard + else: proc createThread*[TArg](t: var Thread[TArg], tp: proc (arg: TArg) {.thread, nimcall.}, |