# # # Nim's Runtime Library # (c) Copyright 2026 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # Read-write lock (RwLock) for lib/system. # Used by YRC and by traceable containers that perform topology-changing ops. # POSIX: pthread_rwlock_* ; Windows: SRWLOCK (slim reader/writer). {.push stackTrace: off.} when defined(windows): # SRWLOCK is pointer-sized; use single pointer for ABI compatibility type RwLock* {.importc: "SRWLOCK", header: "", final, pure, byref.} = object p: pointer proc initializeSRWLock(L: var RwLock) {.importc: "InitializeSRWLock", header: "".} proc acquireSRWLockShared(L: var RwLock) {.importc: "AcquireSRWLockShared", header: "".} proc releaseSRWLockShared(L: var RwLock) {.importc: "ReleaseSRWLockShared", header: "".} proc acquireSRWLockExclusive(L: var RwLock) {.importc: "AcquireSRWLockExclusive", header: "".} proc releaseSRWLockExclusive(L: var RwLock) {.importc: "ReleaseSRWLockExclusive", header: "".} proc initRwLock*(L: var RwLock) {.inline.} = initializeSRWLock(L) proc deinitRwLock*(L: var RwLock) {.inline.} = discard proc acquireRead*(L: var RwLock) {.inline.} = acquireSRWLockShared(L) proc releaseRead*(L: var RwLock) {.inline.} = releaseSRWLockShared(L) proc acquireWrite*(L: var RwLock) {.inline.} = acquireSRWLockExclusive(L) proc releaseWrite*(L: var RwLock) {.inline.} = releaseSRWLockExclusive(L) elif defined(genode): {.error: "RwLock is not implemented for Genode".} else: # POSIX: pthread_rwlock_* type SysRwLockObj {.importc: "pthread_rwlock_t", pure, final, header: """#include #include """, byref.} = object when defined(linux) and defined(amd64): abi: array[56 div sizeof(clong), clong] proc pthread_rwlock_init(rwlock: var SysRwLockObj, attr: pointer): cint {. importc: "pthread_rwlock_init", header: "", noSideEffect.} proc pthread_rwlock_destroy(rwlock: var SysRwLockObj): cint {. importc: "pthread_rwlock_destroy", header: "", noSideEffect.} proc pthread_rwlock_rdlock(rwlock: var SysRwLockObj): cint {. importc: "pthread_rwlock_rdlock", header: "", noSideEffect.} proc pthread_rwlock_wrlock(rwlock: var SysRwLockObj): cint {. importc: "pthread_rwlock_wrlock", header: "", noSideEffect.} proc pthread_rwlock_unlock(rwlock: var SysRwLockObj): cint {. importc: "pthread_rwlock_unlock", header: "", noSideEffect.} when defined(linux): # PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP: once a writer is waiting, # new readers block. Prevents continuous mutator read-locks from starving # the collector's write-lock acquisition (glibc default is PREFER_READER). type SysRwLockAttr {.importc: "pthread_rwlockattr_t", pure, final, header: "".} = object const PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP = cint(3) proc pthread_rwlockattr_init(attr: ptr SysRwLockAttr): cint {. importc: "pthread_rwlockattr_init", header: "".} proc pthread_rwlockattr_destroy(attr: ptr SysRwLockAttr): cint {. importc: "pthread_rwlockattr_destroy", header: "".} proc pthread_rwlockattr_setkind_np(attr: ptr SysRwLockAttr; pref: cint): cint {. importc: "pthread_rwlockattr_setkind_np", header: "".} when defined(ios): type RwLock* = ptr SysRwLockObj proc initRwLock*(L: var RwLock) = when not declared(c_malloc): proc c_malloc(size: csize_t): pointer {.importc: "malloc", header: "".} proc c_free(p: pointer) {.importc: "free", header: "".} L = cast[RwLock](c_malloc(csize_t(sizeof(SysRwLockObj)))) discard pthread_rwlock_init(L[], nil) proc deinitRwLock*(L: var RwLock) = if L != nil: discard pthread_rwlock_destroy(L[]) when not declared(c_free): proc c_free(p: pointer) {.importc: "free", header: "".} c_free(L) L = nil proc acquireRead*(L: var RwLock) = discard pthread_rwlock_rdlock(L[]) proc releaseRead*(L: var RwLock) = discard pthread_rwlock_unlock(L[]) proc acquireWrite*(L: var RwLock) = discard pthread_rwlock_wrlock(L[]) proc releaseWrite*(L: var RwLock) = discard pthread_rwlock_unlock(L[]) else: type RwLock* = SysRwLockObj proc initRwLock*(L: var RwLock) = when defined(linux): var attr: SysRwLockAttr discard pthread_rwlockattr_init(addr attr) discard pthread_rwlockattr_setkind_np(addr attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) discard pthread_rwlock_init(L, addr attr) discard pthread_rwlockattr_destroy(addr attr) else: discard pthread_rwlock_init(L, nil) proc deinitRwLock*(L: var RwLock) = discard pthread_rwlock_destroy(L) proc acquireRead*(L: var RwLock) = discard pthread_rwlock_rdlock(L) proc releaseRead*(L: var RwLock) = discard pthread_rwlock_unlock(L) proc acquireWrite*(L: var RwLock) = discard pthread_rwlock_wrlock(L) proc releaseWrite*(L: var RwLock) = discard pthread_rwlock_unlock(L) template withReadLock*(L: var RwLock, body: untyped) = acquireRead(L) try: body finally: releaseRead(L) template withWriteLock*(L: var RwLock, body: untyped) = acquireWrite(L) try: body finally: releaseWrite(L) {.pop.}