summary refs log tree commit diff stats
path: root/lib/core/locks.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/core/locks.nim')
-rw-r--r--lib/core/locks.nim214
1 files changed, 69 insertions, 145 deletions
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
index 071bde93a..523727479 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -1,166 +1,90 @@
 #
 #
-#            Nimrod's Runtime Library
-#        (c) Copyright 2012 Andreas Rumpf
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module contains Nimrod's support for locks and condition vars.
-## If the symbol ``preventDeadlocks`` is defined
-## (compiled with ``-d:preventDeadlocks``) special logic is added to
-## every ``acquire``, ``tryAcquire`` and ``release`` action that ensures at
-## runtime that no deadlock can occur. This is achieved by forcing a thread
-## to release its locks should it be part of a deadlock. This thread then
-## re-acquires its locks and proceeds.
+## This module contains Nim's support for locks and condition vars.
 
-include "system/syslocks"
+#[
+for js, for now we treat locks as noop's to avoid pushing `when defined(js)`
+in client code that uses locks.
+]#
+
+when not compileOption("threads") and not defined(nimdoc):
+  when false: # fix #12330
+    {.error: "Locks requires --threads:on option.".}
+
+import std/private/syslocks
 
 type
-  TLock* = TSysLock ## Nimrod lock; whether this is re-entrant
-                    ## or not is unspecified! However, compilation
-                    ## in preventDeadlocks-mode guarantees re-entrancy.
-  TCond* = TSysCond ## Nimrod condition variable
-  
-  FLock* = object of TEffect ## effect that denotes that some lock operation
-                             ## is performed
-  FAquireLock* = object of FLock  ## effect that denotes that some lock is
-                                  ## aquired
-  FReleaseLock* = object of FLock ## effect that denotes that some lock is
-                                  ## released
-  
-const
-  noDeadlocks = defined(preventDeadlocks)
-  maxLocksPerThread* = 10 ## max number of locks a thread can hold
-                          ## at the same time; this limit is only relevant
-                          ## when compiled with ``-d:preventDeadlocks``.
-
-var
-  deadlocksPrevented*: int ## counts the number of times a 
-                           ## deadlock has been prevented
-
-when noDeadlocks:
-  var
-    locksLen {.threadvar.}: int
-    locks {.threadvar.}: array [0..MaxLocksPerThread-1, pointer]
-
-  proc OrderedLocks(): bool = 
-    for i in 0 .. locksLen-2:
-      if locks[i] >= locks[i+1]: return false
-    result = true
-
-proc InitLock*(lock: var TLock) {.inline.} =
+  Lock* = SysLock ## Nim lock; whether this is re-entrant
+                  ## or not is unspecified!
+  Cond* = SysCond ## Nim condition variable
+
+{.push stackTrace: off.}
+
+
+proc `$`*(lock: Lock): string =
+  # workaround bug #14873
+  result = "()"
+
+proc initLock*(lock: var Lock) {.inline.} =
   ## Initializes the given lock.
-  InitSysLock(lock)
+  when not defined(js):
+    initSysLock(lock)
 
-proc DeinitLock*(lock: var TLock) {.inline.} =
+proc deinitLock*(lock: Lock) {.inline.} =
   ## Frees the resources associated with the lock.
-  DeinitSys(lock)
+  deinitSys(lock)
 
-proc TryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} = 
+proc tryAcquire*(lock: var Lock): bool {.inline.} =
   ## Tries to acquire the given lock. Returns `true` on success.
-  result = TryAcquireSys(lock)
-  when noDeadlocks:
-    if not result: return
-    # we have to add it to the ordered list. Oh, and we might fail if
-    # there is no space in the array left ...
-    if locksLen >= len(locks):
-      ReleaseSys(lock)
-      raise newException(EResourceExhausted, "cannot acquire additional lock")
-    # find the position to add:
-    var p = addr(lock)
-    var L = locksLen-1
-    var i = 0
-    while i <= L:
-      assert locks[i] != nil
-      if locks[i] < p: inc(i) # in correct order
-      elif locks[i] == p: return # thread already holds lock
-      else:
-        # do the crazy stuff here:
-        while L >= i:
-          locks[L+1] = locks[L]
-          dec L
-        locks[i] = p
-        inc(locksLen)
-        assert OrderedLocks()
-        return
-    # simply add to the end:
-    locks[locksLen] = p
-    inc(locksLen)
-    assert OrderedLocks()
-
-proc Acquire*(lock: var TLock) {.tags: [FAquireLock].} =
+  result = tryAcquireSys(lock)
+
+proc acquire*(lock: var Lock) {.inline.} =
   ## Acquires the given lock.
