Niezawodność Oprogramowania, rdodB, 1


B0x08 graphic

Podprogramy zarządzania pamięcią

Kod zamieszczony w niniejszym dodatku stanowi implementację prostego systemu rejestrującego operacje związane z dynamicznym zarządzaniem pamięcią — przydział, zwalnianie i realokację bloków oraz kontrolę odwołań do nich. System zrealizowany został na podstawie jednokierunko­wej listy łączonej, której każdy element reprezentuje jeden dynamicznie przydzielony blok wraz z jego podstawowymi atrybutami — adresem początku i rozmiarem. Poszczególne elementy tworzone są za pomocą funkcji malloc i dla prostoty wstawiane na początku listy — kolejność poszczególnych bloków w liście nie jest bowiem istotna.

Być może implementacja ta nie jest specjalnie efektywna — bardziej zaawansowana struktura z rodzaju B-drzewa, czy drzewa AVL z pewnością byłaby tu bardziej odpowiednia — jednak podstawowym celem niniejszego dodatku jest przedstawienie podstawowych koncepcji zarządzania pamięcią i efektywność nie jest tu czynnikiem decydującym.

block.h

#ifdef DEBUG

/* ------------------------------------------------------

* blockinfo jest strukturą zawierającą informację o przydzielonym

* bloku pamięci. Każdy przydzielony blok posiada swą reprezentację

* w postaci bloku blockinfo w kronice przydziału pamięci

*/

typedef struct BLOCKINFO

{

struct BLOCKINFO *pbiNext;

byte *pb; /* początek bloku */

size_t size; /* rozmiar bloku */

flag fReferenced /* było odwołanie do bloku? */

} blockinfo;

flag fCreateBlockInfo(byte *pbNew, size_t sizeNew);

void FreeBlockInfo(byte *pbToTree);

void UpdateBlockInfo(byte *pbOld, byte *pbNew, size_t sizeNew);

size_t sizeofBlock(byte *pb);

void ClearMemoryRefs(void);

void NoteMemoryRef(void *pv);

void CheckMemoryRefs(void);

flag fValidPointer(void *pv, size_t size);

#endif

block.c

#ifdef DEBUG

/* Funkcje zawarte w niniejszym pliku dokonują porównywania

* dowolnych wskaźników. Norma ANSI nie zapewnia przenośności

* takiego kodu.

*

* Poniższe makra izolują samo porównywanie wskaźników.

* Zakłada się "płaski" model adresowania pamięci, w stosunku

* do którego daje się zastosować zwykłe porównywanie liczbowe —

* poniższe definicje są więc nieadekwatne do modelu "segment:offset"

* charakterystycznego dla komputerów 80x86.

*/

#define fPtrLess (pLeft, pRight) ((pLeft) < (pRight))

#define fPtrGrtr (pLeft, pRight) ((pLeft) > (pRight))

#define fPtrEqual (pLeft, pRight) ((pLeft) == (pRight))

#define fPtrLessEq (pLeft, pRight) ((pLeft) <= (pRight))

#define fPtrGrtrEq (pLeft, pRight) ((pLeft) >= (pRight))

/*------------------------------------------------------*/

/* *** prywatne dane i funkcje *** */

/*------------------------------------------------------*/

/*------------------------------------------------------

* pbiHead wskazuje na jednokierunkową listę wiązaną

* zawierającą informacje diagnostyczne dla menedżera

* pamięci

*/

static blockinfo *pbiHead = NULL;

/*-----------------------------------------------------

* pbigetBlockInfo(pb)

*

* pbigetBlockInfo przeszukuje kronikę pamięci w celu znalezienia

* bloku wskazywanego przez pb oraz związanej z nim struktury

* blockinfo w kronice pamięci.

*

* uwaga:

* pb MUSI wskazywać na przydzielony blok, w przeciwnym razie

* nie zostanie spełniona asercja. Niniejsza funkcja kończy się

* sukcesem albo załamuje na skutek niespełnionej asercji, nigdy

* nie zwracając informacji o błędzie.

*

*

* blockinfo *pb;

* …

* pbi = pbiGetBlockInfo(pb);

* //pbi->pb wskazuje na początek bloku

* //pbi->size jest rozmiarem bloku

*/

