sharedMemPool is an alloc/dealloc module with an initial system alloc/dealloc call. The given chunk of sharedmem is split into parts of equal sizes according to the parameters given. suitable for zero-copy protocol stacks, custom buffering and memory layout
this implementation is without exceptions; it is threadsafe and no worker thread is spawned. It runs with or without GC. No memory allocation calls are performed within the implementation.
It could also be used to synchronise access of memory mapped I/O. In this case use the proc requestBufferBySlotNum to obtain the desired memory address (buffer initialisation should be turned off)
example (see tests for multithread examples) :
import sharedmempool let mempool = newSharedMemPool( SharedMemPoolBuffersize.b16 ,512, allocShared0(sharedmempool.calculateMemBufferSize( SharedMemPoolBuffersize.b16,512)), allocShared0(sharedmempool.getMemHelperBaseSize())) let tststring : string = "teststring" let (bufferptr,slotidOrErrno) = mempool.requestBuffer() if slotidOrErrno.isValid: echo $slotidOrErrno copyMem( bufferptr,unsafeAddr(tststring),tststring.len) var tst : ptr string = cast[ptr string](bufferptr) echo tst[] echo "buffers in use " & $mempool.getUsedBufferCount mempool.releaseBuffer(slotidOrErrno) echo "buffers in use after release " & $mempool.getUsedBufferCount mempool.deinitSharedMemPool deallocShared(mempool.getMemBufferBasePtr) deallocShared(mempool.getMemHelperBasePtr)
the maximum buffer count is 1024 ; the minimum buffsize is 1byte and the maximum segmentation is 4096kB
if no buffer is free while requesting for it, an errorcode is returned and the contention count is raised. this situation should never occur and it's the implementors task to finetune the buffer consumption. if a buffer is not needed anymore it should be pushed back to the pool immediately.
while requesting the buffer, the caller can specifiy a bitpattern the buffer is initialised with (optional; the default value is 0)
Types
SharedMemPoolErrno = enum slotNotOccupied = -9, offsetOutOfRange = -8, reservedErrno = -7, slotInUse = -6, invalidSlot = -5, outOfBuffer = -4, waitLimitExceed = -3, threadNotObjectsOwner = -2, genericError = -1
SharedMemPoolBuffersize = enum b01 = 1, b02 = 2, b04 = 4, b08 = 8, b16 = 16, b32 = 32, b64 = 64, b128 = 128, b256 = 256, b512 = 512, k1 = 1024, k2 = 2048, k4 = 4096, k8 = 8192, k16 = 16348, k32 = 32768, k64 = 65536, k128 = 131072, k256 = 262144, k512 = 524288, k1024 = 1048576, k2048 = 2097152, k4096 = 4194304
SharedMemPoolSlot = range[slotNotOccupied.int .. 1024.int]
- returntype which indicates error or contains the allocated slotnumber
SharedBufferHandle = tuple[sharedBufferPtr: pointer, slotidOrErrno: SharedMemPoolSlot]
- type returned by the allocation proc. if the operation was successful a slotid is returned (slotidOrErrno > -1 ). Otherwise it´s an errorcode (slotidOrErrno < 0). the isValid template should be used for the condition check
SharedMemPoolRef = ref SharedMemPool
SharedMemPoolPtr = ptr SharedMemPool
Consts
InvalidPointer: pointer = 0
Procs
proc newSharedMemPool(buffersize: SharedMemPoolBuffersize; buffercount: SharedMemPoolSlot; memBufferBasePtr: pointer; memHelperBasePtr: pointer): SharedMemPoolRef {...}{.raises: [], tags: [].}
- returns a new sharedMemPool
proc getMemBufferBasePtr(poolref: SharedMemPoolRef): pointer {...}{.raises: [], tags: [].}
- convenience proc to obtain the ptr of the memory buffer (dealloc)
proc getMemHelperBasePtr(poolref: SharedMemPoolRef): pointer {...}{.raises: [], tags: [].}
- convenience proc to obtain the ptr of the worker memory (dealloc)
proc getContentionCount(poolref: SharedMemPoolRef): int {...}{.raises: [], tags: [].}
- retrieves the contention count within the overall pool´s lifetime
proc getContentionCount(poolptr: SharedMemPoolPtr): int {...}{.raises: [], tags: [].}
- retrieves the contention count within the overall pool´s lifetime
proc getUsedBufferCount(poolref: SharedMemPoolRef): int {...}{.raises: [], tags: [].}
- returns the count of the currently allocated buffers (ref version)
proc getUsedBufferCount(poolptr: SharedMemPoolPtr): int {...}{.raises: [], tags: [].}
- returns the count of the currently allocated buffers (ptr version)
proc isSpawningThread(poolptr: SharedMemPoolPtr): bool {...}{.raises: [], tags: [].}
- returns true if objects context belongs to current thread
proc deinitSharedMemPool(poolref: SharedMemPoolRef) {...}{.raises: [], tags: [].}
- deinits the pool and frees resources. ensure that no ptr is in use anymore
proc requestBuffer(poolptr: SharedMemPoolPtr; fillval: int = 0; wipeBufferMem: bool = true): SharedBufferHandle {...}{.raises: [], tags: [].}
-
after returning the field slotidOrErrno indicates if the pointer is valid or not
if slotidOrErrno.isValid == false sharedBufferPointer contains InvalidPointer
proc requestBuffer(poolref: SharedMemPoolRef; fillval: int = 0; wipeBufferMem: bool = true): SharedBufferHandle {...}{.raises: [], tags: [].}
-
after returning the field slotidOrErrno indicates if the pointer is valid or not
if slotidOrErrno.isValid == false sharedBufferPointer contains InvalidPointer
proc requestBufferBySlotNum(poolptr: SharedMemPoolPtr; slotnum: SharedMemPoolSlot; fillval: int = 0; wipeBufferMem: bool = false): SharedBufferHandle {...}{. raises: [], tags: [].}
- requests a buffer by fixed slotnum. only suitable for memory mapped access
proc requestBufferBySlotNum(poolref: SharedMemPoolRef; slotnum: SharedMemPoolSlot; fillval: int = 0; wipeBufferMem: bool = false): SharedBufferHandle {...}{. raises: [], tags: [].}
- requests a buffer by fixed slotnum. only suitable for memory mapped access
proc releaseBuffer(poolptr: SharedMemPoolPtr; slotnum: SharedMemPoolSlot) {...}{. raises: [], tags: [].}
- marks the specified buffer as unused. if there are waiting threads a signal is fired
proc releaseBuffer(poolref: SharedMemPoolRef; slotnum: SharedMemPoolSlot) {...}{. raises: [], tags: [].}
- ref version
Funcs
func calculateMemBufferSize(buffersize: SharedMemPoolBuffersize; buffercount: SharedMemPoolSlot): int {...}{.raises: [], tags: [].}
- helper proc to get the total memory size needed
func getMemHelperBaseSize(): int {...}{.raises: [], tags: [].}
- helper proc to get the total memory size for the internals
Templates
template isValid(slotnum: SharedMemPoolSlot): bool
- checks if the specified slotnum is valid or contains an errorcode (< 0)
template slotnum2BufferPointer(poolptr: SharedMemPoolPtr; slotnum: SharedMemPoolSlot; offset: int = 0): pointer
- convenience template to obtain a buffer from the specified slotId. InvalidPointer is returned if the offset does not match the buffer´s context (bounds check)
template handle2BufferPointer(poolptr: SharedMemPoolPtr; handle: SharedBufferHandle; offset: int = 0): pointer
- convenience template to obtain a buffer from the specified handle. InvalidPointer is returned if the offset does not match the buffer´s context (bounds check)