mshare.cc

//*************************************************************************
//  MODULE : MSHARE - Shared Memory for Interprocess Communication module *
//  AUTHOR : Ron Chernich                                                 *
//  PURPOSE: This module contains the Kernel IPC functions to support 	  *
//	     named and anonynomous shared memory blocks.		  *
//  HISTORY:                                                              *
//    18-APR-94 First Version						  *
//*************************************************************************

#include "exec.hh"	    // related header
#include "kernel.hh"	    // can't put this in header due recursion


///////////////////////////////////////////////////////////////////////////
//	 Class Methods for Shared Memory Descriptor List Object
//-------------------------------------------------------------------------
// Constructor must Init the queue type (FIFO) .. destructor will
// cleanup any memory in use (in case of a dis-orderly shut-down)
//
QmMgr::QmMgr (void) : DblList(FALSE) { }

QmMgr::~QmMgr (void)
{
  PMS pMs = (PMS)DblGetHead();
  while (pMs) {
    delete pMs->pstName;
    DELETE_ARRAY pMs->pData;
    DblDelete();
    pMs = (PMS)DblGetHead();
  }
}

//////////////
// Walk the list looking for a block with the passed name
// RETURNS: TRUE  .. it exists (and is now "current")
//          FALSE .. never heard of it
//
BOOL QmMgr::QmExists (char *pszName, PMS *p)
{
  PMS pMs = (PMS)DblGetHead();
  while (pMs)
    if (*pMs->pstName == pszName) {
      *p = pMs;
      return TRUE;
    }
    pMs = (PMS)DblGetNext();
  return FALSE;
}

//////////////
// Walk the list looking for a block with the passed ID
// RETURNS: TRUE  .. it exists (and is now "current")
//          FALSE .. never heard of it
//
BOOL QmMgr::QmExists (UINT16 nFindID, PMS *p)
{
  PMS pMs = (PMS)DblGetHead();
  while (pMs)
    if (pMs->nID == nFindID) {
      *p = pMs;
      return TRUE;
    }
    pMs = (PMS)DblGetNext();
  return FALSE;
}

/////////////
// Increment the usage count of the passed list element (assumes that
// this call was preceeded by a successful call to  )
//
void QmMgr::QmIncCnt (UINT16 nTargID)
{
  PMS pMs = (PMS)DblGetHead();
  while (pMs)
    if (pMs->nID != nTargID)
      pMs = (PMS)DblGetNext();
    else {
      pMs->nCnt++;
      break;
    }
}

/////////////
// Decrement the usage count of the passed list element (assumes that
// this call was preceeded by a successful call to ). If the
// usage count becomes zero, delete the element. We flush the data to
// an unusual value to ease trapping bugs.
//
void QmMgr::QmDecCnt (UINT16 nTargID)
{
  PMS pMs = (PMS)DblGetHead();
  while (pMs) {
    if (pMs->nID == nTargID) {
      pMs->nCnt--;
      if (pMs->nCnt == 0) {
        memset(pMs->pData, 0xb2, (sizeof(UINT16) * pMs->nLen));
        delete pMs->pstName;
	DELETE_ARRAY pMs->pData;
        DblDelete();
      }
      break;
    }
    pMs = (PMS)DblGetNext();
  }
}

///////////////
// Create a new node for the list with an ID one greater than the last list
// node, with a data array of the passed size, giving it the passed name.
// The caller has validated that the name is unique and the size is
// greater than zero.
//
BOOL QmMgr::QmAdd (char *pszNew, UINT16 nSize)
{
  MSHARE mShare;
  PMS p = (PMS)DblGetTail();
  
  if (mShare.pData = new INT16[nSize]) {
    mShare.pstName = new Str(pszNew);
    if (mShare.pstName == NULL) {
      DELETE_ARRAY mShare.pData;
      return FALSE;
    }
    memset(mShare.pData, 0xa1, (sizeof(UINT16) * nSize));
    mShare.nID = ((p == NULL) ? 0 : p->nID) + 1;
    mShare.nCnt = 1;
    mShare.nLen = nSize;
    DblAppend((void*)&mShare, sizeof(MSHARE));
    return TRUE;
  }
  return FALSE;
}

////////////////
// Fetch the nth element of the passed shared memory block.
// RETURNS: TRUE  .. value returned by reference
//          FALSE .. bad ID or offset value
//
BOOL QmMgr::QmGet (UINT16 nID, UINT16 nOff, INT16 *pn)
{
  PMS pMs;
  if (QmExists(nID, &pMs))
    if (nOff < pMs->nLen) {
      *pn = *(pMs->pData + nOff);
      return TRUE;
    }
  return FALSE;
}