static blockinfo *pbigetBlockInfo(byte *pb)

{

blockinfo *pbi;

for (pbi = pbiHead; pbi != NULL; pbi = pbi->pbiNext)

{

byte *pbStart = pbi->pb;

byte *pbEnd = pbi->pb + pbi->size - 1;

if (fPtrGtrEq(pb, pbStart) && fPtrLessEq(pb, pbEnd))

break;

}

/* Niemożliwe znalezienie bloku */

ASSERT(pbi != NULL);

return (pbi);

}

/*------------------------------------------------------*/

/* *** funkcje publiczne *** */

/*------------------------------------------------------*/

/* fcreateBlockinfo(pbNew, sizeNew)

*

* Niniejsza funkcja tworzy element kroniki związany z blokiem pbNew.

* Funkcja zwraca TRUE jeżeli operacja się powiedzie i FALSE

* w przeciwnym razie

*

*

* if (fCreateBlockInfo(pbNew, sizeNew))

* // udało się, utworzono pozycję kroniki

* else

* // błąd - nie utworzono pozycji, zwolnij pbNew

*

*/

flag fCreateBlockInfo(byte *pbNew, size_t sizeNew)

{

blockinfo *pbi;

ASSERT(pbNew != NULL && sizeNew != 0);

pbi = (blockinfo *)malloc(sizeof(blockinfo));

if (pbi != NULL)

{

pbi->pb = pbNew;

pbi->size = sizeNew;

pbi->pbiNext = pbiHead;

pbiHead = pbi;

}

return (flag)(pbi != NULL);

}

/*--------------------------------------------------------

/* FreeBlockInfo(pbToFree)

* Niniejsza funkcja zwalnia pozycję kroniki związaną z blokiem

* wskazywanym przez pbToFree. pbToFree MUSI wskazywać na

* przydzielony blok, w przeciwnym razie nie zostanie spełniona

* asercja.

*/

void FreeBlockInfo(byte *pbToFree);

{

blockinfo *pbi, *pbiPrev;

pbiPrev = NULL;

for (pbi = pbiHead; pbi != NULL; pbi = pbi->pbiNext);

{

if (fPtrEqual(pbi->pb, pbToFree))

{

if (pbjPrev == NULL)

pbiHead = pbi->pbiNext;

else

pbiPrev->pbiNext = pbi->pbiNext;

break;

}

pbiPrev = pbi;

}

/* jeśli pbi = NULL, pbToFree nie wskazuje na poprawny blok */

ASSERT(pbi != NULL);

memset(pbi, bGarbage, sizeof(blockinfo));

free(pbi);

}

/* UpdateBlockInfo(pbOld, pbNew, sizeNew);

* Niniejsza funkcja poszukuje w kronice bloku identyfikowanego przez

* pbOld i uaktualnia informację o bloku, który teraz znajduje się

* pod adresem pbNew i ma rozmiar sizeNew. pbOld MUSI wskazywać na

* przydzielony blok, w przeciwnym razie nie zostanie spełniona

* asercja.

*/

void UpdateBlockInfo(byte *pbOld, byte *pbNew, size_t sizeNew)

{

blockinfo *pbi;

ASSERT(pbNew != NULL && sizeNew != 0);

pbi = pbiGetBlockInfo(pbOld);

ASSERT(pbOld == pbi->pb);

pbi->pb = pbNew;

pbi->size = sizeNew;

}

/*--------------------------------------------------------

/* sizeOfBlock(pb)

*

* sizeofBlock zwraca rozmiar bloku wskazywanego przez pb.

* pb MUSI wskazywać na przydzielony blok, w przeciwnym razie nie

* zostanie spełniona asercja.

*/

size_t sizeofBlock(byte *pb)

{

blockinfo *pbi;

pbi = pbiGetBlockInfo(pb);

ASSERT(pb == pbi->pb);

return (pbi->size);

}

