Самодел 1 (1114716), страница 31
Текст из файла (страница 31)
/* деление на ноль – здесь процессу будет послан сигнал SIGFPE – floating point exception */
return argc/0;
}
/* Процесс-родитель:*/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid;
int status;
struct user_regs_struct REG;
if ((pid = fork()) == 0) {
/*находимся в процессе-потомке, разрешаем трассировку */
ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(“son”, ”son”, 0); /* замещаем тело процесса */
/* здесь процесс-потомок будет остановлен с сигналом SIG_TRAP, ожидая команды продолжения выполнения от управляющего процесса*/
}
/* в процессе-родителе */
while (1) {
/* ждем, когда отлаживаемый процесс приостановится */
wait(&status);
/*читаем содержимое регистров отлаживаемого процесса */
ptrace(PTRACE_GETREGS, pid, ®, ®);
/* выводим статус отлаживаемого процесса, номер сигнала, который его остановил и значения прочитанных регистров */
printf("signal = %d, status = %#x, EIP=%#x ESP=%#x\n", WSTOPSIG(status), status, REG.eip, REG.esp);
if (WSTOPSIG(status) != SIGTRAP) {
if (!WIFEXITED(status)) {
/* завершаем выполнение трассируемого процесса */
ptrace (PTRACE_KILL, pid, 0, 0);
}
break;
}
/* разрешаем выполнение трассируемому процессу */
ptrace (PTRACE_CONT, pid, 0, 0);
}
}
Система межпроцессного взаимодействия IPC.
Система IPC – альтернатива именованным каналам. Позволяет организовывать работу именованных каналов в произвольные моменты времени.
Состав :
- Очереди сообщений
- Семафоры
- Разделяемая память
Общие концепции
Для каждого разделяемого ресурса используется «уникальная» система именования. Существует код, идентифицирующий конкретный разделяемый ресурс. Для работы с этим ресурсам необходимо знать этот код.
Каждый IPCресурс обладает набором атрибутов:
-Владельца ресурса (идентификатор процесса, создавшего ресурс, хотя процесс может делегировать ресурс другим процессам)
- Права доступа
Для всех средств IPC приняты общие правила именования объектов, позволяющие процессу получить доступ к такому объекту. Для именования объекта IPC используется ключ, представляющий собой целое число. Ключи являются уникальными во всей UNIX-системе идентификаторами объектов IPC, и зная ключ для некоторого объекта, процесс может получить к нему доступ. При этом процессу возвращается дескриптор объекта, который в дальнейшем используется для всех операций с ним. Проведя аналогию с файловой системой, можно сказать, что ключ аналогичен имени файла, а получаемый по ключу дескриптор – файловому дескриптору, получаемому во время операции открытия файла. Ключ для каждого объекта IPC задается в момент его создания тем процессом, который его порождает, а все процессы, желающие получить в дальнейшем доступ к этому объекту, должны указывать тот же самый ключ.
Для именования ресурсов IPC используется уникальные ключи. Для каждого из разделяемых ресурсов.
Генерация ключей: функция ftok().
Все процессы, которые хотят работать с одним и тем же IPC-ресурсом, должны знать некий целочисленный ключ, по которому можно получить к нему доступ.
Необходим механизм уникального именования ресурса, но вместе с тем нужно, чтобы этот механизм позволял всем процессам, желающим работать с одним ресурсом, получить одно и то же значение ключа.
Итак, все процессы, которые хотят работать с одним и тем же IPC-ресурсом, должны знать некий целочисленный ключ, по которому можно получить к нему доступ. В принципе, программист, пишущий программы для работы с разделяемым ресурсом, может просто жестко указать в программе некоторое константное значение ключа для именования разделяемого ресурса. Однако, возможна ситуация, когда к моменту запуска такой программы в системе уже существует разделяемый ресурс с таким значением ключа, и в виду того, что ключи должны быть уникальными во всей системе, попытка породить второй ресурс с таким же ключом закончится неудачей (подробнее этот момент будет рассмотрен ниже).
Для решения этой задачи служит функция ftok():
#include <sys/types.h>
#include<sys/ipc.h>
key_t ftok (char *filename, char proj)
Эта функция генерирует значение ключа по некоторой строке символов и добавочному символу, передаваемым в качестве параметров. Гарантируется, что полученное таким образом значение будет отличаться от всех других значений, сгенерированных функцией ftok() с другими значениями параметров, и в то же время, при повторном запуске ftok() с теми же параметрами, будет получено то же самое значение ключа.
Смысл второго аргумента функции ftok() – добавочного символа – в том, что он позволяет генерировать разные значения ключа по одному и тому же значению первого параметра – строки. Это позволяет программисту поддерживать несколько версий своей программы, которые будут использовать одну и ту же строку, но разные добавочные символы для генерации ключа, и тем самым получат возможность в рамках одной системы работать с разными разделяемыми ресурсами.
Следует заметить, что функция ftok() не является системным вызовом, а предоставляется библиотекой.
Для создания разделяемого ресурса с заданным ключом, либо подключения к уже существующему ресурсу с таким ключом используются ряд системных вызовов, имеющих общий суффикс get. Общими параметрами для всех этих вызовов являются ключ и флаги. В качестве значения ключа при создании любого IPC-объекта может быть указано значение IPC_PRIVATE. При этом создается ресурс, который будет доступен только породившему его процессу. Такие ресурсы обычно порождаются родительским процессом, который затем сохраняет полученный дескриптор в некоторой переменной и порождает своих потомков. Т.к. потомкам доступен уже готовый дескриптор созданного объекта, они могут непосредственно работать с ним, не обращаясь предварительно к «get»-методу. Таким образом, созданный ресурс может совместно использоваться родительским и порожденными процессами. Однако, важно понимать, что если один из этих процессов повторно вызовет «get»-метод с ключом IPC_PRIVATE, в результате будет получен другой, совершенно новый разделяемый ресурс, т.к. при обращении к «get»-методу с ключом IPC_PRIVATE всякий раз создается новый объект нужного типа.
Если при обращении к «get»-методу указан ключ, отличный от IPC_PRIVATE, происходит следующее:
Происходит поиск объекта с заданным ключом среди уже существующих объектов нужного типа. Если объект с указанным ключом не найден, и среди флагов указан флаг IPC_CREAT, будет создан новый объект. При этом значение параметра флагов должно содержать побитовое сложение флага IPC_CREAT и константы, указывающей права доступа для вновь создаваемого объекта.
Если объект с заданным ключом не найден, и среди переданных флагов отсутствует флаг IPC_CREAT, «get»-метод вернет –1, а в переменной errno будет установлено значение ENOENT
Если объект с заданным ключом найден среди существующих, «get»-метод вернет дескриптор для этого существующего объекта, т.е. фактически, в этом случае происходит подключение к уже существующему объекту по заданному ключу. Если процесс ожидал создания нового объекта по указанному ключу, то для него такое поведение может оказаться нежелательным, т.к. это будет означать, что в результате случайного совпадения ключей (например, если процесс не использовал функцию ftok()) он подключился к чужому ресурсу. Чтобы избежать такой ситуации, следует указать в параметре флагов наряду с флагом IPC_CREAT и правами доступа еще и флаг IPC_EXCL – в этом случае «get»-метод вернет -1, если объект с таким ключом уже существует (переменная errno будет установлена в значение EEXIST)
Следует отметить, что при подключении к уже существующему объекту дополнительно проверяются права доступа к нему. В случае, если процесс, запросивший доступ к объекту, не имеет на то прав, «get»-метод вернет –1, а в переменной errno будет установлено значение EACCESS
Нужно заметить, что для каждого типа объектов IPC существует некое ограничение на максимально возможное количество одновременно существующих в системе объектов данного типа. Если при попытке создания нового объекта окажется, что указанное ограничение превышено, «get»-метод, совершавший попытку создания объекта, вернет -1, а в переменной errno будет указано значение ENOSPC.
Отметим, что даже если ни один процесс не подключен к разделяемому ресурсу, система не удаляет его автоматически. Удаление объектов IPC является обязанностью одного из работающих с ним процессов и для этого определена специальная функция. Для этого системой предоставляются соответствующие функции по управлению объектами System V IPC.
Очередь сообщений
Очередь сообщений представляет собой некое хранилище типизированных сообщений, организованное по принципу FIFO. Любой процесс может помещать новые сообщения в очередь и извлекать из очереди имеющиеся там сообщения. Каждое сообщение имеет тип, представляющий собой некоторое целое число. Благодаря наличию типов сообщений, очередь можно интерпретировать двояко — рассматривать ее либо как сквозную очередь неразличимых по типу сообщений, либо как некоторое объединение подочередей, каждая из которых содержит элементы определенного типа. Извлечение сообщений из очереди происходит согласно принципу FIFO – в порядке их записи, однако процесс-получатель может указать, из какой подочереди он хочет извлечь сообщение, или, иначе говоря, сообщение какого типа он желает получить – в этом случае из очереди будет извлечено самое «старое» сообщение нужного типа.
Системный вызов msgget()
Для создания новой или для доступа к существующей используется системный вызов msgget:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/message.h>
int msgget (key_t key, int msgflag)
В случае успеха вызов возвращает положительный дескриптор очереди, который может в дальнейшем использоваться для операций с ней, в случае неудачи -1. Первым аргументом вызова является ключ, вторым – флаги, управляющие поведением вызова.
Функция msgsnd()
Для отправки сообщения используется функция msgsnd():
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
Ее первый аргумент — идентификатор очереди, полученный в результате вызова msgget(). Второй аргумент — указатель на буфер, содержащий реальные данные и тип сообщения, подлежащего посылке в очередь, в третьем аргументе указывается размер буфера.
В качестве буфера необходимо указывать структуру, содержащую следующие поля (в указанном порядке):
long msgtype — тип сообщения
char msgtext[ ] — данные (тело сообщения)
В заголовочном файле <sys/msg.h> определена константа MSGMAX, описывающая максимальный размер тела сообщения. При попытке отправить сообщение, у которого число элементов в массиве msgtext превышает это значение, системный вызов вернет –1.
Четвертый аргумент данного вызова может принимать значения 0 или IPC_NOWAIT. В случае отсутствия флага IPC_NOWAIT вызывающий процесс будет блокирован (т.е. приостановит работу), если для посылки сообщения недостаточно системных ресурсов, т.е. если полная длина сообщений в очереди будет больше максимально допустимого. Если же флаг IPC_NOWAIT будет установлен, то в такой ситуации выход из вызова произойдет немедленно, и возвращаемое значение будет равно –1.
В случае удачной записи возвращаемое значение вызова равно 0.
Функция msgrcv()
Для получения сообщения имеется функция msgrcv:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)