summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system')
-rw-r--r--lib/system/alloc.nim4
-rw-r--r--lib/system/avltree.nim8
-rw-r--r--lib/system/channels.nim54
-rw-r--r--lib/system/deepcopy.nim19
-rw-r--r--lib/system/sysstr.nim5
-rw-r--r--lib/system/threads.nim2
6 files changed, 55 insertions, 37 deletions
diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim
index bed9fd906..745bbbf62 100644
--- a/lib/system/alloc.nim
+++ b/lib/system/alloc.nim
@@ -101,8 +101,8 @@ type
 
 # shared:
 var
-  bottomData: AvlNode
-  bottom: PAvlNode
+  bottomData {.threadvar.}: AvlNode
+  bottom {.threadvar.}: PAvlNode
 
 {.push stack_trace: off.}
 proc initAllocator() =
diff --git a/lib/system/avltree.nim b/lib/system/avltree.nim
index d5c901542..50faada26 100644
--- a/lib/system/avltree.nim
+++ b/lib/system/avltree.nim
@@ -9,7 +9,7 @@
 
 # not really an AVL tree anymore, but still balanced ...
 
-template isBottom(n: PAvlNode): bool = n == bottom
+template isBottom(n: PAvlNode): bool = n.link[0] == n
 
 proc lowGauge(n: PAvlNode): int =
   var it = n
@@ -52,7 +52,7 @@ proc split(t: var PAvlNode) =
     inc t.level
 
 proc add(a: var MemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
-  if t == bottom:
+  if t.isBottom:
     t = allocAvlNode(a, key, upperBound)
   else:
     if key <% t.key:
@@ -65,14 +65,14 @@ proc add(a: var MemRegion, t: var PAvlNode, key, upperBound: int) {.benign.} =
     split(t)
 
 proc del(a: var MemRegion, t: var PAvlNode, x: int) {.benign.} =
-  if t == bottom: return
+  if isBottom(t): return
   a.last = t
   if x <% t.key:
     del(a, t.link[0], x)
   else:
     a.deleted = t
     del(a, t.link[1], x)
-  if t == a.last and a.deleted != bottom and x == a.deleted.key:
+  if t == a.last and not isBottom(a.deleted) and x == a.deleted.key:
     a.deleted.key = t.key
     a.deleted.upperBound = t.upperBound
     a.deleted = bottom
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index caa709229..0c97bc8db 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -52,6 +52,7 @@ proc deinitRawChannel(p: pointer) =
 
 proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
               mode: LoadStoreMode) {.benign.}
+
 proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
               mode: LoadStoreMode) {.benign.} =
   var
@@ -71,6 +72,9 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
 
 proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
               mode: LoadStoreMode) =
+  template `+!`(p: pointer; x: int): pointer =
+    cast[pointer](cast[int](p) +% x)
+
   var
     d = cast[ByteAddress](dest)
     s = cast[ByteAddress](src)
@@ -93,7 +97,9 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
       if s2 == nil:
         unsureAsgnRef(x, s2)
       else:
-        unsureAsgnRef(x, copyString(cast[NimString](s2)))
+        let y = copyDeepString(cast[NimString](s2))
+        #echo "loaded ", cast[int](y), " ", cast[string](y)
+        unsureAsgnRef(x, y)
         dealloc(t.region, s2)
   of tySequence:
     var s2 = cast[PPointer](src)[]
@@ -107,26 +113,27 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
     else:
       sysAssert(dest != nil, "dest == nil")
       if mode == mStore:
-        x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
+        x[] = alloc0(t.region, seq.len *% mt.base.size +% GenericSeqSize)
       else:
         unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
       var dst = cast[ByteAddress](cast[PPointer](dest)[])
+      var dstseq = cast[PGenericSeq](dst)
+      dstseq.len = seq.len
+      dstseq.reserved = seq.len
       for i in 0..seq.len-1:
         storeAux(
           cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
           cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
                         GenericSeqSize),
           mt.base, t, mode)
-      var dstseq = cast[PGenericSeq](dst)
-      dstseq.len = seq.len
-      dstseq.reserved = seq.len
       if mode != mStore: dealloc(t.region, s2)
   of tyObject:
-    # copy type field:
-    var pint = cast[ptr PNimType](dest)
-    pint[] = cast[ptr PNimType](src)[]
     if mt.base != nil:
       storeAux(dest, src, mt.base, t, mode)
+    else:
+      # copy type field:
+      var pint = cast[ptr PNimType](dest)
+      pint[] = cast[ptr PNimType](src)[]
     storeAux(dest, src, mt.node, t, mode)
   of tyTuple:
     storeAux(dest, src, mt.node, t, mode)
@@ -143,15 +150,24 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
       else:
         unsureAsgnRef(x, nil)
     else:
-      let size = if mt.base.kind == tyObject: cast[ptr PNimType](s)[].size
-                 else: mt.base.size
+      #let size = if mt.base.kind == tyObject: cast[ptr PNimType](s)[].size
+      #           else: mt.base.size
       if mode == mStore:
