diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-03-31 18:51:11 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-03-31 18:51:11 +0300 |
commit | 8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5 (patch) | |
tree | 3fb011eb742df74754abc2479d211bbdbef16b02 /lib | |
parent | 22dc76a361c70af93403dfbf2610c8d49111637c (diff) | |
parent | c7fc519fa39ded59744bc677261faa04b6947cee (diff) | |
download | Nim-8d698b2bdd63cb7390a418d9ebb3ee7fdc7ea3b5.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod into upstream
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/irc.nim | 6 | ||||
-rwxr-xr-x | lib/pure/sockets.nim | 87 | ||||
-rwxr-xr-x | lib/system.nim | 54 | ||||
-rwxr-xr-x | lib/system/ansi_c.nim | 1 | ||||
-rw-r--r-- | lib/system/embedded.nim | 106 | ||||
-rwxr-xr-x | lib/system/excpt.nim | 2 | ||||
-rwxr-xr-x | lib/system/mmdisp.nim | 72 | ||||
-rwxr-xr-x | lib/system/repr.nim | 3 |
8 files changed, 298 insertions, 33 deletions
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim index 8946a9d8f..81dff024e 100644 --- a/lib/pure/irc.nim +++ b/lib/pure/irc.nim @@ -142,6 +142,8 @@ proc parseMessage(msg: string): TIRCEvent = inc(i) # Skip `:` var nick = "" i.inc msg.parseUntil(nick, {'!', ' '}, i) + result.nick = "" + result.serverName = "" if msg[i] == '!': result.nick = nick inc(i) # Skip `!` @@ -237,7 +239,8 @@ proc processLine(irc: var TIRC, line: string): TIRCEvent = result = parseMessage(line) # Get the origin result.origin = result.params[0] - if result.origin == irc.nick: result.origin = result.nick + if result.origin == irc.nick and + result.nick != "": result.origin = result.nick if result.cmd == MError: irc.close() @@ -386,6 +389,7 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort, result.messageBuffer = @[] result.handleEvent = ircEvent result.userArg = userArg + result.lineBuffer = "" proc register*(d: PDispatcher, irc: PAsyncIRC) = ## Registers ``irc`` with dispatcher ``d``. diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 5721d79fe..31973c6ce 100755 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -8,8 +8,12 @@ # ## This module implements a simple portable type-safe sockets layer. +## +## Most procedures raise EOS on error. + import os, parseutils +from times import epochTime when defined(Windows): import winlean @@ -59,6 +63,8 @@ type TRecvLineResult* = enum ## result for recvLineAsync RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail + ETimeout* = object of ESynch + const InvalidSocket* = TSocket(-1'i32) ## invalid socket number @@ -377,12 +383,14 @@ proc connect*(socket: TSocket, name: string, port = TPort(0), ## host name. If ``name`` is a host name, this function will try each IP ## of that host name. ``htons`` is already performed on ``port`` so you must ## not do it. + var hints: TAddrInfo var aiList: ptr TAddrInfo = nil hints.ai_family = toInt(af) hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_protocol = toInt(IPPROTO_TCP) gaiNim(name, port, hints, aiList) + # try all possibilities: var success = false var it = aiList @@ -445,7 +453,6 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0), freeaddrinfo(aiList) if not success: OSError() - proc timeValFromMilliseconds(timeout = 500): TTimeVal = if timeout != -1: var seconds = timeout div 1000 @@ -545,7 +552,33 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int = result = int(select(cint(m+1), addr(rd), nil, nil, nil)) pruneSocketSet(readfds, (rd)) + +proc recv*(socket: TSocket, data: pointer, size: int): int = + ## receives data from a socket + result = recv(cint(socket), data, size, 0'i32) +template waitFor(): stmt = + if timeout - int(waited * 1000.0) < 1: + raise newException(ETimeout, "Call to recv() timed out.") + var s = @[socket] + var startTime = epochTime() + if select(s, timeout - int(waited * 1000.0)) != 1: + raise newException(ETimeout, "Call to recv() timed out.") + waited += (epochTime() - startTime) + +proc recv*(socket: TSocket, data: var string, size: int, timeout: int): int = + ## overload with a ``timeout`` parameter in miliseconds. + var waited = 0.0 # number of seconds already waited + + var read = 0 + while read < size: + waitFor() + result = recv(cint(socket), addr(data[read]), 1, 0'i32) + if result < 0: + return + inc(read) + + result = read proc recvLine*(socket: TSocket, line: var TaintedString): bool = ## returns false if no further data is available. `Line` must be initialized @@ -567,6 +600,29 @@ proc recvLine*(socket: TSocket, line: var TaintedString): bool = elif c == '\L': return true add(line.string, c) +proc recvLine*(socket: TSocket, line: var TaintedString, timeout: int): bool = + ## variant with a ``timeout`` parameter, the timeout parameter specifies + ## how many miliseconds to wait for data. + + var waited = 0.0 # number of seconds already waited + + setLen(line.string, 0) + while true: + var c: char + waitFor() + var n = recv(cint(socket), addr(c), 1, 0'i32) + if n < 0: return + elif n == 0: return true + if c == '\r': + waitFor() + n = recv(cint(socket), addr(c), 1, MSG_PEEK) + if n > 0 and c == '\L': + discard recv(cint(socket), addr(c), 1, 0'i32) + elif n <= 0: return false + return true + elif c == '\L': return true + add(line.string, c) + proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult = ## similar to ``recvLine`` but for non-blocking sockets. ## The values of the returned enum should be pretty self explanatory: @@ -592,10 +648,6 @@ proc recvLineAsync*(socket: TSocket, line: var TaintedString): TRecvLineResult = elif c == '\L': return RecvFullLine add(line.string, c) -proc recv*(socket: TSocket, data: pointer, size: int): int = - ## receives data from a socket - result = recv(cint(socket), data, size, 0'i32) - proc recv*(socket: TSocket): TaintedString = ## receives all the data from the socket. ## Socket errors will result in an ``EOS`` error. @@ -625,6 +677,16 @@ proc recv*(socket: TSocket): TaintedString = add(result.string, buf) if bytesRead != bufSize-1: break +proc recvTimeout*(socket: TSocket, timeout: int): TaintedString = + ## overloaded variant to support a ``timeout`` parameter, the ``timeout`` + ## parameter specifies the amount of miliseconds to wait for data on the + ## socket. + var s = @[socket] + if s.select(timeout) != 1: + raise newException(ETimeout, "Call to recv() timed out.") + + return socket.recv + proc recvAsync*(socket: TSocket, s: var TaintedString): bool = ## receives all the data from a non-blocking socket. If socket is non-blocking ## and there are no messages available, `False` will be returned. @@ -723,6 +785,21 @@ proc setBlocking*(s: TSocket, blocking: bool) = if fcntl(cint(s), F_SETFL, mode) == -1: OSError() +proc connect*(socket: TSocket, timeout: int, name: string, port = TPort(0), + af: TDomain = AF_INET) = + ## Overload for ``connect`` to support timeouts. The ``timeout`` parameter + ## specifies the time in miliseconds of how long to wait for a connection + ## to be made. + ## + ## **Warning:** If ``socket`` is non-blocking and timeout is not ``-1`` then + ## this function may set blocking mode on ``socket`` to true. + socket.setBlocking(true) + + socket.connectAsync(name, port, af) + var s: seq[TSocket] = @[socket] + if selectWrite(s, timeout) != 1: + raise newException(ETimeout, "Call to connect() timed out.") + when defined(Windows): var wsa: TWSADATA if WSAStartup(0x0101'i16, wsa) != 0: OSError() diff --git a/lib/system.nim b/lib/system.nim index e1b82b6bb..78912be7e 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -851,7 +851,7 @@ template sysAssert(cond: bool, msg: string) = include "system/inclrtl" -when not defined(ecmascript) and not defined(nimrodVm): +when not defined(ecmascript) and not defined(nimrodVm) and not defined(avr): include "system/cgprocs" proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} @@ -1604,16 +1604,17 @@ when not defined(EcmaScript) and not defined(NimrodVM): {.push stack_trace: off.} proc initGC() - when not defined(boehmgc): + when not defined(boehmgc) and not defined(useMalloc): proc initAllocator() {.inline.} - proc initStackBottom() {.inline.} = - # WARNING: This is very fragile! An array size of 8 does not work on my - # Linux 64bit system. Very strange, but we are at the will of GCC's - # optimizer... - var locals {.volatile.}: pointer - locals = addr(locals) - setStackBottom(locals) + when not defined(nogc): + proc initStackBottom() {.inline.} = + # WARNING: This is very fragile! An array size of 8 does not work on my + # Linux 64bit system. Very strange, but we are at the will of GCC's + # optimizer... + var locals {.volatile.}: pointer + locals = addr(locals) + setStackBottom(locals) var strDesc: TNimType @@ -1868,7 +1869,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): when hasThreadSupport: include "system/syslocks" include "system/threads" - else: + elif not defined(nogc): initStackBottom() initGC() @@ -1881,21 +1882,23 @@ when not defined(EcmaScript) and not defined(NimrodVM): ## for debug builds. {.push stack_trace: off.} - include "system/excpt" + when hostCPU == "avr": + include "system/embedded" + else: + include "system/excpt" + # we cannot compile this with stack tracing on # as it would recurse endlessly! include "system/arithm" {.pop.} # stack trace {.pop.} # stack trace - include "system/dyncalls" + when hostOS != "standalone": include "system/dyncalls" include "system/sets" const GenericSeqSize = (2 * sizeof(int)) - proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} - proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") var d: int @@ -1918,7 +1921,7 @@ when not defined(EcmaScript) and not defined(NimrodVM): include "system/mmdisp" {.push stack_trace: off.} - include "system/sysstr" + when hostCPU != "avr": include "system/sysstr" {.pop.} include "system/sysio" @@ -1938,18 +1941,19 @@ when not defined(EcmaScript) and not defined(NimrodVM): var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield TaintedString(res) - include "system/assign" - include "system/repr" + when hostCPU != "avr": + include "system/assign" + include "system/repr" - proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} = - ## retrieves the current exception; if there is none, nil is returned. - result = currException + proc getCurrentException*(): ref E_Base {.compilerRtl, inl.} = + ## retrieves the current exception; if there is none, nil is returned. + result = currException - proc getCurrentExceptionMsg*(): string {.inline.} = - ## retrieves the error message that was attached to the current - ## exception; if there is none, "" is returned. - var e = getCurrentException() - return if e == nil: "" else: e.msg + proc getCurrentExceptionMsg*(): string {.inline.} = + ## retrieves the error message that was attached to the current + ## exception; if there is none, "" is returned. + var e = getCurrentException() + return if e == nil: "" else: e.msg {.push stack_trace: off.} when defined(endb): diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 9722e1396..e328f7099 100755 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -103,4 +103,3 @@ proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.} proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.} {.pop} - diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim new file mode 100644 index 000000000..f17432561 --- /dev/null +++ b/lib/system/embedded.nim @@ -0,0 +1,106 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +# Bare-bones implementation of some things for embedded targets. + +proc writeToStdErr(msg: CString) = write(stdout, msg) + +proc chckIndx(i, a, b: int): int {.inline, compilerproc.} +proc chckRange(i, a, b: int): int {.inline, compilerproc.} +proc chckRangeF(x, a, b: float): float {.inline, compilerproc.} +proc chckNil(p: pointer) {.inline, compilerproc.} + +proc pushFrame(s: PFrame) {.compilerRtl, inl.} = nil +proc popFrame {.compilerRtl, inl.} = nil + +proc setFrame(s: PFrame) {.compilerRtl, inl.} = nil +proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = nil +proc popSafePoint {.compilerRtl, inl.} = nil +proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = nil +proc popCurrentException {.compilerRtl, inl.} = nil + +# some platforms have native support for stack traces: +const + nativeStackTraceSupported = false + hasSomeStackTrace = false + +proc quitOrDebug() {.inline.} = + quit(1) + +proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = + writeToStdErr(ename) + +proc reraiseException() {.compilerRtl.} = + writeToStdErr("reraise not supported") + +proc WriteStackTrace() = nil + +proc setControlCHook(hook: proc () {.noconv.}) = + # ugly cast, but should work on all architectures: + type TSignalHandler = proc (sig: cint) {.noconv.} + c_signal(SIGINT, cast[TSignalHandler](hook)) + +proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = + writeToStdErr("value out of range") + +proc raiseIndexError() {.compilerproc, noreturn, noinline.} = + writeToStdErr("index out of bounds") + +proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = + writeToStdErr("field is not accessible") + +proc chckIndx(i, a, b: int): int = + if i >= a and i <= b: + return i + else: + raiseIndexError() + +proc chckRange(i, a, b: int): int = + if i >= a and i <= b: + return i + else: + raiseRangeError(i) + +proc chckRange64(i, a, b: int64): int64 {.compilerproc.} = + if i >= a and i <= b: + return i + else: + raiseRangeError(i) + +proc chckRangeF(x, a, b: float): float = + if x >= a and x <= b: + return x + else: + raise newException(EOutOfRange, "value " & $x & " out of range") + +proc chckNil(p: pointer) = + if p == nil: c_raise(SIGSEGV) + +proc chckObj(obj, subclass: PNimType) {.compilerproc.} = + # checks if obj is of type subclass: + var x = obj + if x == subclass: return # optimized fast path + while x != subclass: + if x == nil: + raise newException(EInvalidObjectConversion, "invalid object conversion") + x = x.base + +proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = + if a != b: + raise newException(EInvalidObjectAssignment, "invalid object assignment") + +proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = + # checks if obj is of type subclass: + var x = obj + if x == subclass: return true # optimized fast path + while x != subclass: + if x == nil: return false + x = x.base + return true diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 8ffca90fb..2df7fe4ad 100755 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -27,7 +27,7 @@ else: proc writeToStdErr(msg: CString) = discard MessageBoxA(0, msg, nil, 0) -proc registerSignalHandler() {.compilerproc.} +proc registerSignalHandler() proc chckIndx(i, a, b: int): int {.inline, compilerproc.} proc chckRange(i, a, b: int): int {.inline, compilerproc.} diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index e8ad23970..1abf3fbbf 100755 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -181,6 +181,78 @@ when defined(boehmgc): proc deallocOsPages() {.inline.} = nil include "system/cellsets" +elif defined(nogc) and defined(useMalloc): + + when not defined(useNimRtl): + proc alloc(size: int): pointer = + result = cmalloc(size) + if result == nil: raiseOutOfMem() + proc alloc0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + proc realloc(p: Pointer, newsize: int): pointer = + result = crealloc(p, newsize) + if result == nil: raiseOutOfMem() + proc dealloc(p: Pointer) = cfree(p) + + proc allocShared(size: int): pointer = + result = cmalloc(size) + if result == nil: raiseOutOfMem() + proc allocShared0(size: int): pointer = + result = alloc(size) + zeroMem(result, size) + proc reallocShared(p: Pointer, newsize: int): pointer = + result = crealloc(p, newsize) + if result == nil: raiseOutOfMem() + proc deallocShared(p: Pointer) = cfree(p) + + proc GC_disable() = nil + proc GC_enable() = nil + proc GC_fullCollect() = nil + proc GC_setStrategy(strategy: TGC_Strategy) = nil + proc GC_enableMarkAndSweep() = nil + proc GC_disableMarkAndSweep() = nil + proc GC_getStatistics(): string = return "" + + proc getOccupiedMem(): int = nil + proc getFreeMem(): int = nil + proc getTotalMem(): int = nil + + proc setStackBottom(theStackBottom: pointer) = nil + + proc initGC() = nil + + proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} = + result = alloc(size) + proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} = + result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize)) + cast[PGenericSeq](result).len = len + cast[PGenericSeq](result).reserved = len + + proc growObj(old: pointer, newsize: int): pointer = + result = realloc(old, newsize) + + proc nimGCref(p: pointer) {.compilerproc, inline.} = nil + proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil + + proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} = + dest[] = src + + type + TMemRegion = object {.final, pure.} + + proc Alloc(r: var TMemRegion, size: int): pointer = + result = alloc(size) + proc Alloc0(r: var TMemRegion, size: int): pointer = + result = alloc0(size) + proc Dealloc(r: var TMemRegion, p: Pointer) = Dealloc(p) + proc deallocOsPages(r: var TMemRegion) {.inline.} = nil + proc deallocOsPages() {.inline.} = nil + elif defined(nogc): # Even though we don't want the GC, we cannot simply use C's memory manager # because Nimrod's runtime wants ``realloc`` to zero out the additional diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 2dec8136c..ec02f5e08 100755 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -9,6 +9,9 @@ # The generic ``repr`` procedure. It is an invaluable debugging tool. +when not defined(useNimRtl): + proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.} + proc reprInt(x: int64): string {.compilerproc.} = return $x proc reprFloat(x: float): string {.compilerproc.} = return $x |