////////////////
// Set the nth element of the passed shared memory block.
// RETURNS: TRUE  .. previous value returned by reference
//          FALSE .. bad ID or offset value
//
BOOL QmMgr::QmPut (UINT16 nID, UINT16 nOff, INT16 *pn)
{
  PMS pMs;
  INT16 nTemp = *pn;
  
  if (QmExists(nID, &pMs))
    if (nOff < pMs->nLen) {
      *pn = *(pMs->pData + nOff);
      *(pMs->pData + nOff) = nTemp;
      return TRUE;
    }
  return FALSE;
}

////////////////
// Fetch the length of the referenced block
// RETURNS: TRUE  .. value returned by reference
//          FALSE .. bad ID or offset value
//
INT16 QmMgr::QmLength (UINT16 nID)
{
  PMS pMs;
  if (QmExists(nID, &pMs))
    return pMs->nLen;
  return -1;
}


///////////////////////////////////////////////////////////////////////////
//	   Kernel methods manage PID lists and PCI requests
//-------------------------------------------------------------------------
// Try to create a shared memory block with the passed name and length
// RETURNS: ID of block created (> 0), or
//          -1 if unable to create due param error or prior instance
//
INT16 Exec::SmCreate (char *psz, UINT16 nLen)
{
  PMS p;
  if (nLen && (ShareMem.QmExists(psz, &p) == FALSE)) {
    UINT16 nID = ShareMem.QmAdd(psz, nLen);
    if (nID > 0) {
      arrPCB[uCurProc].Share.DblAppend((void*)&nID, sizeof(UINT16));
      return nID;
    }
  }
  return -1;
}

////////////////
// Try to open the passed named memory block for the current process. If
// the process already has it open, ignore the request.
// RETURNS: ID of block opened (> 0), or
//          -1 block does not exist
//
INT16 Exec::SmOpen (char *psz)
{
  PMS p;
  
  if (ShareMem.QmExists(psz, &p)) {
    UINT16 *pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetHead());
    while (pOpen && (*pOpen != p->nID))
      pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetNext());
    if (pOpen == NULL) {
      ShareMem.QmIncCnt(p->nID);
      arrPCB[uCurProc].Share.DblAppend((void*)&p->nID, sizeof(UINT16));
      return p->nID;
    }
  }
  return -1;
}

/////////////////
// The passed PID wants (or has to) close the passed shared memory
// descriptor. Try to do so.
// RETURNS: Zero for success or -1 if ID unknown or not open for process
//
INT16 Exec::SmClose (UINT16 nProc, UINT16 nID)
{
  PMS p;
  
  if (ShareMem.QmExists(nID, &p)) {
    UINT16 *pOpen = (UINT16*)(arrPCB[nProc].Share.DblGetHead());
    while (pOpen)
      if (*pOpen != nID)
        pOpen = (UINT16*)(arrPCB[nProc].Share.DblGetNext());
      else {
        ShareMem.QmDecCnt(nID);
        arrPCB[nProc].Share.DblDelete();
        return 0;
      }
  }
  return -1;
}

////////////////////
// The current process wants to know the size of a shared memory block, so
// provided the ID is valid and the process has it open, tell it.
// RETURNS: size of block (in PLL/2 integers) or -1 for error.
//
INT16 Exec::SmLength (UINT16 nID)
{
  UINT16 *pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetHead());
  while (pOpen)
    if (*pOpen == nID)
      return ShareMem.QmLength(nID);
    else
      pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetNext());
  return -1;
}

/////////////
// If the current process has the passed block open and the passed offset is
// within bounds, set the value as requested.
// RETURNS: TRUE  .. value set
//          FALSE .. unable to set
//
BOOL Exec::SmWrite (UINT16 nID, UINT16 nOff, INT16 *pn)
{
  UINT16 *pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetHead());
  while (pOpen)
    if (*pOpen == nID)
      return ShareMem.QmPut(nID, nOff, pn);
    else
      pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetNext());
  return FALSE;
}

/////////////
// If the current process has the passed block open and the passed offset is
// within bounds, get the value as requested.
// RETURNS: TRUE  .. value set
//          FALSE .. unable to set
//
BOOL Exec::SmRead (UINT16 nID, UINT16 nOff, INT16 *pn)
{
  UINT16 *pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetHead());
  while (pOpen)
    if (*pOpen == nID)
      return ShareMem.QmGet(nID, nOff, pn);
    else
      pOpen = (UINT16*)(arrPCB[uCurProc].Share.DblGetNext());
  return FALSE;
}

/////////////////////////////////// eof ////////////////////////////////////