Linux Kernel (Ядро линукса) (часть 2)


Системные вызовы tkillQ и tgkillQ

Системные вызовы tkiiio и tgkiiio посылают сигналы конкретному процессу в группе. Функция pthread_ki.il каждой библиотеки pthread, удовлетворяющей стандарту POSIX, делает один из этих вызовов для отправки сигнала заданному облегченному процессу.

Системный вызов tkiiio принимает два параметра: pid— идентификатор процесса, которому посылается сигнал, и sig— номер сигнала. Служебная процедура sys tkiii о заполняет таблицы siginfo, вычисляет адрес дескриптора процесса, делает некоторые проверки (вроде тех, что описаны в шаге 2
в разд. "Функция group_send_sig_info()ff ранее в этой главе) и вызывает функцию specif ic send sig info , Чтобы ПОСЛатЬ СИГНал.

Системный вызов tgkiiio отличается от tkiiio, поскольку имеет третий параметр, tgid — идентификатор группы потоков, в которую входит процесс- получатель сигнала. Служебная процедура sys tgkiiio выполняет те же действия, что и sys tkiiio, но, кроме того, проверяет принадлежность процесса-получателя к группе tgid. Эта дополнительная проверка решает проблему одновременного доступа, которая возникает, когда уничтожаемому процессу посылается какой-то сигнал: если другое многопоточное приложение создает облегченные процессы достаточно быстро, сигнал может быть доставлен не тому процессу. Системный вызов tgkiii о справляется с ситуацией, потому что идентификатор группы потоков не меняется на протяжении существования многопоточного приложения.

Изменение действия сигнала

Системный вызов sigaction(sig,act,oact) позволяет пользователям определять действие сигнала. Естественно, если это не сделано, ядро выполняет действие по умолчанию, ассоциированное с доставленным сигналом.

Служебная процедура sys sigactiono принимает два параметра: sig— номер сигнала и act — таблицу типа oid sigaction, которая задает новое действие.
Третий, необязательный выходной параметр oact может быть использован для получения информации о предыдущем действии, ассоциированном с сигналом. Структура oid sigaction состоит из тех же полей, что и структура sigaction, описанная ранее, но поля расположены в другом порядке.
Функция проверяет допустимость адреса act. Затем она заполняет поля sa handler, sa flags И sa mask локальной переменной new ka, имеющей ТИП k sigaction, значениями из соответствующих полей таблицы act:
get_user(new_ka.sa.sa_handler, &act->sa_handler);
get_user(new_ka.sa.sa_flags, &act->sa_flags);
get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
Функция вызывает функцию do_sigaction(), чтобы скопировать таблицу new ka в элемент с индексом sig-i в массиве current->sig->action (номер сигнала на единицу больше индекса элемента, поскольку нет сигнала с нулевым номером):
k = ¤t->sig->action[sig-1]; if (act) {
k = act;
sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); if (k->sa.sa_handler == SIG_IGN || (k->sa.sa_handler = SIG_DFL &&
(sig—SIGCONT || sig=SIGCHLD || sig==SIGWINCH || sig==SIGURG) ) ) { rm_from_queue(sigmask(sig), ¤t->signal->shared_pending); t = current; do {
rm_from_queue(sigmask(sig), ¤t->pending); recalc_sigpending_tsk(t); t = next_thread(t);
} while (t != current);
}
}

Стандарт POSIX требует, чтобы установка действия сигнала в значение sig ign или sig dfl, когда действием по умолчанию является "игнорировать”, приводила к отбрасыванию каждого висящего сигнала того же типа. Следует также обратить внимание, что, независимо от того, какие сигналы пытается замаскировать пользователь для обработчика сигнала, сигналы sigkill и sigstop никогда не маскируются.

Системный вызов sigactiono, кроме прочего, позволяет пользователю инициализировать поле sa fiags в таблице sigaction. Допустимые значения этого поля и их смысл даны в табл. 11.6.

