// // File: hzSSR.cpp // Purpose: Implimentation of the Small String Allocation and Management Regime. // // Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com) // // The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free // Software Foundation, either version 3 of the License, or any later version. // // The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses. //
// Please note: SSR functions are not intended for direct use in applications
#include <iostream> #include <stdarg.h>
#include "hzBasedefs.h" #include "hzTextproc.h" #include "hzProcess.h" #include "hzSSR.h"
//static _ssrRegime* s_pSSR ; // The one and only string regime
uchar* hzSSR::Xlate (uint32_t ssrAddr) { // Translate a 32-bit unsigned string address, to a pointer to an (encoded) string // // Argument: ssrAddr The address // // Returns: The encoded string OR // NULL if not located
_hzfunc("hzSSR::Xlate") ;
_ssrBloc* pBloc ; // Pointer to superblock uint64_t* pSeg ; // Data segment uint32_t blkNo ; // Offset within vector of blocks uint32_t slotNo ; // String slot within block
if (!ssrAddr) return 0 ;
slotNo = ssrAddr & 0xffff ; blkNo = (ssrAddr & SSR_BLOC_MASK) >> 16 ;
if (blkNo == 0 || blkNo > m_Super.Count()) { threadLog("CORRUPT: Cannot xlate address %u:%u. No such superblock (%u issued)\n", blkNo, slotNo, m_Super.Count()) ; return 0 ; }
pBloc = m_Super[blkNo-1] ; if (!pBloc) { threadLog("CORRUPT: No block found for address %u:%u. Total of %u superblocks issued)\n", blkNo, slotNo, m_Super.Count()) ; return 0 ; }
pSeg = pBloc->m_Space + slotNo ; return (uchar*) pSeg ; }
uint32_t hzSSR::Alloc (uint32_t nSize) { // Allocate memory from the memory regime if required size is 64 bytes or less and from the heap otherwise. Under the regime, allocation is // always from a freelist of segments of either 16,24,32,48 or 64 bytes. If the appropriate freelist is empty, a new block is allocated and // divided into multiple segments. // // Argument: nSize Total size required (including sting space meta data and null terminator) // // Returns: Pointer to the required string space. If is a fatal condition if this cannot be obtained.
_hzfunc("hzSSR::Alloc") ;
uint32_t ssrAddr = 0 ; // Address of string (block + slot) uint32_t nUnit ; // Number of 8-byte units required
// Check required size if (nSize >= 256) { threadLog("SIZE VIOLATION: Max size is 256 bytes\n") ; return 0 ; }
if (!nSize) return 0 ; nUnit = (nSize/8) + (nSize%8 ? 1:0) ;
_ssrBloc* pBloc = 0 ; // Pointer to superblock _ssrFLE* pSlot = 0 ; // Pointer to freelist slot uint64_t* pSeg = 0 ; // Pointer to segment
// Small string space (8 to 256 bytes) if (m_flistItem[nUnit-1]) { if (_hzGlobal_MT) m_lockItem[nUnit-1].LockWrite() ;
if (m_flistItem[nUnit-1]) { // Slot of the exact size is free so grab it
_hzGlobal_Memstats.m_strSm_u[nUnit-1]++ ; _hzGlobal_Memstats.m_strSm_f[nUnit-1]-- ; m_flistPopl[nUnit-1]-- ; m_nAllocOld++ ;
ssrAddr = m_flistItem[nUnit-1] ; if (!(ssrAddr & SSR_BLOC_MASK)) hzexit(E_CORRUPT, "Case 1 Illegal String Address %u:%u", (ssrAddr&0x7fff0000)>>16, ssrAddr&0xffff) ;
pSlot = (_ssrFLE*) Xlate(ssrAddr) ; if (!pSlot) hzexit(E_CORRUPT, "Illegal freelist (%d) string address %u:%u", nUnit-1, (ssrAddr&0x7fff0000)>>16, ssrAddr&0xffff) ;
// Since the slot is being allocated from the free list, it should contain its own address //if (pSlot->m_fleSelf != ssrAddr) if (pSlot->m_Blank[0] != 0xff) threadLog("CORRUPT: %u unit Slot in free list addr (%u:%u), points elsewhere\n", nUnit, (ssrAddr&0xffff0000)>>16, ssrAddr&0xffff) ;
m_flistItem[nUnit-1] = pSlot->m_fleNext ; memset(pSlot, 0, nUnit * 8) ; }
if (_hzGlobal_MT) m_lockItem[nUnit-1].Unlock() ;
if (ssrAddr) { //pBloc = m_Super[((ssrAddr & SSR_BLOC_MASK)>>16)-1] ; //pBloc->m_Alloc[ssrAddr&0xffff] = nSize-1 ; return ssrAddr ; } }
// No free slots so allocate from the top superblock if (_hzGlobal_MT) m_lockSbloc.LockWrite() ;
// Allocate new top superblock if needed if (!m_pTopBlock || ((m_pTopBlock->m_Usage + nUnit) > SSR_BLOC_SPACE)) { // Assign any remaining free space on the highest block to the small freelist of the size
// Then create a new highest block m_pTopBlock = pBloc = new _ssrBloc() ; memset(pBloc, 0, sizeof(_ssrBloc)) ;
//m_Super[m_nBloc] = pBloc ; m_Super.Add(pBloc) ; //m_nBloc++ ; //_hzGlobal_Memstats.m_numSblks = m_nBloc ;
pBloc->m_blkSelf = (m_Super.Count() << 16) ; pBloc->m_Usage = 0 ;
threadLog("CREATED SUPERBLOCK %u at %p\n", pBloc->m_blkSelf >> 16, pBloc) ; }
// Assign from the superblock free space pSeg = m_pTopBlock->m_Space + m_pTopBlock->m_Usage ; ssrAddr = m_pTopBlock->m_blkSelf + m_pTopBlock->m_Usage ; if (!(ssrAddr & SSR_BLOC_MASK)) hzexit(E_CORRUPT, "Case 2 Illegal String Address %u:%u", (ssrAddr&0x7fff0000)>>16, ssrAddr&0xffff) ;
//m_pTopBlock->m_Alloc[ssrAddr&0xffff] = nSize-1 ; m_pTopBlock->m_Usage += nUnit ; memset(pSeg, 0, nUnit * 8) ; _hzGlobal_Memstats.m_strSm_u[nUnit-1]++ ; m_nAllocNew++ ;
if (_hzGlobal_MT) m_lockSbloc.Unlock() ; return ssrAddr ; }
hzEcode hzSSR::Free (uint32_t strAddr, uint32_t nSize) { // Places object in freelist if it is of one of the precribed sizes, otherwise it frees it from the OS managed heap // // Arguments: 1) pMemobj A pointer to what is assumed to be string space to be freed // 2) nSize The size of the string space // // Returns: E_CORRUPT If no string item found at the supplied address or the stated size is zero // E_OK Operation successful
_hzfunc("hzSSR::Free") ;
static uint32_t _noCalls = 0 ;
//_ssrBloc* pBloc ; // Pointer to superblock _ssrFLE* pSlot ; // Item cast to _ssrFLE (to self point on free and to check it is not already free) //uint32_t blkNo ; // Offset within vector of blocks //uint32_t slotNo ; // String slot within block uint32_t nUnit ; // Number of 8-byte units in string being freed
// Increment call count _noCalls++ ;
// Check for null item if (!strAddr || !nSize) { if (!strAddr) threadLog("Warning: Cannot delete null item\n") ; if (!nSize) threadLog("Warning: Cannot delete zero size item\n") ;
return E_OK ; }
pSlot = (_ssrFLE*) Xlate(strAddr) ; if (!pSlot) return hzerr(E_CORRUPT, "WARNING freeing invalid obj %u:%u of size %u bytes\n", (strAddr & 0xffff0000)>>16, strAddr & 0xffff, nSize) ; if (pSlot->m_Blank[0] == 0xff) return hzerr(E_CORRUPT, "WARNING already deleted obj %u:%u of size %u bytes\n", (strAddr & 0xffff0000)>>16, strAddr & 0xffff, nSize) ;
//slotNo = strAddr & 0xffff ; //blkNo = (strAddr & SSR_BLOC_MASK) >> 16 ; //pBloc = m_Super[blkNo-1] ;
nUnit = (nSize/8) + (nSize%8 ? 1:0) ;
// Check that the stated address is compatible with the stated size /* if (pBloc->m_Alloc[slotNo] != (nSize-1)) { threadLog("TEST: CORRUPT: Address %u:%u has size %u, not %u\n", blkNo, slotNo, pBloc->m_Alloc[slotNo]+1, nSize) ; threadLog("Bad string address %u:%u (nocalls %u)\n", (strAddr&0x7fff0000)>>16, strAddr&0xffff, _noCalls) ; threadLog("Str value approx is [%s]\n", pItem->m_data + 3) ; return E_CORRUPT ; } */
if (_hzGlobal_MT) m_lockItem[nUnit-1].LockWrite() ;
pSlot->m_Blank[0] = 0xff ; pSlot->m_fleNext = m_flistItem[nUnit-1] ; m_flistItem[nUnit-1] = strAddr ; m_flistPopl[nUnit-1]++ ; m_nReleases++ ;
if (_hzGlobal_MT) m_lockItem[nUnit-1].Unlock() ; return E_OK ; }
void hzSSR::Report (hzChain& report) { _hzfunc("hzSSR::Report") ;
uint32_t n ; // Loop counter
if (!this) hzexit(E_CORRUPT, "No instance") ;
report.Clear() ;
report << "SSR Integrity Report\n" ; report.Printf("Live Item population: %s\n", FormalNumber(m_nLive)) ; report.Printf("Total allocations: %s\n", FormalNumber(m_nAllocNew + m_nAllocOld)) ; report.Printf("New allocs: %s\n", FormalNumber(m_nAllocNew)) ; report.Printf("Reallocations: %s\n", FormalNumber(m_nAllocOld)) ; report.Printf("Total releases (free) %s\n", FormalNumber(m_nReleases)) ; report << "Freelists\n" ;
for (n = 0 ; n < 32 ; n++) { if (m_flistItem[n] == 0 && m_flistPopl[n] == 0) continue ;
if (m_flistItem[n] && m_flistPopl[n]) { report.Printf("\tUnit %u: %s\n", n+1, FormalNumber(m_flistPopl[n])) ; continue ; }
//Z.Printf("\tError found for n=%u\n", n+1) ; report.Printf("\tUnit %u: Error free list addr %u, population %s\n", n+1, m_flistItem[n], FormalNumber(m_flistPopl[n])) ; }
//threadLog("SSR Integrity Report\n") ; //threadLog("Live Item population: %u\n", m_nLive) ; //threadLog("Total allocations: %u\n", (m_nAllocNew + m_nAllocOld)) ; //threadLog("New allocs: %u\n", m_nAllocNew) ; //threadLog("Reallocations: %u\n", m_nAllocOld) ; //threadLog("Total releases (free) %u\n", m_nReleases) ; //threadLog("Freelists\n") ;
/* for (n = 0 ; n < 32 ; n++) { if (m_flistItem[n] == 0 && m_flistPopl[n] == 0) continue ;
if (m_flistItem[n] && m_flistPopl[n]) { threadLog("\tUnit %u: %u\n", n+1, m_flistPopl[n]) ; continue ; }
threadLog("\tError found for n=%u\n", n+1) ; } */
//threadLog(Z) ; }