-        x[] = alloc(t.region, size)
+        let dyntype = when declared(usrToCell): usrToCell(s).typ
+                      else: mt
+        let size = dyntype.base.size
+        # we store the real dynamic 'ref type' at offset 0, so that
+        # no information is lost
+        let a = alloc0(t.region, size+sizeof(pointer))
+        x[] = a
+        cast[PPointer](a)[] = dyntype
+        storeAux(a +! sizeof(pointer), s, dyntype.base, t, mode)
       else:
-        var obj = newObj(mt, size)
+        let dyntype = cast[ptr PNimType](s)[]
+        var obj = newObj(dyntype, dyntype.base.size)
         unsureAsgnRef(x, obj)
-      storeAux(x[], s, mt.base, t, mode)
-      if mode != mStore: dealloc(t.region, s)
+        storeAux(x[], s +! sizeof(pointer), dyntype.base, t, mode)
+        dealloc(t.region, s)
   else:
     copyMem(dest, src, mt.size) # copy raw bits
 
@@ -194,10 +210,8 @@ template sendImpl(q: expr) {.immediate.} =
   if q.mask == ChannelDeadMask:
     sysFatal(DeadThreadError, "cannot send message; thread died")
   acquireSys(q.lock)
-  var m: TMsg
-  shallowCopy(m, msg)
   var typ = cast[PNimType](getTypeInfo(msg))
-  rawSend(q, addr(m), typ)
+  rawSend(q, unsafeAddr(msg), typ)
   q.elemType = typ
   releaseSys(q.lock)
   signalSysCond(q.cond)
@@ -228,8 +242,10 @@ proc recv*[TMsg](c: var Channel[TMsg]): TMsg =
 
 proc tryRecv*[TMsg](c: var Channel[TMsg]): tuple[dataAvailable: bool,
                                                   msg: TMsg] =
-  ## try to receives a message from the channel `c` if available. Otherwise
-  ## it returns ``(false, default(msg))``.
+  ## try to receives a message from the channel `c`, but this can fail
+  ## for all sort of reasons, including contention. If it fails,
+  ## it returns ``(false, default(msg))`` otherwise it
+  ## returns ``(true, msg)``.
   var q = cast[PRawChannel](addr(c))
   if q.mask != ChannelDeadMask:
     if tryAcquireSys(q.lock):
diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim
index 5445a067c..38cc8cbf3 100644
--- a/lib/system/deepcopy.nim
+++ b/lib/system/deepcopy.nim
@@ -32,12 +32,6 @@ proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
       genericDeepCopyAux(dest, src, m)
   of nkNone: sysAssert(false, "genericDeepCopyAux")
 
-proc copyDeepString(src: NimString): NimString {.inline.} =
-  if src != nil:
-    result = rawNewStringNoInit(src.len)
-    result.len = src.len
-    copyMem(addr(result.data), addr(src.data), src.len + 1)
-
 proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
   var
     d = cast[ByteAddress](dest)
@@ -70,10 +64,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
   of tyObject:
     # we need to copy m_type field for tyObject, as it could be empty for
     # sequence reallocations:
-    var pint = cast[ptr PNimType](dest)
-    pint[] = cast[ptr PNimType](src)[]
     if mt.base != nil:
       genericDeepCopyAux(dest, src, mt.base)
+    else:
+      var pint = cast[ptr PNimType](dest)
+      pint[] = cast[ptr PNimType](src)[]
     genericDeepCopyAux(dest, src, mt.node)
   of tyTuple:
     genericDeepCopyAux(dest, src, mt.node)
@@ -103,16 +98,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
         else:
           let realType = x.typ
           let z = newObj(realType, realType.base.size)
-
           unsureAsgnRef(cast[PPointer](dest), z)
           x.typ = cast[PNimType](cast[int](z) or 1)
           genericDeepCopyAux(z, s2, realType.base)
           x.typ = realType
       else:
-        let realType = mt
-        let z = newObj(realType, realType.base.size)
+        let size = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[].size
+                   else: mt.base.size
+        let z = newObj(mt, size)
         unsureAsgnRef(cast[PPointer](dest), z)
-        genericDeepCopyAux(z, s2, realType.base)
+        genericDeepCopyAux(z, s2, mt.base)
   of tyPtr:
     # no cycle check here, but also not really required
     let s2 = cast[PPointer](src)[]
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 3e170172b..3a93221e0 100644
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.nim
@@ -110,6 +110,11 @@ proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
     result.len = src.len
     copyMem(addr(result.data), addr(src.data), src.len + 1)
 
+proc copyDeepString(src: NimString): NimString {.inline.} =
+  if src != nil:
+    result = rawNewStringNoInit(src.len)
+    result.len = src.len
+    copyMem(addr(result.data), addr(src.data), src.len + 1)
 
 proc hashString(s: string): int {.compilerproc.} =
   # the compiler needs exactly the same hash function!
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 62829f62c..6f5bb38b1 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -356,6 +356,8 @@ proc threadProcWrapStackFrame[TArg](thrd: ptr Thread[TArg]) =
 
 template threadProcWrapperBody(closure: expr) {.immediate.} =
   when declared(globalsSlot): threadVarSetValue(globalsSlot, closure)
+  when declared(initAllocator):
+    initAllocator()
   var thrd = cast[ptr Thread[TArg]](closure)
   threadProcWrapStackFrame(thrd)
   # Since an unhandled exception terminates the whole process (!), there is