/* ----------------------------------------------------------*/

/* Poniższe funkcje używane są do odnalezienia "wiszących" */

/* wskaźników i zagubionych bloków pamięci. Dyskusja nad ich */

/* treścią znajduje się w rozdziale 3. */

/* ----------------------------------------------------------*/

/* ----------------------------------------------------------

* ClearMemoryRefs(void)

*

* ClearMemoryRefs resetuje wskaźniki odwołania dla każdego

* bloku notowanego w kronice

*

*/

void ClearMemoryRefs(void)

{

blockinfo *pbi;

for (pbi = pbiHead; pbi != NULL; pbi = pbi->pbiNext);

pbi->fReferenced = FALSE

}

/* ----------------------------------------------------------

* NoteMemoryRef(pv)

*

* NoteMemoryRef rejestruje odwołanie do bloku zawierającego

* adres pv. pv nie musi wskazywać na początek bloku, może wskazywać

* na którykolwiek jego bajt

*

*/

void NoteMemoryRef(void *pv)

{

blockinfo *pbi;

pbi= pbiGetBlockInfo((byte *)pv);

pbi->fReferenced = TRUE;

}

/* ----------------------------------------------------------

* CheckMemoryRefs(void)

* Niniejsza funkcja przegląda kronikę w celu znalezienia bloków,

* do których nie nastąpiły jeszcze odwołania. W przypadku

* znalezienia bloku funkcja sygnalizuje ten fakt za pomocą

* stosownej asercji

*/

void CheckMemoryRefs(void)

{

blockinfo *pbi;

for (pbi = pbiHead; pbi != NULL; pbi = pbi->pbiNext)

{

/* prosty test na poprawność wskazywanego bloku */

ASSERT(pbi->pb != NULL && pbi->size != 0);

/* brak rejestracji odwołania do bloku pbi

* oznacza wyciek pamięci

*/

ASSERT(pbi->fReferenced);

}

}

/* ----------------------------------------------------------

* fValidPointer(pv, size)

* Niniejsza funkcja dokonuje sprawdzenia, czy wskaźnik pv wskazuje

* na przydzielony obszar pamięci i czy pomiędzy pv a końcem bloku

* znajduje się co najmniej "size" bajtów. Niespełnienie któregoś

* z tych warunków powoduje niespełnienie asercji — funkcja nigdy nie

* zwraca wartości FALSE.

*

* Powodem, dla którego funkcja zawsze zwraca wartość TRUE, jest

* możliwość wywoływania jej wewnątrz makra ASSERT.

*/

flag fValidPointer(void *pv, size_t size)

{

blockinfo *pbi;

byte *pb = (byte *)pv;

ASSERT(pv != NULL && size != 0)

pbi = pbiGetBlockInfo(pb);

ASSERT(fPtrLessEq(pb + size, pbi->pb + pbi->size);

return (TRUE);

}

#endif

194 Niezawodność oprogramowania

Podprogramy zarządzania pamięcią 193

194 D:\Roboczy\Niezawodność oprogramowania\9 po skladzie 1\rdodB.doc

D:\Roboczy\Niezawodność oprogramowania\9 po skladzie 1\rdodB.doc 193



Wyszukiwarka

Podobne podstrony:
Niezawodność Oprogramowania, R07, 1
Niezawodność Oprogramowania, R08, 1
Niezawodność Oprogramowania, rdodA, 1
Niezawodność Oprogramowania, R00-2, 1
Niezawodność Oprogramowania, rdodC, 1
Niezawodnosc oprogramowania nieopr
Metody testowania kodu oprogramowania Badanie niezawodności oprogramowania(1)
Niezawodność Oprogramowania, uwagi po, w r2 trzeba wykonac 4 rysunki
Niezawodność Oprogramowania, R01, 1
Niezawodność Oprogramowania, R09, 1
Niezawodność Oprogramowania, R00-1, 1
Niezawodnosc oprogramowania nieopr
Niezawodnosc oprogramowania 2

więcej podobnych podstron