# # # Nim's Runtime Library # (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # A simple mark&sweep garbage collector for Nim. Define the # symbol ``gcUseBitvectors`` to generate a variant of this GC. {.push profiler:off.} const InitialThreshold = 4*1024*1024 # X MB because marking&sweeping is slow withBitvectors = defined(gcUseBitvectors) # bitvectors are significantly faster for GC-bench, but slower for # bootstrapping and use more memory rcWhite = 0 rcGrey = 1 # unused rcBlack = 2 template mulThreshold(x): untyped = x * 2 when defined(memProfiler): proc nimProfile(requestedSize: int) when hasThreadSupport: import sharedlist type WalkOp = enum waMarkGlobal, # we need to mark conservatively for global marker procs # as these may refer to a global var and not to a thread # local waMarkPrecise # fast precise marking Finalizer {.compilerproc.} = proc (self: pointer) {.nimcall, benign.} # A ref type can have a finalizer that is called before the object's # storage is freed. GcStat = object collections: int # number of performed full collections maxThreshold: int # max threshold that has been set maxStackSize: int # max stack size freedObjects: int # max entries in cycle table GcStack {.final, pure.} = object when nimCoroutines: prev: ptr GcStack next: ptr GcStack maxStackSize: int # Used to track statistics because we can not use # GcStat.maxStackSize when multiple stacks exist. bottom: pointer when nimCoroutines: pos: pointer GcHeap = object # this contains the zero count and # non-zero count table stack: GcStack when nimCoroutines: activeStack: ptr GcStack # current executing coroutine stack. cycleThreshold: int when useCellIds: idGenerator: int when withBitvectors: allocated, marked: CellSet tempStack: CellSeq # temporary stack for recursion elimination recGcLock: int # prevent recursion via finalizers; no thread lock region: MemRegion # garbage collected region stat: GcStat when hasThreadSupport: toDispose: SharedList[pointer] gcThreadId: int additionalRoots: CellSeq # dummy roots for GC_ref/unref when defined(nimTracing): tracing: bool indentation: int var gch {.rtlThreadVar.}: GcHeap when not defined(useNimRtl): instantiateForRegion(gch.region) template acquire(gch: GcHeap) = when hasThreadSupport and hasSharedHeap: acquireSys(HeapLock) template release(gch: GcHeap) = when hasThreadSupport and hasSharedHeap: releaseSys(HeapLock) template gcAssert(cond: bool, msg: string) = when defined(useGcAssert): if not cond: echo "[GCASSERT] ", msg quit 1 proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(Cell))) proc usrToCell(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(Cell))) proc canbeCycleRoot(c: PCell): bool {.inline.} = result = ntfAcyclic notin c.typ.flags proc extGetCellType(c: pointer): PNimType {.compilerproc.} = # used for code generation concerning debugging result = usrToCell(c).typ proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} = dest[] = src proc internRefcount(p: pointer): int {.exportc: "getRefcount".} = result = 0 # this that has to equals zero, otherwise we have to round up UnitsPerPage: when BitsPerPage mod (sizeof(int)*8) != 0: {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".} # forward declarations: proc collectCT(gch: var GcHeap; size: int) {.benign.} proc forAllChildren(cell: PCell, op: WalkOp) {.benign.} proc doOperation(p: pointer, op: WalkOp) {.benign.} proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.} # we need the prototype here for debugging purposes when defined(nimGcRefLeak): const MaxTraceLen = 20 # tracking the last 20 calls is enough type GcStackTrace = object lines: array[0..MaxTraceLen-1, cstring] files: array[0..MaxTraceLen-1, cstring] proc captureStackTrace(f: PFrame, st: var GcStackTrace) = const firstCalls = 5 var it = f i = 0 total = 0 while it != nil and i <= high(st.lines)-(firstCalls-1): # the (-1) is for the "..." entry st.lines[i] = it.procname st.files[i] = it.filename inc(i) inc(total) it = it.prev var b = it while it != nil: inc(total) it = it.prev for j in 1..total-i-(firstCalls-1): if b != nil: b = b.prev if total != i: st.lines[i] = "..." st.files[i] = "..." inc(i) while b != nil and i <= high(st.lines): st.lines[i] = b.procname st.files[i] = b.filename inc(i) b = b.prev var ax: array[10_000, GcStackTrace] proc ni
discard """
file: "tasyncawait.nim"
cmd: "nimrod cc --hints:on $# $#"
output: "5000"
"""
import asyncio2, sockets2, net, strutils
var disp = newDispatcher()
var msgCount = 0
const
swarmSize = 50
messagesToSend = 100
var clientCount = 0
proc sendMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
for i in 0 .. <messagesToSend:
discard await disp.send(client, "Message " & $i & "\c\L")
proc launchSwarm(disp: PDispatcher, port: TPort): PFuture[int] {.async.} =
for i in 0 .. <swarmSize:
var sock = socket()
#disp.register(sock)
discard await disp.connect(sock, "localhost", port)
when true:
discard await sendMessages(disp, sock)
sock.close()
else:
# Issue #932: https://github.com/Araq/Nimrod/issues/932
var msgFut = sendMessages(disp, sock)
msgFut.callback =
proc () =
sock.close()
proc readMessages(disp: PDispatcher, client: TSocketHandle): PFuture[int] {.async.} =
while true:
var l