Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Complete the following GC functions mmInit, mmAllocate, mmCollect, mmMark, mmAss

ID: 3869890 • Letter: C

Question

Complete the following GC functions mmInit, mmAllocate, mmCollect, mmMark, mmAssoc.

header file:

-----------

Driver File

infinite loop. This code has to understand metadata to know where the pointers are located void mmCollect(StorageManager .pMgr. MMResult +pm nResult) This is the third subphase of Garbage Collection. In this phase, you will sequentially traverse the heap, collecting the 'C' nodes, combining adjacent 'C' nodes, and placing the nodes onto a new free list. Each insertion will be to the front of the free list. As you collect free space, print one of the two following messages: printf(eCollecting %O8IXm". ULAddr(Candidate)) printf("cCombining %08IX with %O81Xm" ULAddripPrecedes), ULAddr(pCandidate)) void mmASsoC(Storage Manager pMgr, void pUserData From,char szAttrName sets a user pointer in the specified user data node to a new referenced user data node. Search for the specified attribute name in the meta data for the from node. If not found, set the pmmResult->rc to RC_ASSOC_ATTR NOT_FOUND, provide an error message that contains the attribute name, and return. (Ignore the remaining bullets.) If the specified attribute is not apointer, set the pmmResult->rc to RC_ASSOC_ATTR NOT_PTR provide an error message that contains the attribute name, and return. (Ignore the remaining bullets.) Change the user pointer in the specified user data node to point to the new referenced user data node or NULL (if that was specified Hint: once you know the offset in the user data: void *.ppNode = (void * *)&(plnUseFromxbDatalpAttr.>shOffset!); ppNode-pUserDataTo;

Explanation / Answer

Driver.c

-----------------------------------------------------------------------------

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <stdarg.h>

#include "cs3723p1.h"

#define MAX_TOKEN_SIZE 50                     // largest token size for tokenizer

#define MAX_BUFFER_SZ 100       // size of input buffer

// prototypes only used by the driver

void processCommands(StorageManager *pMgr, FILE *pfileCommand);

int getSimpleToken(char szInput[], const char szDelims[]

, int *piBufferPosition, char szToken[]);

void setData(StorageManager *pMgr, short shNodeType, char szInput[], char sbData[]);

void initMetadata(StorageManager *pMgr);

void printMeta(StorageManager *pMgr);

// If on Windows, don't use extern "C" in calling file.

// g++ compiler requires the extern "C".

#if defined(_WIN32) || defined(_WIN64)

extern void *getHash(const char *szKey);

extern void putHash(const char *szKey, void *value);

extern void eraseAll();

extern void getAll(HashMO *pHashMO);

#else

extern "C" void *getHash(const char *szKey);

extern "C" void putHash(const char *szKey, void *value);

extern "C" void eraseAll();

extern "C" void getAll(HashMO *pHashMO);

#endif

int main(int argc, char *argv[])

{

StorageManager storageManager;

// Set up the storage manager and our metadata

smInit(&storageManager);

initMetadata(&storageManager);

// Print the metadata

printMeta(&storageManager);

// Process commands for manipulating user data nodes

processCommands(&storageManager, stdin);

free(storageManager.pBeginStorage);

printf(" ");

return 0;

}

#define HEAP_SIZE 900

void smInit(StorageManager *pMgr)

{

pMgr->pBeginStorage = (char *)malloc(HEAP_SIZE);

if (pMgr->pBeginStorage == NULL)

errExit("%s", "malloc failed to allocate heap ");

pMgr->iHeapSize = HEAP_SIZE;

pMgr->pEndStorage = pMgr->pBeginStorage + HEAP_SIZE;

pMgr->pFreeHead = NULL;

// The minimum node size is the size of a minimum free node.

// This is 12 bytes on 32-bit or 16 bytes on 64 bit

// 2 byte - shNodeSize

// 2 byte - shNodeType

// 1 byte - cGC

// 3 slack bytes

// 4 or 8 byte pointer to the next free node.

pMgr->iMinimumNodeSize = sizeof(FreeNode);

// Invoke student's mmInit to initialize the free list and a huge free node

mmInit(pMgr);

}

void initMetadata(StorageManager *pMgr)

{

#define SHCUST 0   // node type for Customer

#define SHLINE 1   // node type for LineItem

// The following macro gives values to the size and offset attributes

#define SIZE_OFFSET(ptr,attr)

((short)sizeof(attr)), (short)(((char *)&attr) - ((char *) ptr))

struct LineItem

{

char szProductId[10];

int iQtyRequest;

double dCost;

struct LineItem *pNextItem;

} lineItem;

struct Customer

{

char szCustomerId[8];

char szName[16];

struct LineItem *pFirstItem;

struct Customer *pNextCustomer;

double dBalance;

} customer;

char *pCustomer = (char *)&customer;

char *pLineItem = (char *)&lineItem;

int iN = 0;

// nodeTypeM contains metadata about each node type which will be copied to storage manager

NodeType nodeTypeM[MAX_NODE_TYPE] =

{

{ "Customer", 0, sizeof(struct Customer) }

, { "LineItem", 5, sizeof(struct LineItem) }

, { "", 0 } // sentinel

};

// metaAttrM contains metadata about each user data attribute which will be copied

// to storage manager. This is using the excellent initialization capability of C.

MetaAttr metaAttrM[MAX_NODE_ATTR] =

{

{ SHCUST, "customerId", 'S', SIZE_OFFSET(pCustomer, customer.szCustomerId) }

, { SHCUST, "name", 'S', SIZE_OFFSET(pCustomer, customer.szName) }

, { SHCUST, "pFirstItem", 'P', SIZE_OFFSET(pCustomer, customer.pFirstItem) }

, { SHCUST, "pNextCust", 'P', SIZE_OFFSET(pCustomer, customer.pNextCustomer) }

, { SHCUST, "balance", 'D', SIZE_OFFSET(pCustomer, customer.dBalance) }

, { SHLINE, "productId", 'S', SIZE_OFFSET(pLineItem, lineItem.szProductId) }

, { SHLINE, "iQtyReq", 'I', SIZE_OFFSET(pLineItem, lineItem.iQtyRequest) }

, { SHLINE, "dCost", 'D', SIZE_OFFSET(pLineItem, lineItem.dCost) }

, { SHLINE, "pNextItem", 'P', SIZE_OFFSET(pLineItem, lineItem.pNextItem) }

, { -1, "END_OF_ATTR" } // sentinel

};

memcpy(pMgr->nodeTypeM, nodeTypeM, sizeof(nodeTypeM));

memcpy(pMgr->metaAttrM, metaAttrM, sizeof(metaAttrM));

}

void printMeta(StorageManager *pMgr)

{

int iN;         // subscript in nodeTypeM array

int iAt;        // subscript in metaAttrM array

printf("Metadata ");

printf("%-10s %-12s %8s ", "Node Type", "Beg Attr Sub", "Total Sz");

// Loop for each node type. The end is marked by a name which is an empty string.

for (iN = 0; pMgr->nodeTypeM[iN].szNodeTypeNm[0] != ''; iN++)

{

printf("%-10s %4d%8s %4d "

, pMgr->nodeTypeM[iN].szNodeTypeNm

, pMgr->nodeTypeM[iN].shBeginMetaAttr

, " "

, pMgr->nodeTypeM[iN].shNodeTotalSize);

printf(" %-14s %-4s %-6s %-4s "

, "Attribute Name"

, "Type"

, "Offset"

, "Size");

// The attributes for the node type begin at its shBeginMetaAttr subscript and continue while

// the shNodeType is this node's node type (which is the node type's subscript in

// the nodeTypeM array).

for (iAt = pMgr->nodeTypeM[iN].shBeginMetaAttr; pMgr->metaAttrM[iAt].shNodeType == iN; iAt++)

{

printf(" %-14s   %c %6i %4i "

, pMgr->metaAttrM[iAt].szAttrName

, pMgr->metaAttrM[iAt].cDataType

, pMgr->metaAttrM[iAt].shOffset

, pMgr->metaAttrM[iAt].shSizeBytes);

}

}

}

void processCommands(StorageManager *pMgr, FILE *pfileCommand)

{

// variables for command processing

char szInputBuffer[MAX_BUFFER_SZ+1];    // input buffer for a single text line

char szCommand[MAX_TOKEN_SIZE + 1];     // command

int bGotToken;                          // TRUE if getSimpleToken got a token

int iBufferPosition;                    // This is used by getSimpleToken to

// track parsing position within input buffer

// variables used for the buffer passed to hexdump

int iBytesPerLine = 40;                 // number of bytes to be displayed per line

// by hexDump

int iScanfCnt;                          // number of values returned by sscanf

int iBytesToSend = 0;                   // number of bytes sent to hexDump

int iLines = 0;                         // number of lines returned from hexDump

MMResult mmResult = { 0, "" };

// get command data until EOF

while (fgets(szInputBuffer, MAX_BUFFER_SZ, pfileCommand) != NULL)

{

// if the line is just a line feed, ignore it

if (szInputBuffer[0] == ' ')

continue;

// get the command

iBufferPosition = 0;                // reset buffer position

bGotToken = getSimpleToken(szInputBuffer, " ", &iBufferPosition, szCommand);

if (! bGotToken)

errExit("Invalid command: %s", szInputBuffer);

// see if the command is a comment

if (szCommand[0]== '*')

{

printf("%s", szInputBuffer);

continue;       // it was just a comment

}

memset(&mmResult, '', sizeof(mmResult)); // in case the mm functions didn't

printf(">>> %s", szInputBuffer);

if (strcmp(szCommand, "ALLOC") == 0)

{   // ALLOC key nodeTypeNm val1, val2, ...

char szKey[MAX_KEY_SIZE + 1];

char szNodeTypeNm[MAX_STRING + 1];

char szRemainingInput[MAX_DATA_SZ + 1]; // Used for a node's data values

char sbData[MAX_DATA_SZ];

void *pUserData = NULL;

iScanfCnt = sscanf(&szInputBuffer[iBufferPosition]

, "%10s %10s %100[^ ]"

, szKey

, szNodeTypeNm

, szRemainingInput);

if (iScanfCnt < 3)

errExit("Invalid ALLOC argument; only %d valid values Input is %s"

, iScanfCnt, szInputBuffer);

// get the node type (i.e., subscript in the nodeTypeM array

short shNodeType = findNodeType(pMgr, szNodeTypeNm);

if (shNodeType == NOT_FOUND)

errExit("ALLOC command has invalid node type = '%s'", szNodeTypeNm);

short shSize = pMgr->nodeTypeM[shNodeType].shNodeTotalSize;

// Set up the data attributes in the user data

setData(pMgr, shNodeType, szRemainingInput, sbData);

// Invoke the memory manager allocate function

pUserData = mmAllocate(pMgr, shSize, shNodeType, sbData, &mmResult);

// If it allocated memory, record the key and pointer in the hash table

if (pUserData != NULL)

{   // they gave it memory, confirm that the pointer is a user pointer

InUseNode *pInUse;

if ((char *)pUserData < pMgr->pBeginStorage || (char *)pUserData >= pMgr->pEndStorage)

errExit("mmAllocate returned a pointer outside of heap range");

pInUse = (InUseNode *)((char *)pUserData - NODE_OVERHEAD_SZ);

if (pInUse->cGC != 'U')

errExit("mmAllocate returned a pointer which has a cGC not equal to 'U'");

// Must be ok

putHash(szKey, pUserData); // record where it was placed

}

else

{    // Did not allocate memory

printf(" !!! Memory not allocated ");

printf(" smAllocate rc=%d, %s "

, mmResult.rc

, mmResult.szErrorMessage);

}

}

else if (strcmp(szCommand, "DEREF") == 0)

{   // FREE key

char szKey[MAX_KEY_SIZE + 1];

char szNULL[MAX_STRING + 1] = "";

// get the key from the input

iScanfCnt = sscanf(&szInputBuffer[iBufferPosition]

, "%10s"

, szKey);

// was the key in it?

if (iScanfCnt < 1)

errExit("Invalid DEREF argument; only %d valid values Input is %s"

, iScanfCnt, szInputBuffer);

// Set the reference in the hash table to NULL.

putHash(szKey, NULL);

}

else if (strcmp(szCommand, "ASSOC") == 0)

{   // ASSOC keyFrom attrName keyTo

char szKeyFrom[MAX_KEY_SIZE + 1];

char szKeyTo[MAX_KEY_SIZE + 1];

char szAttrNm[MAX_STRING + 1];

void *pUserFromData = NULL;

void *pUserToData = NULL;

iScanfCnt = sscanf(&szInputBuffer[iBufferPosition]

, "%10s %10s %10s"

, szKeyFrom

, szAttrNm

, szKeyTo);

if (iScanfCnt < 3)

errExit("Invalid ASSOC argument; only %d valid values Input is %s"

, iScanfCnt, szInputBuffer);

// get the user address of the from

pUserFromData = (char *)getHash(szKeyFrom);

if (pUserFromData == NULL)

{

printf("*** getHash for 'from' returned NULL ");

continue;

}

// get the user address of the to

pUserToData = (char *)getHash(szKeyTo);

if (pUserToData == NULL)

{

printf("*** getHash for 'to' returned NULL ");

continue;

}

mmAssoc(pMgr, pUserFromData, szAttrNm, pUserToData, &mmResult);

if (mmResult.rc != 0)

{

printf(" mmAssoc rc=%d, %s "

, mmResult.rc

, mmResult.szErrorMessage);

}

}

else if (strcmp(szCommand, "GCOLL") == 0)

{ // Garbage Collection Process

garbageCollection(pMgr, &mmResult);

}

else if (strcmp(szCommand, "DUMP") == 0)

smDump(pMgr);

else if (strcmp(szCommand, "PRTNODE") == 0)

{   // PRTNODE key

char szKey[MAX_KEY_SIZE + 1];

char *pUserData;

// get the key from the input

iScanfCnt = sscanf(&szInputBuffer[iBufferPosition]

, "%10s"

, szKey);

// was the key in it?

if (iScanfCnt < 1)

errExit("Invalid PRTNODE argument; only %d valid values Input is %s"

, iScanfCnt, szInputBuffer);

// get the address to user data

pUserData = (char *)getHash(szKey);

if (pUserData == NULL)

{

printf("*** getHash returned NULL ");

continue;

}

else

printNode(pMgr, pUserData);

}

else if (strcmp(szCommand, "PRTALL") == 0)

{ // Print all the nodes having a reference in the hash table

printAll(pMgr);

printf(" ");

}

else

errExit("Invalid command: '%s'", szCommand);

}

printf(" ");   // good place for a breakpoint

}

short findNodeType(StorageManager *pMgr, char szNodeTypeNm[])

{

int iN;

// Loop for each node type. The end is marked by a name which is an empty string.

for (iN = 0; pMgr->nodeTypeM[iN].szNodeTypeNm[0] != ''; iN++)

{

if (strcmp(pMgr->nodeTypeM[iN].szNodeTypeNm, szNodeTypeNm) == 0)

return iN;

}

return NOT_FOUND;

}

void setData(StorageManager *pMgr, short shNodeType, char szInput[], char sbData[])

{

int iAt;                        // control variable representing subscript in metaAttrM

char szToken[MAX_STRING];       // token returned by getSimpleToken

int iBufferPos = 0;             // current buffer position used by getSimpleToken

MetaAttr *pAttr;                // slightly simplifies referencing item in metaAttrM

int iScanfCnt;                  // returned by sscanf

int iValue;                     // integer value when attribute is an int

double dValue;                  // double value when attribute is a double

char *pszMemAtOffset;           // pointer into user data if this attribute is a string

int *piMemAtOffset;             // pointer into user data if this attribute is an int

void **ppNode;                  // pointer into user data if this attribute is a pointer

double *pdMemAtOffset;          // pointer into user data if this attribute is a double

int iLen;                       // helps with checking too long of a string value

// zero out the user data

memset(sbData, '', pMgr->nodeTypeM[shNodeType].shNodeTotalSize);

// Loop through each of the user data's attributes. The subscripts start with

// shBeginMetaAttr from nodeTypeM and end when the corresponding metaAttr's node type is

// different.

for (iAt = pMgr->nodeTypeM[shNodeType].shBeginMetaAttr; pMgr->metaAttrM[iAt].shNodeType == shNodeType; iAt++)

{

pAttr = &(pMgr->metaAttrM[iAt]);   // slightly simplify the reference in the metaAttrM array

// get the next token from the input

if (!getSimpleToken(szInput, ", ",&iBufferPos, szToken))

return;

// set the data based on the attribute data type

switch (pAttr->cDataType)

{

case 'P': // pointer

// The value in the data must state NULL

if (strcmp(szToken, "NULL")!= 0)

errExit("Invalid ALLOC command argument: '%s'", szToken);

// get the attribute's address based on its offset

ppNode = (void **) &(sbData[pAttr->shOffset]);

*ppNode = NULL;                 // assign it NULL

break;

case 'S': // char string

// check for too long of a value

iLen = strlen(szToken);

if (iLen > pAttr->shSizeBytes - 1)

errExit("Invalid ALLOC command argument, value too long: '%s'", szToken);

// get the attribute's address based on its offset

pszMemAtOffset = (char *) &(sbData[pAttr->shOffset]);

strcpy(pszMemAtOffset, szToken);

break;

case 'I': // int

// Convert the token to an int

iScanfCnt = sscanf(szToken, "%d", &iValue);

if (iScanfCnt < 1)

errExit("Invalid ALLOC command argument, not an int: '%s'", szToken);

// get the attribute's address based on its offset

piMemAtOffset = (int *) &(sbData[pAttr->shOffset]);

*piMemAtOffset = iValue;

break;

case 'D': // double

// Convert the token to a double

iScanfCnt = sscanf(szToken, "%lf", &dValue);

if (iScanfCnt < 1)

errExit("Invalid ALLOC command argument, not an double: '%s'", szToken);

// get the attribute's address based on its offset

pdMemAtOffset = (double *)&(sbData[pAttr->shOffset]);

*pdMemAtOffset = dValue;

break;

default:

errExit("Invalid data type '%c' for attribute named '%s'"

, pAttr->cDataType

, pAttr->szAttrName);

}

}

}

void smDump(StorageManager *pMgr)

{

int iBytesToSend;

int iBytesPerLine = 20;

char *pCh;

short shTempSize;

InUseNode *pAlloc;

FreeNode *pFree;

// Print each item from the beginning of the heap to the end

printf(" %-8s %-5s %4s %8s ", "Address", "Mem", "Size", "NodeType");

for (pCh = pMgr->pBeginStorage; pCh < pMgr->pEndStorage; pCh += shTempSize)

{

pAlloc = (InUseNode *)pCh;

shTempSize = pAlloc->shNodeSize;

// Change the output based on the cGC type

switch (pAlloc->cGC)

{

case 'F':

// It is a free item

printf(" %08lX %-5s %4d "

, ULAddr(pAlloc), "Free", shTempSize);

pFree = (FreeNode *)pAlloc;

printf(" Next:%08lX", ULAddr(pFree->pFreeNext));

// check for bad pFreeNext pointer

if ( pFree->pFreeNext != NULL &&

((char *)pFree->pFreeNext) < pMgr->pBeginStorage

|| ((char *) pFree->pFreeNext) > pMgr->pEndStorage )

printf(" *** next pointer is outside of heap ");

else

printf(" ");

break;

case 'U':

// It is in use

printf(" %08lX %-5s %4d   %d "

, ULAddr(pAlloc), "InUse", shTempSize, pAlloc->shNodeType);

iBytesToSend = shTempSize - NODE_OVERHEAD_SZ;

if (iBytesToSend > HEAP_SIZE)

iBytesToSend = HEAP_SIZE; // checking bad node size

hexDump(pCh + NODE_OVERHEAD_SZ, iBytesToSend, iBytesPerLine);

break;

case 'C':

// It is a candidate

printf(" %08lX %-5s %4d "

, ULAddr(pAlloc), "Cand", shTempSize);

iBytesToSend = shTempSize - NODE_OVERHEAD_SZ;

if (iBytesToSend > HEAP_SIZE)

iBytesToSend = HEAP_SIZE; // checking bad node size

hexDump(pCh + NODE_OVERHEAD_SZ, iBytesToSend, iBytesPerLine);

break;

default:

// It is unknown

printf(" %08lX %-5s %4d *** unknown cGC "

, ULAddr(pAlloc), "Unk", shTempSize);

iBytesToSend = shTempSize - NODE_OVERHEAD_SZ;

if (iBytesToSend > HEAP_SIZE)

iBytesToSend = HEAP_SIZE; // checking bad node size

hexDump(pCh + NODE_OVERHEAD_SZ, iBytesToSend, iBytesPerLine);

}

if (shTempSize <= 0)

errExit("shNodeSize is zero or negative");

}

}

void printAll(StorageManager *pMgr)

{

int i;

void *pUserData;

HashMO hashMO;

// get the hash table entries as an array

getAll(&hashMO);

// Iterate through the entire hash table

for (i = 0; i < hashMO.iNumEntries; i += 1)

{

pUserData = hashMO.entryM[i].pUserData;

// Print the node if the hash value is not NULL

if (pUserData != NULL)

printNode(pMgr, pUserData);

}

}

void garbageCollection(StorageManager *pMgr, MMResult *pmmResult)

{

int i;

void *pUserData;

HashMO hashMO;

// mark all nodes as candidates ('C') for collection

mmMark(pMgr, pmmResult);

if (pmmResult->rc != 0)

{

printf(" mmMark rc=%d, %s "

, pmmResult->rc

, pmmResult->szErrorMessage);

return;

}

// To get the references, we need the contents of the hash table.

// In most GC solutions, we would get the entries from either the

// runtime memory stack or (in the case of Python) a hash table.

getAll(&hashMO);

// go through the array of hash entries, calling mmFollow

for (i = 0; i < hashMO.iNumEntries; i += 1)

{

pUserData = hashMO.entryM[i].pUserData;

if (pUserData != NULL)

{   // mark any reachable nodes as in use ('U')

mmFollow(pMgr, pUserData, pmmResult);

if (pmmResult->rc != 0)

{

printf(" mmFollow rc=%d, %s "

, pmmResult->rc

, pmmResult->szErrorMessage);

return;

}

}

}

// Collect all the candidate entries as free.

mmCollect(pMgr, pmmResult);

if (pmmResult->rc != 0)

{

printf(" mmCollect rc=%d, %s "

, pmmResult->rc

, pmmResult->szErrorMessage);

return;

}

}

/*

** This Hex Dump can be used instead of calling the real

** hexDump from smDump when using Visual Studio. Rename this to hexDump.

** Please remember to remove it when you run your code on a fox server.

*/

int dumbHexDump(char *sbBuffer, int iBufferLength, int iBytesPerLine)

{

printf(" , %s", sbBuffer); // print the data

return 1;               // arbitrary value and meaningless in this case

}

/*

** This is the dumb version of print node which can be used instead

** of calling the real printnode. Rename this to printNode.

** Please remember to remove it when you run your code on a fox server.

*/

void dumbPrintNode(StorageManager *pMgr, void *pUserData)

{

InUseNode *pAlloc = (InUseNode *)(((char *)pUserData) - 2 * sizeof(short) - 1);

printf(" %-14s %-4s %-9s %-14s ", "Alloc Address", "Size", "Node Type", "Data Address");

printf(" %p      %4i %6i    %08lX ", pAlloc

, pAlloc->shNodeSize, pAlloc->shNodeType, ULAddr(pUserData));

printf("dumb print");

}

int getSimpleToken(char szInput[], const char szDelims[]

, int *piBufferPosition, char szToken[])

{

int iDelimPos;                      // found position of delim

int iCopy;                          // number of characters to copy

// check for past the end of the string

if (*piBufferPosition >= (int) strlen(szInput))

{

szToken[0] = '';              // mark it empty

return FALSE;                   // no more tokens

}

// get the position of the first delim, relative to the iBufferPosition

iDelimPos = strcspn(&szInput[*piBufferPosition], szDelims);

// see if we have more characters than target token, if so, trunc

if (iDelimPos > MAX_TOKEN_SIZE)

iCopy = MAX_TOKEN_SIZE;             // truncated size

else

iCopy = iDelimPos;

// copy the token into the target token variable

memcpy(szToken, &szInput[*piBufferPosition], iCopy);

szToken[iCopy] = '';              // null terminate

// advance the position

*piBufferPosition += iDelimPos + 1;

return TRUE;

}

void errExit(const char szFmt[], ... )

{

va_list args;               // This is the standard C variable argument list type

va_start(args, szFmt);      // This tells the compiler where the variable arguments

// begins. They begin after szFmt.

printf("ERROR: ");

vprintf(szFmt, args);       // vprintf receives a printf format string and a

// va_list argument

va_end(args);               // let the C environment know we are finished with the

// va_list argument

printf(" ");

exit(99);

}

----------------------------------------------------------------------------------------------------------

cs3723p1.c

------------------------------------------------------------

#include "cs3723p1.h"

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

//ADD PMM RESULT TO EVERYTHING

void mmInit(StorageManager *pMgr){

pMgr->pFreeHead = (FreeNode *)pMgr->pBeginStorage;

memset(pMgr->pBeginStorage,'',pMgr->iHeapSize);

pMgr->pFreeHead->cGC = 'F';

pMgr->pFreeHead->shNodeSize = pMgr->iHeapSize;

pMgr->pFreeHead->pFreeNext = (FreeNode *)0;

}

void * mmAllocate(StorageManager *pMgr, short shDataSize, short shNodeType, char sbData[], MMResult *pmmResult)

{

char *errMsg; //temp pointer for error message

FreeNode *pPrev = (FreeNode *)0; //previous free node in free list

FreeNode *pCurr = pMgr->pFreeHead; //the current free node in the list

InUseNode *pNewNode = (InUseNode *)0; //enhance readability

short shDiff; //stores leftover space after allocation

int totalSize; //stores pNewNodes size

while(pCurr && (char *)pCurr < pMgr->pEndStorage) //traces through free node list

{

if(pCurr->shNodeSize >= (shDataSize + NODE_OVERHEAD_SZ)) //find a node large enough to fit another one

{

shDiff = pCurr->shNodeSize - (shDataSize + NODE_OVERHEAD_SZ); //check if there's enough space for an in use node + free node

if(shDiff >= pMgr->iMinimumNodeSize)

{

if(!pPrev)

pMgr->pFreeHead = pCurr->pFreeNext; //free node is in beginning of list

else

pPrev->pFreeNext = pCurr->pFreeNext; //free node is somewhere else in the list

totalSize = shDataSize + NODE_OVERHEAD_SZ;

//totalSize = shDataSize + iMinumumNodeSize;

pNewNode = (InUseNode *)pCurr;

pNewNode->cGC = 'U'; //user input mark node as in use

pNewNode->shNodeType = shNodeType;

pNewNode->shNodeSize = totalSize;

memcpy((void *)pNewNode->sbData, (void *)sbData, shDataSize);//allocate user node

//if enough space is left over for a free node make a new free node

pCurr = (FreeNode *)((char *)pCurr + totalSize);

pCurr->cGC = 'F'; //set current to Free

pCurr->shNodeSize = shDiff;

pCurr->pFreeNext = pMgr->pFreeHead;

pMgr->pFreeHead = pCurr; //insert free node at beginning of free list

} //end if

else{

if(!pPrev) //beginning of free list

pMgr->pFreeHead = pCurr->pFreeNext;

else

pPrev->pFreeNext = pCurr->pFreeNext;

pNewNode = (InUseNode *)pCurr;

pNewNode->cGC = 'U';

pNewNode->shNodeType = shNodeType;

memcpy((void *)pNewNode->sbData, (void *)sbData, shDataSize);

}//end else

return pNewNode->sbData;

}//end if large enough node

else

{

pPrev = pCurr;

pCurr = pCurr->pFreeNext;

}

}//end while

pmmResult->rc = RC_NOT_AVAIL;

errMsg = "Free node not found";

memcpy((void*)pmmResult->szErrorMessage, errMsg, strlen(errMsg)+1);

return (void *)0;

} //end mmAllocate

void mmMark(StorageManager *pMgr, MMResult *pmmResult){

char * cursor = NULL;

short shTempSize = 0;

for(cursor = pMgr->pBeginStorage;cursor < pMgr->pEndStorage;cursor += shTempSize)//increments the cursor by 1 byte

{

shTempSize = ((InUseNode *)cursor)->shNodeSize;

((InUseNode *)cursor)->cGC = 'C';

}

}

void mmFollow(StorageManager *pMgr, void *pUserData, MMResult *pmmResult){

if(!pUserData)

{

return;

}

InUseNode * pCurr;

int iAttr;

short shNodeType;

MetaAttr *pAttr;

void **pp;

pCurr = (InUseNode *)((char *)pUserData - NODE_OVERHEAD_SZ);

shNodeType = pCurr->shNodeType;

switch(pCurr->cGC)

{

case 'U':

return;

//break;

case 'C':

pCurr->cGC = 'U';

for(iAttr = pMgr->nodeTypeM[shNodeType].shBeginMetaAttr; pMgr->metaAttrM[iAttr].shNodeType == shNodeType; iAttr++)

{

pAttr = &(pMgr->metaAttrM[iAttr]);

if(pAttr->cDataType == 'P')

pp = (void **)&pCurr->sbData[pAttr->shOffset];

mmFollow(pMgr, *pp, pmmResult);

/*{

pp = (void **)&pCurr->sbData[]

}*/

}

break;

}

}

void mmCollect(StorageManager *pMgr, MMResult *pmmResult){

//sets free nodes to F from C

char * pCur;

char * pNext;

char * pPrev = (char *)0;

FreeNode * pNewNode;

short shTempSize;

int iTotalSize;

pMgr->pFreeHead = (FreeNode *)0;

pCur = pMgr->pBeginStorage;

while(pCur < pMgr->pEndStorage)

{

shTempSize = ((FreeNode *)pCur)->shNodeSize;

pNext = pCur + shTempSize;

if(((FreeNode *)pCur)->cGC == 'C')

{

if(pNext < pMgr->pEndStorage && ((FreeNode *)pNext)->cGC == 'C')

{

printf(" Combining %08lX with %08lX ", ULAddr(pCur), ULAddr(pNext));

pNewNode = (FreeNode *)pCur;

iTotalSize = ((FreeNode *)pCur)->shNodeSize + ((FreeNode *)pNext)->shNodeSize;

pNewNode->shNodeSize = iTotalSize;

}

else

{

printf(" Collecting %08lX ", ULAddr(pCur));

pNewNode = (FreeNode *)pCur;

pNewNode->cGC = 'F';

pNewNode->pFreeNext = (FreeNode *)pPrev;

pPrev = pCur;

pCur += shTempSize;

}

}

else

{

pCur += shTempSize;

}

}

pMgr->pFreeHead = (FreeNode *)pPrev;

}

/*void mmCollect(StorageManager *pMgr, MMResult *pmmResult)

{

char *pCurr;

char *pTrace;

char *pPrev = (char *)0;

FreeNode *pNewNode;

short shTempSize;

int totalSize;

pMgr->pFreeHead = (FreeNode *)0;

pCurr = pMgr->pBeginStorage;

while(pCurr < pMgr->pEndStorage)

{

shTempSize = ((FreeNode *)pCurr)->shNodeSize;

pTrace = pCurr + shTempSize;

if(((FreeNode *)pCurr)->cGC == 'C')

{

if(pTrace < pMgr->pEndStorage && ((FreeNode *)pTrace)->cGC == 'C')

{

printf(" Combining %08lX with %08lX ", ULAddr(pCurr), ULAddr(pTrace));

pNewNode = (FreeNode *)pCurr;

totalSize = ((FreeNode *)pCurr)->shNodeSize + ((FreeNode *)pTrace)->shNodeSize;

pNewNode->shNodeSize = totalSize;

}

else

{

printf(" Collecting %08lX ", ULAddr(pCurr));

pNewNode = (FreeNode *)pCurr;

pNewNode->cGC = 'F';

pNewNode->pFreeNext = (FreeNode *)pPrev;

pPrev = pCurr;

pCurr += shTempSize;

}

}

else

{

pCurr += shTempSize;

}

}

pMgr->pFreeHead = (FreeNode *)pPrev;

}*/

void mmAssoc(StorageManager *pMgr, void *pUserDataFrom, char szAttrName[], void *pUserDataTo, MMResult *pmmResult){

char *pUserNode;

MetaAttr *pAttr;

char *errMsg;

short shNodeType;

int iAt;

void **ppNode;

pUserNode = (char *)pUserDataFrom - NODE_OVERHEAD_SZ;

shNodeType = ((InUseNode *)pUserNode)->shNodeType;

for(iAt = pMgr->nodeTypeM[shNodeType].shBeginMetaAttr; iAt < MAX_NODE_ATTR && pMgr->metaAttrM[iAt].shNodeType == shNodeType; iAt++)

{

pAttr = &(pMgr->metaAttrM[iAt]);

if(strcmp(pAttr->szAttrName, szAttrName) == 0)

{

if(pAttr->cDataType == 'P')

{

ppNode = (void **)&(((InUseNode *)pUserNode)->sbData[pAttr->shOffset]);

*ppNode = pUserDataTo;

return;

}

else

{

pmmResult->rc = RC_ASSOC_ATTR_NOT_PTR;

sscanf(errMsg, "Attribute not a pointer: %s", szAttrName);

memcpy((void *)pmmResult->szErrorMessage, errMsg, strlen(errMsg)+1);

return;

}

}

}

pmmResult->rc = RC_ASSOC_ATTR_NOT_FOUND;

sscanf(errMsg, "Attribute not found: %s", szAttrName);

memcpy((void *)pmmResult->szErrorMessage, errMsg, strlen(errMsg)+1);

}

----------------------------------------------------------------------------------------------------------

cs3723p1.h

-------------------------------------------------------------------

#define TRUE 1

#define FALSE 0

#define MAX_KEY_SIZE 10                     // Maximum size of a key for Hash Table

#define MAX_MESSAGE_SIZE 100                // Maximum message size for smResult

#define MAX_STRING 30                       // Maximum size of strings like

// node type names, attribute names

#define MAX_NODE_TYPE 5                            // Maximum number of node types

#define MAX_NODE_ATTR 50                    // Maximum number of combined node attr

#define MAX_DATA_SZ 500                     // Maximum size of sbData

#define ERROR_PROCESSING 3                  // error during processing - exit value

#define MAX_HASH_ENTRIES 100                // Maximum number of hash entries

#define NOT_FOUND -1                        // Could not find name in metadata

// Errors returned in the rc of MMResult

#define RC_NOT_AVAIL 901            // There isn't any free memory to handle alloc request

#define RC_INVALID_ADDR 903         // Invalid address which isn't within heap

#define RC_ASSOC_ATTR_NOT_PTR 801   // Attribute name for ASSOC not a pointer attribute

#define RC_ASSOC_ATTR_NOT_FOUND 802 // Attribute name for ASSOC not found for the from node

// MetaAttr describes an attribute within a node type

typedef struct MetaAttr

{

short shNodeType;                      // Type of node

char   szAttrName[MAX_STRING+1];        // Name of the attribute

char   cDataType;                       // Data type: S - char string, P -Ptr, D - double, I - int

short shSizeBytes;                     // size in bytes including zero byte for strings

short shOffset;

}MetaAttr;

// NodeType describes one type of node

typedef struct NodeType

{

char szNodeTypeNm[MAX_STRING+1];

short shBeginMetaAttr;              // Subscript in metaAttrM of first attribute for

// this node type.

short shNodeTotalSize;

}NodeType;

// InUseNode represents an allocated node. The actual size of an allocated item may be much

// larger.

typedef struct InUseNode

{

short shNodeSize;                   // total size of the allocated item.

short shNodeType;                   // Node Type subscript.

char cGC;                          // Garbage Collection status byte has one of these

// values: F - free, C - candidate to free,

//          U - in use

char sbData[MAX_DATA_SZ];          // This is the user's data in the node. It might

// be bigger than MAX_STRING.

} InUseNode;

// Define the size of overhead in an InUseNode

#define NODE_OVERHEAD_SZ (sizeof(short)+sizeof(short)+1)

// FreeNode represent a free node. Note that an actual free node

// will occupt more than the size of this structure.

typedef struct FreeNode

{

short shNodeSize;                   // Total size of this free node.

short shNodeType;                   // Not used

char cGC;                          // Garbage Collection status byte has one of these

// values: F - free, C - candidate to free,

//          U - in use

struct FreeNode *pFreeNext;         // Points to next free node

} FreeNode;

// StorageManager is the primary structure used by this program.

typedef struct

{

int iHeapSize;                       // Total size of the heap memory being managed

int iMinimumNodeSize;                // The minimum size of any node.

char *pBeginStorage;                 // Beginning of the heap memory being managed

char *pEndStorage;                   // End address immediately after the heap memory

FreeNode *pFreeHead;                 // Head of the free list

NodeType nodeTypeM[MAX_NODE_TYPE];   // array of node types

MetaAttr metaAttrM[MAX_NODE_ATTR];   // array of attribute meta data

} StorageManager;

// This is returned by many of the mm functions via the parameter list.

typedef struct

{

int rc;                                // Return Code is 0 if it is normal. Otheriwise,

// it is not zero. See the defined constants.

char szErrorMessage[MAX_MESSAGE_SIZE + 1]; // If a problem is encountered, this should

// explain the error.

} MMResult;

// This is for returning one Hash Table entry pair

typedef struct

{

char szKey[MAX_KEY_SIZE + 1];           // the hash key

void *pUserData;                        // the entry contains just a ptr

} HashEntryPair;

// This is used to return the entire contents of the Hash Table

typedef struct

{

int iNumEntries;

HashEntryPair entryM[MAX_HASH_ENTRIES];

} HashMO;

// student functions

void * mmAllocate(StorageManager *pMgr

, short shDataSize, short shNodeType, char sbData[], MMResult *pmmResult);

void mmInit(StorageManager *pMgr);

void mmMark(StorageManager *pMgr, MMResult *pmmResult);

void mmFollow(StorageManager *pMgr, void *pUserData, MMResult *pmmResult);

void mmCollect(StorageManager *pMgr, MMResult *pmmResult);

void mmAssoc(StorageManager *pMgr

, void *pUserDataFrom, char szAttrName[], void *pUserDataTo, MMResult *pmmResult);

// Driver functions

void smPrintMeta(StorageManager *pMgr);

void smPrintFree(StorageManager *pMgr);

short findNodeType(StorageManager *pMgr, char szNodeTypeNm[]);

void smInit(StorageManager *pMgr);

void smDump(StorageManager *pMgr);

void garbageCollection(StorageManager *pMgr, MMResult *pmmResult);

void printAll(StorageManager *pMgr);

void errExit(const char szFmt[], ...);

// Larry provided .o versions of these functions.

// If you are running your code on Microsoft, you must use

// the dummy versions

void printNode(StorageManager *pMgr, void *pUserData);

int hexDump(char *psbBuffer, int iBufferLength, int iBytesPerLine);

// Simple macro for converting addresses to unsigned long

#if defined(_WIN32)

#define ULAddr(addr) ((unsigned long) addr)

#else

#define ULAddr(addr) (((unsigned long) addr)&0x00000000FFFFFFFF)

#endif

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote