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/channels.nim7
-rw-r--r--lib/system/excpt.nim6
-rw-r--r--lib/system/gc.nim36
3 files changed, 39 insertions, 10 deletions
diff --git a/lib/system/channels.nim b/lib/system/channels.nim
index 3e5ca0795..d07d6eae1 100644
--- a/lib/system/channels.nim
+++ b/lib/system/channels.nim
@@ -232,9 +232,10 @@ proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvailable: bool,
   ## it returns ``(false, default(msg))``.

   var q = cast[PRawChannel](addr(c))

   if q.mask != ChannelDeadMask:

-    if tryAcquireSys(q.lock):

-      llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))

-      result.dataAvailable = true

+    if tryAcquireSys(q.lock):
+      if q.count > 0:

+        llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg)))

+        result.dataAvailable = true

       releaseSys(q.lock)

 

 proc peek*[TMsg](c: var TChannel[TMsg]): int =

diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index e21eeca6a..237b42482 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -296,15 +296,15 @@ when not defined(noSignalHandler):
     template processSignal(s, action: expr) {.immediate,  dirty.} =
       if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
       elif s == SIGSEGV: 
-        action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
+        action("SIGSEGV: Illegal storage access. (Try to compile with -d:useSysAssert -d:useGcAssert for details.)\n")
       elif s == SIGABRT:
         when defined(endb):
           if dbgAborting: return # the debugger wants to abort
         action("SIGABRT: Abnormal termination.\n")
       elif s == SIGFPE: action("SIGFPE: Arithmetic error.\n")
       elif s == SIGILL: action("SIGILL: Illegal operation.\n")
-      elif s == SIGBUS: 
-        action("SIGBUS: Illegal storage access. (Attempt to read from nil?)\n")
+      elif s == SIGBUS:
+        action("SIGBUS: Illegal storage access.  (Try to compile with -d:useSysAssert -d:useGcAssert for details.)\n")
       else:
         block platformSpecificSignal:
           when declared(SIGPIPE):
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index e0db3fba4..58587cf7f 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -49,7 +49,7 @@ type
     waMarkGlobal,    # part of the backup/debug mark&sweep
     waMarkPrecise,   # part of the backup/debug mark&sweep
     waZctDecRef, waPush, waCycleDecRef, waMarkGray, waScan, waScanBlack, 
-    waCollectWhite,
+    waCollectWhite #, waDebug
 
   TFinalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.}
     # A ref type can have a finalizer that is called before the object's
@@ -595,9 +595,15 @@ proc scan(s: PCell) =
     else:
       s.setColor(rcWhite)
       forAllChildren(s, waScan)
-  
+
 proc collectWhite(s: PCell) =
-  if s.color == rcWhite and s notin gch.cycleRoots:
+  # This is a hacky way to deal with the following problem (bug #1796)
+  # Consider this content in cycleRoots:
+  #   x -> a; y -> a  where 'a' is an acyclic object so not included in
+  # cycleRoots itself. Then 'collectWhite' used to free 'a' twice. The
+  # 'isAllocatedPtr' check prevents this. This also means we do not need
+  # to query 's notin gch.cycleRoots' at all.
+  if isAllocatedPtr(gch.region, s) and s.color == rcWhite:
     s.setColor(rcBlack)
     forAllChildren(s, waCollectWhite)
     freeCyclicCell(gch, s)
@@ -648,6 +654,28 @@ when useMarkForDebug or useBackupGc:
       if objStart != nil:
         markS(gch, objStart)
 
+when logGC:
+  var
+    cycleCheckA: array[100, PCell]
+    cycleCheckALen = 0
+
+  proc alreadySeen(c: PCell): bool =
+    for i in 0 .. <cycleCheckALen:
+      if cycleCheckA[i] == c: return true
+    if cycleCheckALen == len(cycleCheckA):
+      gcAssert(false, "cycle detection overflow")
+      quit 1
+    cycleCheckA[cycleCheckALen] = c
+    inc cycleCheckALen
+
+  proc debugGraph(s: PCell) =
+    if alreadySeen(s):
+      writeCell("child cell (already seen) ", s)
+    else:
+      writeCell("cell {", s)
+      forAllChildren(s, waDebug)
+      c_fprintf(c_stdout, "}\n")
+
 proc doOperation(p: pointer, op: TWalkOp) =
   if p == nil: return
   var c: PCell = usrToCell(p)
@@ -690,6 +718,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
   of waMarkPrecise:
     when useMarkForDebug or useBackupGc:
       add(gch.tempStack, c)
+  #of waDebug: debugGraph(c)
 
 proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
   doOperation(d, TWalkOp(op))
@@ -702,7 +731,6 @@ when useMarkForDebug or useBackupGc:
 
 proc collectRoots(gch: var TGcHeap) =
   for s in elements(gch.cycleRoots):
-    excl(gch.cycleRoots, s)
     collectWhite(s)
 
 proc collectCycles(gch: var TGcHeap) =