Старые варианты System V предлагают системный вызов signal , до сих пор широко используемый программистами. В новых версиях библиотек С signal реализован с помощью функции rt_sigaction. Однако Linux до сих пор поддерживает старые библиотеки С и предлагает служебную процедуру sys_signal:
new_sa.sa.sa_handler = handler;
new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;
ret = do_sigaction(sig, &new_sa, &old_sa);
return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
Просмотр висящих заблокированных сигналов
Системный вызов sigpendingo позволяет процессу просмотреть набор висящих заблокированных сигналов, т. е. сигналов, которые были посланы, будучи заблокированными. Соответствующая служебная процедура sys_ sigpendingo принимает единственный параметр, set, содержащий адрес пользовательской переменной, в которую следует скопировать битовый массив:
sigorsets(Spending, ¤t->pending.signal,
¤t->signal->shared_pending.signal);
sigandsets(Spending, ¤t->blocked, Spending); copy_to_user(set, Spending, 4);
Модификация набора заблокированных сигналов
Системный вызов sigprocmasko позволяет процессам изменять набор заблокированных сигналов. Он действует только на обычные сигналы (не являющиеся сигналами реального времени). Служебная процедура sys_ sigprocmasko принимает три параметра:
- oset — указатель в адресном пространстве процесса на битовый массив, в котором следует сохранить предыдущую битовую маску;
- set — указатель в адресном пространстве процесса на битовый массив, содержащий новую битовую маску;
- how — флаг, принимающий одно из следующих значений:
• sig block— массив-маска set задает сигналы, которые должны быть добавлены к массиву-маске заблокированных сигналов;
• sig unblock— массив-маска set задает сигналы, которые должны быть удалены из массива-маски заблокированных сигналов;
• sig setmask— массив-маска set задает новую битовую маску заблокированных сигналов.

Функция вызывает функцию copy from userо, чтобы скопировать значение, на которое указывает параметр set, в локальную переменную new set, а также копирует массив-маску стандартных заблокированных сигналов процесса current в локальную переменную oid set. Затем она выполняет над этими двумя переменными действие, определяемые флагом how:
if (copy_from_user(&new_set, set, sizeof (set))) return -EFAULT; new_set &= ~(sigmask(SIGKILL)|sigmask(SIGSTOP)); old_set = current->blocked.sig[0]; if (how == SIG_BLOCK)
sigaddsetmask(¤t->blocked, new_set); else if (how == SIG_UNBLOCK)
sigdelsetmask(¤t->blocked, new_set); else if (how == SIG_SETMASK)
current->blocked.sig[0] = new_set;
else
return -EINVAL; recalc_sigpending(current);
if (oset && copy_to_user(oset, &old_set, sizeof(oset))) return -EFAULT; return 0;
Приостановка выполнения процесса
Системный вызов sigsuspendo переводит процесс в состояние task_ interrupt ible, предварительно заблокировав стандартные сигналы, заданные массивом-маской, на которую указывает параметр mask. Процесс будет разбужен только не игнорируемым, незаблокированным сигналом.
Служебная процедура sys_sigsuspend выполняет следующий код:
mask &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));
saveset = current->blocked;
siginitset(¤t->blocked, mask);
recalc_sigpending(current);
regs->eax = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE; schedule();
if (do_signal(regs, &saveset)) return -EINTR;
}

Функция schedule (выбирает, какой процесс будет выполняться дальше. Когда процесс, сделавший системный ВЫЗОВ sigsuspendo, выполняется снова, функция sys sigsuspendo ВЫЗЫВает фуНКЦИЮ do_signal() ДЛЯ ДОСТавКИ СИГ- нала, который разбудил процесс. Если последняя функция возвратит единицу, сигнал не был проигнорирован. Таким образом, системный вызов завершается возвратом кода ошибки -eintr.

Системный вызов sigsuspendo может показаться избыточным, поскольку комбинация вызовов sigprocmasko и sleep о предположительно приведет к тому же результату. На самом деле это не так. Процессы могут чередоваться в любой момент, и необходимо отдавать себе отчет, что если вы сделаете системный вызов, выполняющий действие А, а затем системный вызов, выполняющий действие В, то это не будет эквивалентно одному системному вызову, выполняющему сначала действие А, а потом — действие В.

В ЭТОМ конкретном случае системный ВЫЗОВ sigprocmasko может отменить блокирование сигнала, который будет доставлен до выполнения системного вызова sleep . Если такое произойдет, процесс может навсегда остаться в состоянии task interruptible, ожидая сигнал, который уже доставлен. Зато системный вызов sigsuspendo не разрешает отправку сигналов после отмены.
ИХ блокирования И ДО вызова функции schedule , потому что другим процессам нельзя захватывать процессор в течение этого промежутка времени.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...