MkKernel PACKAGE - Storage Management …
MkKernel PACKAGE - Storage Management …
Storage management is used in ccmkkernel to provide temporary storage. It is a common design pattern that ccmkkernel only returns a reference to the Internal-Temporary-Storage (ITS), so the Internal-Active-Storage (IAS) is not returned to the external end user. The ITS is a storage that is only used as a return value and nothing else. The temporary in ITS refers exclusively to the current state of the storage and not to the lifespan of the storage, the ITS is only allocated once at startup and then used again and again, similar to the static storage in C.
Internal ccmkkernel distinguishes three different storage sources:
The CLS and FLS have the same visibility to the end user and are explained together as FLS.
The RLS is not mentioned in this documentation section because the RLS is more internal than CLS and FLS.
The end-user uses a FLS reference like a normal local C++ variable but with the following restriction:
The "Dup" (duplicate) function is used to convert a temporary FLS variable into a global storage. The global storage is managed by the end user and may have to be released depending on the target programming language.
Example from server.cc
→ "ReadBFL" overwrite previous "ReadBFL"
void BFL2() { auto tmp1 = ReadBFL() ; // "tmp1" is now a reference to the FLS storage of "ReadBFL" auto tmp2 = ReadBFL() ; // ERROR: the "tmp2" is using a SHARED reference with "tmp1" Send("R","LL",tmp1,tmp2) ; // ERROR: "tmp1" and "tmp2" are the SAME values }
Example from server.cc
→ "ReadBFL" overwrite previous "ReadBFL" even in an "Event-Loop"
void pBFL3() { /* tmp2 = */ ReadBFL() ; // ERROR: the "tmp2" is using a SHARED reference with "tmp1" } void BFL3() { auto tmp1 = ReadBFL() ; // "tmp1" is now a reference to the FLS storage of "ReadBFL" Send("C",MqTokenICB(&Server::pBFL3),"ECOL:[III]",4,5,6) ; // ATTENTION: callback "pBFL3" using "ReadBFL" ProcessEvent(MQ_WAIT_OWN) ; // ERROR: enter event-loop, callback "pBFL3" is called Send("R","L",tmp1) ; // ERROR: "tmp1" has now the value from "tmp2" }
Example from server.cc
→ convert "ReadBFL" result into global storage using "Dup" and free later
void BFL4() { auto tmp1 = ReadBFL() ; // "tmp1" is now a reference to the FLS storage of "ReadBFL" auto glb1 = tmp1->Dup() ; // OK: "glb1" is now a UNSHARED reference to the global memory auto tmp2 = ReadBFL() ; // "tmp2" is now a reference to the FLS storage of "ReadBFL" Send("R","LL",glb1,tmp2) ; // OK: "glb1" (alias tmp1) and "tmp2" are separate references }
In the C language the TLS (Thread-Local-Storage) is unique per definition and the name is used to distinguish the storage.
The Problem is to create a TLS interface useable in all Target-Programming-Language (TPL) supported by the Programming-Language-Micro-Kernel (PLMK).
The *CreateTLS
style function return a TLS that is a global storage. global mean unique per runtime and not unique per definition. The tlsid (0,1,2,3...) is used to distinguish the storage on the global level.
Every
*CreateTLS
style function with the same tlsid return the same memory in the same thread.
There is always a risk that the memory used by the *CreateTLS
style of functions will also be used by another component of the software in the same thread.
*CreateTLS
style function with caution in a local (controlled) context. enum
Example from perfserver.cc
→ performance test with TLS storage in a local (controlled) context
void BUST () { auto bus = MkBufferStreamC::CreateTLS( "perfserver-BUST" ); while (ReadItemExists()) { bus->WriteBUF(ReadBUF()); } bus->PosToStart(); SendSTART(); while (bus->ReadItemExists()) { SendBUF(bus->ReadBUF()); } SendRETURN(); }
Example from LibSq3LiteRpcClient.tcl
→ callback dealing the temporary TLS data
# Intro : Example from tcl-rpc-client of using a CreateTLS-like function (here for MkBufferListC) # to improve code speed and readability. # # Problem : This function is used to invoke a callback (myCb). The arguments come from the argument # list args *and* from a service call (ReadBFL). # The problem is that ReadBFL is called *twice* and the *second* call overwrites the value # of the *first* call because CreateTLS always returns *the same* MkBufferListC, just # replaced with a new set of values. # # Solution : The MkBufferListC instance returned by ReadBFL is copied into another MkBufferListC # instance returned by CreateTLS. # The "CreateTLS" instance is only created *once* and reused, *but* now we can create as # many MkBufferListC instances as we want, because "CreateTLS" distinguishes the returned # instances by the string identifier. # WITHOUT "CreateTLS" a copy would have to be created (Dup) which would then be destroyed # *after* the callback is called (Delete) proc Sq3LiteRpcClientExecV2CB {rpc myCb args} { set valL [MkBufferListC CreateTLS "Sq3LiteRpcClientExecV2CB→valL"] set colL [MkBufferListC CreateTLS "Sq3LiteRpcClientExecV2CB→colL"] $valL Copy [$rpc ReadBFL] $colL Copy [$rpc ReadBFL] $myCb {*}$args $valL $colL }