- •Системное программное обеспечение
- •Разд. 1. Операционные системы и среды
- •Тема 1.1. Структура программного обеспечения вычислительной системы
- •Тема 1.2 Назначение, функции и структура операционной системы
- •1.2.1 Типы ос. Системы реального времени и операционные системы реального времени
- •Тема 1.3. Управление временем центрального процессора
- •Рекомендуется всегда проверять возвращаемое значение Res. Получение и использование процессом ссылок на себя
- •Использование потоков при разработке приложений
- •1.3.3 Синхронизация взаимодействующих потоков
- •Interlocked – функции.
- •Семафорные примитивы Дейкстры
- •Решение проблемы критических участков с помощью семафорных примитивов Дейкстры
- •1.3.4 Синхронизации потоков средствами операционной системы
- •Пример 2
- •Пример 3 Поток_1 Поток_2
- •1.3.5. Проблема тупиков и методы борьбы с тупиками
- •Взаимного исключения, при котором процессы имеют монопольный доступ к ресурсам;
- •Ожидания, при котором процесс, запрашивающий ресурс, ждет до тех пор, пока запрос не будет удовлетворен, удерживая ранее полученные ресурсы;
- •Методы борьбы с тупиками
- •Тема 1.4 Управление памятью
- •Защищенный режим процессоров Intel и его возможности
- •1.4.2. Реализация многозадачного режима в защищенном режиме процессоров фирмы Intel
- •Аппаратная поддержка многозадачности
- •Обработка прерываний в реальном режиме. Вектора прерываний.
- •Режимы работы мп 386
- •Системный режим
- •Особенности s – режима.
- •Организация виртуальной памяти
- •Управление страничной памятью в ос ms Windows
- •Линейный адрес
- •1.4.4. Разделы в виртуальном адресном пространстве процесса
- •Области применения dll
- •Основные dll ms Windows:
- •Создание dll
- •Использование dll (импорт функций из dll)
- •Неявная загрузка dll (неявное подключение)
- •Явная загрузка dll
- •Выполнение процедур инициализации и деинициализации Dll
- •Тема 1.6 Структура ms Windows и драйверы режима ядра
- •Тема 1.7 Управление вводом-выводом и файловые системы Win32
- •Эволюция файловых систем эвм
- •Раздел 2. Программирование в операционной среде
- •Тема 2.1. Ассемблеры и макроязыки
- •2.1.1. Этапы подготовки программы к выполнению
- •Операнды команд
- •Алгоритмы работы Ассемблеров
- •Двухпроходный Ассемблер - 1-й проход
- •2.1.2. Макроязыки
- •Заголовок макроопределения
- •Окончание макроопределения
- •Локальные переменные макроопределения
- •Присваивание значений переменным макроопределения
- •Оператор безусловного перехода и метки макроопределения
- •Тема 2.2.Трансляторы
- •2.3.1. Трансляторы. Компиляторы и интерпретаторы. Мобильность программного обеспечения
- •Тема 2.3 Формальные языки и грамматики
- •Синтаксический и лексический анализатор
- •Детерминированные и недетерминированные автоматы
- •Алгоритм синтаксического анализа
- •Пример 1
- •Пример 2
1.4.4. Разделы в виртуальном адресном пространстве процесса
Адресное пространство процесса Windows
Адресное пространство процесса разделено на системный и пользовательский разделы – см. рис. 2- 27.
Ядро Windows Драйверы
Системные таблицы
Системные
DLL Пользовательские DLL Данные Приложения
Рисунок 1 – 27 – разделы в адресном пространстве процесса Windows
В Win32 определены четыре механизма управления виртуальной памятью:
виртуальная память, используемая для операций с большими массивами объектов или структур (размер массива превышает размер страницы). Для реализации метода используется резервирование регионов в адресном пространстве процесса и последующая передача физической памяти региону;
кучи (heaps), применяемые для операций с большим количеством малых объектов (размер объекта меньше размера страницы);
файлы, проецируемые в память - средства для операций с файлами большого размера и для обеспечения совместного доступа приложений к данным;
AWE (Adressing Windowing Extension) – отображение виртуального адресного пространства на окно размером 4 Гб физической памяти, размер которой превышает 4 Гб.
Резервирование регионов в адресном пространстве процесса и передача физической памяти региону
Регионом в адресном пространстве процесса называется совокупность смежных страниц виртуальной памяти, имеющих одинаковый статус, тип и атрибут защиты.
Приложение резервирует регион в адресном пространстве процесса, используя функцию
VirtualAlloc(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD): Pointer;
Первый параметр определяет положение резервируемого региона в адресном пространстве. Если параметр равен Nil, система определяет положение региона самостоятельно. Регионы всегда резервируются на границе 64К.
Если запрос выполнен, функция возвращает базовый адрес зарезервированного региона.
Второй параметр задает размер резервируемого региона в байтах. Заданный размер увеличивается до величины, кратной размеру страницы.
Третий параметр определяет вид операции – MEM_RESERVE – зарезервировать регион, MEM_COMMIT - передать региону физическую память (сначала нужно зарезервировать регион, затем передать ему память).
При указании параметра MEM_TOP_DOWN система размещает регион по максимально возможному адресу - Allocates memory at the highest possible address. Это дает возможность уменьшить фрагментацию виртуального адресного пространства.
В принципе можно одновременно зарезервировать регион и передать ему физическую память – например
VirtualAlloc (Nil, 100*1024, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);
Последний параметр определяет атрибут защиты.
Для возврата физической памяти, спроецированной на регион, или освобождения всего региона адресного пространства используется функция
VirtualFree (lpAddress: Pointer; dwSize,: DWORD): BOOL;
В простейшем случае использования этой функции – для освобождения всей переданной региону физической памяти – в параметр lpAddress необходимо передать базовый адрес региона, в параметр dwSize=0, так как системе известен размер региона. В третьем параметре следует передать MEM_RELEASE – это приведет к возврату системе всей физической памяти, спроецированной на регион, и освобождению самого региона. Если необходимо не освобождая регион вернуть в систему часть физической памяти, переданной региону, в параметр lpAddress заносится адрес, идентифицирующий первую возвращаемую страницу, в параметр dwSize – количество возвращаемых байт, в параметре dwFreeType - MEM_DECOMMIT.
Файлы, проецируемые в память
Как и виртуальная память, проецируемые файлы позволяют резервировать регион адресного пространства и передавать ему физическую память. При использовании проецируемых файлов физическая память не выделяется из системного страничного файла, а берется из файла, уже находящегося на диске. Как только файл спроецирован в память, к нему можно обращаться так, будто он целиком в нее загружен.
Описанный механизм управления памятью применяется для:
загрузки и исполнения EXE- и DLL-файлов. Это позволяет существенно экономить как на размере страничного файла, так и на времени, необходимом системе для подготовки приложения к исполнению;
доступа к файлу данных, размещенному на диске. Это позволяет обойтись без операций файлового ввода/вывода и буферизации содержимого файла - не нужно выделять память под буфер, загружать данные из файла в память;
обеспечения совместного доступа разных процессов к общим данным.
Подготовка к использованию файлов, проецируемых в память
Для этого нужно выполнить три операции:
Создать или открыть объект ядра "файл".
Создать объект ядра "проецируемый файл", чтобы сообщить системе размер файла и способ доступа к нему.
Указать системе, как спроецировать в адресное пространство процесса созданный в п.2 объект - целиком или только его часть.
Для завершения работы с файлом, проецируемым в память, следует выполнить три операции:
Сообщить системе об отмене проецирования на адресное пространство процесса объекта ядра "проецируемый файл".
Закрыть этот объект.
Закрыть объект ядра "файл".
Создание и использование куч
Процессу разрешено создавать несколько куч, являющихся частью его адресного пространства.
Куча - это регион зарезервированного адресного пространства. Первоначально большей его части физическая память не передается. После того, как программа занимает эту область под данные, диспетчер, управляющий кучами, передает ей страницы физической памяти. При освобождении страниц в куче диспетчер возвращает физическую память системе.
Одна куча предоставляется процессу по умолчанию. Ее описатель возвращает функция
GetProcessHeap() : Handle;
Дополнительные кучи создаются вызовом функции
HeapCreate ( flOption, dwInitialSize, MaximumSize) : Handle;
Первый параметр определяет характер операций, выполняемых над кучей. По умолчанию (значение 0) действует принцип последовательного доступа к куче (как к критическому участку).
Второй параметр определяет количество байт, первоначально передаваемых куче.
Третий параметр указывает максимальный размер кучи. Может быть равен 0 - в этом случае система резервирует регион, самостоятельно определяя его размер и при необходимости расширяет его до максимально возможного объема.
Выделение блока памяти из кучи выполняет функция
HeapAlloc ( Handle, dwFlags, dwBytes ) : pointer;
Первый параметр - описатель кучи, возвращаемый функциями GetProcessHeap() или HeapCreate()
Второй параметр указывает на характер выделения памяти. При его значении, равным HEAP_ZERO_MEMORY=8, выделяемый блок заполняется нулями.
Третий параметр определяет число выделяемых в куче байт.
Освобождение блока памяти выполняет функция
HeapFree ( Handle, dwFlags, dwBytes ) : Boolean;
Уничтожение кучи выполняет функция HeapDestroy (Handle) : Boolean.
Получение информации о состояниии виртуальной памяти
Сведения о конкретной платформе предоставляет процедура:
void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
Структура данных SYSTEM_INFO описана cледующим образом:
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId; struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO
Более подробная информация приведена в MSDN.
Для динамического отслеживания текущего состояния памяти используется процедура
void GlobalMemoryStatus(
LPMEMORYSTATUS lpBuffer
);
Структура данных _MEMORYSTATUS описана как
typedef struct _MEMORYSTATUS { DWORD dwLength;
DWORD dwMemoryLoad;
SIZE_T dwTotalPhys;
SIZE_T dwAvailPhys;
SIZE_T dwTotalPageFile;
SIZE_T dwAvailPageFile;
SIZE_T dwTotalVirtual;
SIZE_T dwAvailVirtual;
} MEMORYSTATUS,
*LPMEMORYSTATUS
Назначение полей данной структуры:
dwMemoryLoad - оценка занятости системы управления памятью(0-100)
dwTotalPhys - общий размер физической памяти RAM-памяти в байтах
dwAvailPhys - общий размер физической памяти RAM-памяти в байтах, доступной для выделения
dwTotalPageFile - максимальное количество байтов, которое может содержаться в страничном файде на жестком диске (или дисках)
dwAvailPageFile - максимальное количество байтов, которое может быть передано процессу из страничного файла
dwTotalVirtual: DWORD - количество байтов в адресном пространстве, принадлежащих лично данному процессу
dwAvailVirtual - суммарный объем всех свободных регионов в адресном пространстве процесса, вызывающего процедуру GlobalMemoryStatus
вычитая из dwTotalVirtual полученное значение, можно найти размер зарезервированной процессом области в виртуальном адресном пространстве
Перед вызовом процедуры необходимо занести в поле dwLength размер структуры в байтах с помощью функции sizeof().
Для запроса информации об участке памяти по заданному адресу (размер, тип памяти, атрибуты защиты) текущего процесса служит функция:
SIZE_T VirtualQuery(
LPCVOID lpAddress,
PMEMORY_BASIC_INFORMATION lpBuffer,
SIZE_T dwLength
);
При вызове функции первый параметр должен содержать адрес виртуальной памяти, о котором нужно получить информацию.
Второй параметр – переменная типа, описанного как
typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; DWORD AllocationProtect; SIZE_T RegionSize; DWORD State; DWORD Protect; DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
Назначение полей данной структуры:
BaseAddress - значение параметра lpAddress, округленное до значения, кратного размеру страницы
AllocationBase - базовый адрес региона, включающего адрес запроса
AllocationProtect - атрибут защиты региона – некоторые из возможных значений PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE
RegionSize - суммарный размер (в байтах) группы страниц, начинающихся с базового адреса и имеющих те же атрибуты защиты, состояние и тип, что и страница, обнаруженная по адресу lpAddress
State - указывает состояние (MEM_FREE, MEM_RESERVE, MEM_COMMIT) всех смежных страниц, имеющих те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу lpAddress
Для состояния MEM_FREE элементы Allocationbase, Alloocation, Protect и Type не определяются
Protect - содержит атрибут защиты (PAGE_*),общий для всех смежных страниц, имеющих те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу lpAddress
Type - определяет тип физической памяти (MEM_IMAGE, MEM_MAPPED или MEM_PRIVATE), связанной с группой смежных страниц, имеющих имеющих те же атрибуты защиты,состояние и тип, что и страница, расположенная по адресу lpAddress
Параметр dwLength задает размер структуры MEORY_BASIC_INFORMATION.
Функция VirtualQuery() возвращает число байт, скопированных в буфер. Если возвращено нулевое значение, информация о запрошенном участке НЕ ПОЛУЧЕНА.
Сканируя память в диапазоне от минимального до максимального адреса, можно построить карту виртуальной памяти процесса.
Тема 1.5. Статическое и динамическое связывание. Динамически подключаемые библиотеки (DLL)
Статическое и динамическое связывание
При разработке программ, используется принцип модульности (разбиения программы на составные части), каждая из которых может подготавливаться отдельно.
Программный модуль - программа или функционально завершенный фрагмент программы, предназначенный для хранения, трансляции, объединения с другими программными модулями и загрузки в оперативную память.
От написания до выполнения программа проходит следующие этапы:
Трансляция
Редактирование связей (компоновка)
Загрузка.
На рисунке 1 -28 показаны перечисленные этапы и используемые для их выполнения системные обрабатывающие программы.
Рисунок 1-28- этапы подготовки и выполнения прикладной программы
Программа пишется в виде исходного модуля, на рисунке - файл ИМ.
Исходный модуль - программный модуль на исходном языке, обрабатываемый транслятором и представляемый для него как целое, достаточное для проведения трансляции.
Трансляция - преобразование программы, представленной на одном языке программирования, в программу на другом языке программирования, в определенном смысле равносильную первой.
Как правило, выходным языком транслятора является машинный язык целевой вычислительной системы. Машинный язык - язык программирования, предназначенный для представления программы в форме, позволяющей выполнять ее непосредственно техническими средствами обработки информации.
Трансляторы - общее название для программ, осуществляющих трансляцию. Они подразделяются на Ассемблеры и Компиляторы - в зависимости от исходного языка программы, которую они обрабатывают.
Объектный модуль (ОМ) - программный модуль, получаемый в результате трансляции исходного модуля.
Поскольку результатом трансляции является модуль на языке, близком к машинному, в нем уже не остается признаков того, на каком исходном языке был написан программный модуль. Это создает принципиальную возможность создавать программы из модулей, написанных на разных языках. Специфика исходного языка, однако, может сказываться на физическом представлении базовых типов данных, способах обращения к процедурам/функциям и т.п.
Большая часть объектного модуля - команды и данные машинного языка именно в той форме, в какой они будут существовать во время выполнения программы. Однако, программа в общем случае состоит из многих модулей. Поскольку транслятор обрабатывает только один конкретный модуль, он не может должным образом обработать те части этого модуля, в которых запрограммированы обращения к данным или процедурам, определенным в другом модуле. Такие обращения называются внешними ссылками. Те места в объектном модуле, где содержатся внешние ссылки, транслируются в некоторую промежуточную форму, подлежащую дальнейшей обработке. Говорят, что объектный модуль представляет собой программу на машинном языке с неразрешенными внешними ссылками.
Разрешение внешних ссылок выполняется на следующем этапе подготовки, который обеспечивается Редактором Связей (Компоновщиком). Редактор Связей соединяет вместе все объектные модули, входящие в программу. Поскольку Редактор Связей "видит" уже все компоненты программы, он имеет возможность обработать те места в объектных модулях, которые содержат внешние ссылки. Результатом работы Редактора Связей является загрузочный модуль.
Загрузочный модуль - программный модуль, представленный в форме, пригодной для загрузки в оперативную память для выполнения.
Загрузочный модуль сохраняется в виде файла на внешней памяти. Для выполнения программа должна быть перенесена (загружена) в оперативную память. Иногда при этом требуется некоторая дополнительная обработка (например, настройка адресов в программе на ту область оперативной памяти, в которую программа загрузилась). Эта функция выполняется Загрузчиком, который обычно входит в состав операционной системы.
Описанный процесс называется статическим связыванием.
Статическое связывание использовалось в однозадачных ОС. В многозадачных ОС (к которым относится и MS Windows) статическое связывание приводит к неэффективному использованию ОП, и вместо него используется динамическое связывание, основанное на использовании динамически связываемых (подключаемых) библиотек – DLL – dynamic linked libraries. В этом случае редактирование связей выполняется при каждом запуске программы на выполнение и совмещается с загрузкой. Этот вариант связывания при запуске более расходный, т.к. затраты на связывание тиражируются при каждом запуске. Но он обеспечивает:
большую гибкость в сопровождении, так как позволяет менять отдельные объектные модули программы, не меняя остальных модулей;
экономию внешней памяти, так как объектные модули, используемые во многих программах не копируются в каждый загрузочный модуль, а хранятся в одном экземпляре.
