Сканування ланцюжка МСВ-блоків дозволяє програмі вирішити ряд специфічних
проблем: знайти фрагментацію оперативної пам’яті та встановити її в разі
необхідності, “зняти” непотрібні резидентні програми, повідомити про те, які
резидентні програми знаходяться в даний момент в пам’яті і т.д. В основі всіх
цих дій лежить послідовний перегляд ланцюга МСВ-блоків з використанням
розглянутої раніше функції scan_mcb(). Почавши, наприклад, сканування МСВ-блока, що
відповідає даній програмі, можливо вивести на екран інформацію про всі блоки
пам’яті, що розміщені по пам’яті вище даної програми, та їх стан. Якщо замість
початкової точки сканування вибирається внутрішня змінна MS_DOS, в якій
зберігається адреса початку ланцюга МСВ-блоків, або перший МСВ-блок, що
відповідає в MS_DOS програмі COMMAND.COM, програма буде
друкувати становище (карту) всієї оперативної пам’яті комп’ютера. На жаль,
місцезнаходження внутрішньої змінної MS_DOS, що вказує на початок ланцюга МСВ-блоків,
“глибоко заховано”. Можливі підходи до вирішення даної проблеми з’ясовуються
далі при побудові функції first_psp(). Наведена функція main() представляє з себе корисну утіліту, що видає карту оперативної пам’яті
із вказівкою початкового сегмента МСВ-блока, його розміру та ім’я програми, для
якої блок розподілений ОС. Визначення імені програми виконує функція exe_name().
/*L6_8*/
#include <stdio.h>
#include <dos.h>
#include “mcb.h”
int main(void)
{char far* file_spec;
int ret;
unsigned next_block_seg, start_seg, seglenght,
command_seg;
unsigned owner_psp; /*PID програма власника*/
printf(“Карта оперативної пам’яті \n\n”\
“Сегмент: зміщення Довжина блоку Специфікація файлу\n”\
“початку блока (параграфи) програми-власника\n”\
“-------------------------------------------------------------\n”)
/*Визначення блока який містить PSP та резидентну частину command.com.
Задається сегментом вектора переривання 2Eh*/
command_seg=*(unsigned
far*)MK_FP(0,(0x2e<<2)+2);
/*Визначення сегмента першого ЬЫ-ВЩЫ блока пам’яті*/
start_seg=firstpsp();
/*Сканування ланцюжка МСВ-блоків.*/
while(1)
{ret=scan_mcb(start_seg,&next_block_seg,&owner_psp);
if(ret==MCB_ERROR)
return MCB_ERROR; /*Вихід оскільки зруйнований ланйюжок*/
/* Визначення імені програми-власника */
if(owner_psp==command_seg)
file_spec=(char far*)”command.com”;
else
if(owner_psp)
file_space=exe_name(owner_psp);
else file_space=”Вільний блок”;
/*Формування выводимой довжини блоку. */
if(ret==NOT_LAST)
seg_length=next_block_seg;
/*Вивід на екран сформованих даних про блок. */
prinf(“%4X:0000
%4X %/30Fs\n”,
start_seg,seg_length,file_space);
if(ret==LAST)
return OK;
else start_seg=next_block_seg;
}
}
Джерелом для вияснення імені .exe- чи .com-файлу програми-власника блока пам’яті служить пам’ять зразу після середовища програми. Після стрічок
середовища із зміщенням 2 байти знаходиться стрічка, в якій знаходиться
специфікація файлу. Сегмент початку середовища береться із PSP за зміщенням 2Ch. Далі наведено приклад функції, яка повертає far-покажчик на стрічку повної специфікації програми-власника блока. Функція
повертає NULL, якщо при скануванні середовища
перевищено її обмеження в 32К байти.
/*L6_9*/
#include <dos.h>
#include “mcb.h”
char far* exe_name(unsigned current_psp_seg)
{char far* char_ptr; unsigned env_seg,
env_length=0;
/*Зчитування із PSP сегмента середовища програми. Формування
покажчика для звернення до стрічки середовища. */
env_seg=*(unsigned far*)
MK_FP(current_psp_seg,0x2c);
char_ptr=(char far*)MK_FP(env_seg,0);
/*Сканування середовища програми до знаходження’\0”\0’. */
while(env_length<0x8000)
{if(!(*(char_ptr)))
return (++char_ptr+3);}
else char_ptr++;
env_length++;
}
return (char far*)0L;
}
Для знаходження сегмента першого PSP в оперативній пам’яті використовується функція firstpsp(), текст якої наведено далі. Алгоритм, закладений в
її основу, такий. Відшукуємо перший параграф, починаючи з 0:0, що містить в
першому байті символ ‘M’, та робиться припущення,що на цій границі
знаходиться МСВ, передуючий першому PSP. Дійсний
МСВ за адресою seg:0 перед PSP відповідає декільком вимогам, які послідовно провіряються:
1)
два
байти, які ми дістали за адресою seg:1, мають бути
рівні seg+1: тому що в байтах 1-2 МСВ має зберігатись
PID програми-власника, сегмент PSP;
2)
наступний
МСВ-блок ланцюжка, знайдений в припущенні, що розглянутий блок – коректний МСВ,
повинен бути коректним МСВ-блоком;
3)
перший
байт за адресою seg+1:0 повинен бути код інструкції INT(CDh).
Якщо перевірені умови не виконуються, значення seg збільшуеться на 1.
Далі наводиться приклад функції, що реалізує розглянутий алгоритм:
/*L6_10. */
#include <dos.h>
#include “mcb.h”
unsigned firstpsp(void)
{unsigned seg=0,offs=0;
struct MCB far* far_ptr;
while(1)
{far_ptr=(struct MCB far*)MK_FP(seg,offs);
if(far_ptr->first_symb!=’M’)
seg++;/*Збільшуємо сегмент*/
else
if(far_ptr->owner_psp==++seg)
if(*(char far*)MK_FP(seg,offs)==0xCD)
}}
Обережно ввівши наведену функцію main, scan_mcb(), exe_name() та firstpsp() та скомпілювавши їх разом, отримаємо зручну
системну утиліту спостереження за оперативною пам’яттю.
![]() |
![]() |
![]() |