
- •Практичне заняття 8 Організація уведення-виведення в unix. Файли пристроїв. Апаратні переривання
- •Операції над файловими системами. Монтування файлових систем
- •Блокові, символьні пристрої. Поняття драйвера. Блокові, символьні драйвери, драйвери низького рівня. Файловий інтерфейс
- •Апаратні переривання (interrupt), виключення (exception), програмні переривання (trap, software interrupt). Їх обробка
- •Поняття сигналу. Способи виникнення сигналів і види їх обробки
- •Поняття групи процесів, сеансу, лідера групи, лідера сеансу, управляючого терміналу сеансу. Системні виклики getpgrp(), setpgrp(), getpgid(), setpgid(), getsid(), setsid()
- •Системний виклик kill() і команда kill
- •Вивчення особливостей отримання термінальних сигналів поточною і фоновою групою процесів
- •Системний виклик signal(). Установка власного обробника сигналу
- •Прогін програми, що ігнорує сигнал sigint
- •Прогін програми з призначеною для користувача обробкою сигналу sigint
- •Відновлення попередньої реакції на сигнал
- •Сигнали sigusr1 і sigusr2. Використовування сигналів для синхронізації процесів
- •Завершення породженого процесу. Системний виклик waitpid(). Сигнал sigchld
- •Прогін програми для ілюстрації обробки сигналу sigchld
- •Виникнення сигналу sigpipe при спробі запису в pipe або fifo, який ніхто не збирається читати
- •Поняття про надійність сигналів. Posix функції для роботи з сигналами
- •Питання до захисту роботи
Вивчення особливостей отримання термінальних сигналів поточною і фоновою групою процесів
Візьмемо тривіальну програму 13–14-1.c, в якій процес породжує дитину, і вони обидва зациклюються, і на її основі проілюструємо сказане вище.
/* Тривіальна програма для ілюстрації понять група процесів, сеанс, фонова група і т.д. */
#include <unistd.h>
int main(void){
(void)fork();
while(1);
return 0;
}
Лістинг 13-14.1. Тривіальна програма (13–14-1.c) для ілюстрації понять група процесів, сеанс, фонова група і т.д.
Для цього використовуватимемо команду ps з опціями –e і j, яка дозволяє одержати інформацію про всі процеси в системі і взнати їх ідентифікатори, ідентифікатори груп процесів і сеансів, управляючий термінал сеансу і до якої групи процесів він приписаний. Набравши команду "ps –e j" (зверніть увагу на наявність пропуску між буквами e і j!!!) ми одержимо список всіх процесів в системі. Колонка PID містить ідентифікатори процесів, колонка PGID – ідентифікатори груп, до яких вони належать, колонка SID – ідентифікатори сеансів, колонка TTY – номер відповідного управляючого терміналу, колонка TPGID (може бути присутній не у всіх версіях UNIX, але в Linux є) – до якої групи процесів приписаний управляючий термінал.
Системний виклик signal(). Установка власного обробника сигналу
Одним із способів зміни поведінки процесу при отриманні сигналу в операційній системі UNIX є використовування системного виклику signal().
Системний виклик signal()
#include <signal.h>
void (*signal (int sig void (*handler) (int)))(int);
Опис системного виклику
Системний виклик signal служить для зміни реакції процесу на який-небудь сигнал. Хоча прототип системного виклику виглядає досить лякаючий, нічого страшного в ньому немає. Приведений вище опис можна словесно висловити таким чином:
функція signal, що повертає покажчик на функцію з одним параметром типу int, яка нічого не повертає, і має два параметри: параметр sig типа int і параметр handler, службовець покажчиком на нічого не повертаючу функцію з одним параметром типу int.
Параметр sig – це номер сигналу, обробку якого належить змінити.
Параметр handler описує новий спосіб обробки сигналу – це може бути покажчик на призначену для користувача функцію – обробник сигналу, спеціальне значення SIG_DFL або спеціальне значення SIG_IGN. Спеціальне значення SIG_IGN використовується для того, щоб процес ігнорував сигнали з номером sig, що поступили, спеціальне значення SIG_DFL – для відновлення реакції процесу на цей сигнал за умовчанням.
Значення, що повертається
Системний виклик повертає покажчик на старий спосіб обробки сигналу, значення якого можна використовувати для відновлення старого способу у разі потреби.
Цей системний виклик має два параметри: один з них задає номер сигналу, реакцію процесу на який вимагається змінити, а другий визначає, як саме ми збираємося її міняти. Для першого варіанту реакції процесу на сигнал (див. розділ "Поняття сигналу. Способи виникнення сигналів і види їх обробки") – його ігнорування – застосовується спеціальне значення цього параметра SIG_IGN. Наприклад, якщо вимагається ігнорувати сигнал SIGINT, починаючи з деяким місцем роботи програми, в цьому місці програми ми повинні спожити конструкцію
(void) signal(SIGINT, SIG_IGN);
Для другого варіанту реакції процесу на сигнал – відновлення його обробки за умовчанням – застосовується спеціальне значення цього параметра SIG_DFL. Для третього варіанту реакції процесу на сигнал як значення параметра підставляється покажчик на призначену для користувача функцію обробки сигналу, яка повинна мати прототип вигляду
void *handler(int);
Нижче приведений приклад скелета конструкції для призначеної для користувача обробки сигналу SIGHUP.
void *my_handler(int nsig) {
<обробка сигналу>
}
int main() {
...
(void)signal(SIGHUP, my_handler);
...
}
Як значення параметра в призначену для користувача функцію обробки сигналу (в нашому скелеті – параметр nsig) передається номер виниклого сигналу, так що одна і та ж функція може бути використана для обробки декількох сигналів.