-  when nodeadlocks:
-    var p = addr(lock)
-    var L = locksLen-1
-    var i = 0
-    while i <= L:
-      assert locks[i] != nil
-      if locks[i] < p: inc(i) # in correct order
-      elif locks[i] == p: return # thread already holds lock
-      else:
-        # do the crazy stuff here:
-        if locksLen >= len(locks):
-          raise newException(EResourceExhausted, 
-              "cannot acquire additional lock")
-        while L >= i:
-          ReleaseSys(cast[ptr TSysLock](locks[L])[])
-          locks[L+1] = locks[L]
-          dec L
-        # acquire the current lock:
-        AcquireSys(lock)
-        locks[i] = p
-        inc(locksLen)
-        # acquire old locks in proper order again:
-        L = locksLen-1
-        inc i
-        while i <= L:
-          AcquireSys(cast[ptr TSysLock](locks[i])[])
-          inc(i)
-        # DANGER: We can only modify this global var if we gained every lock!
-        # NO! We need an atomic increment. Crap.
-        discard system.atomicInc(deadlocksPrevented, 1)
-        assert OrderedLocks()
-        return
-        
-    # simply add to the end:
-    if locksLen >= len(locks):
-      raise newException(EResourceExhausted, "cannot acquire additional lock")
-    AcquireSys(lock)
-    locks[locksLen] = p
-    inc(locksLen)
-    assert OrderedLocks()
-  else:
-    AcquireSys(lock)
-  
-proc Release*(lock: var TLock) {.tags: [FReleaseLock].} =
+  when not defined(js):
+    acquireSys(lock)
+
+proc release*(lock: var Lock) {.inline.} =
   ## Releases the given lock.
-  when nodeadlocks:
-    var p = addr(lock)
-    var L = locksLen
-    for i in countdown(L-1, 0):
-      if locks[i] == p: 
-        for j in i..L-2: locks[j] = locks[j+1]
-        dec locksLen
-        break
-  ReleaseSys(lock)
-
-
-proc InitCond*(cond: var TCond) {.inline.} =
+  when not defined(js):
+    releaseSys(lock)
+
+
+proc initCond*(cond: var Cond) {.inline.} =
   ## Initializes the given condition variable.
-  InitSysCond(cond)
+  initSysCond(cond)
 
-proc DeinitCond*(cond: var TCond) {.inline.} =
-  ## Frees the resources associated with the lock.
-  DeinitSysCond(cond)
-
-proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
-  ## waits on the condition variable `cond`. 
-  WaitSysCond(cond, lock)
-  
-proc signal*(cond: var TCond) {.inline.} =
-  ## sends a signal to the condition variable `cond`. 
+proc deinitCond*(cond: Cond) {.inline.} =
+  ## Frees the resources associated with the condition variable.
+  deinitSysCond(cond)
+
+proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
+  ## Waits on the condition variable `cond`.
+  waitSysCond(cond, lock)
+
+proc signal*(cond: var Cond) {.inline.} =
+  ## Sends a signal to the condition variable `cond`.
   signalSysCond(cond)
 
+proc broadcast*(cond: var Cond) {.inline.} =
+  ## Unblocks all threads currently blocked on the
+  ## specified condition variable `cond`.
+  broadcastSysCond(cond)
+
+template withLock*(a: Lock, body: untyped) =
+  ## Acquires the given lock, executes the statements in body and
+  ## releases the lock after the statements finish executing.
+  acquire(a)
+  {.locks: [a].}:
+    try:
+      body
+    finally:
+      release(a)
+
+{.pop.}