Сигнал линукс для чего

Практика работы с сигналами

Хочу запечатлеть небольшой опыт работы с сигналами в Linux. Ниже будут представлены примеры использования наиболее значимых конструкций в этой области. Постараюсь разложить все по отдельным полочкам, чтобы всегда было легко глянуть и вспомнить, что и как использовать.

Важные факты о сигналах:

  • Сигналы в Linux играют роль некоего средства межпроцессного взаимодействия (а так же и межпоточного)
  • Каждый процесс имеет маску сигналов (сигналов, получение которых он игнорирует)
  • Каждая нить (thread), так же как и процесс, имеет свою маску сигналов
  • При получении сигнала(если он не блокируется) процесс/нить прерывается, управление передается в функцию обработчик сигнала, и если эта функция не приводит к завершению процесса/нити, то управление передается в точку на которой процесс/нить была прервана
  • Можно установить свою функцию обработчик сигнала, но только для процесса. Данный обработчик будет вызываться и для каждой нити порожденной из этого процесса

Я не буду углубляться в теорию сигналов, что откуда зачем и куда. Меня в первую очередь интересует сам механизм работы с ними. Поэтому в качестве используемых сигналов будут выступать SIGUSR1 и SIGUSR2, это два единственных сигнала отданных в полное распоряжение пользователя. А так же я постараюсь уделить больше внимание именно межпоточному взаимодействию сигналов.
Итак, поехали.

Функция обработчик сигналов

Данная функция вызывается, когда процесс (или нить) получает неблокируемый сигнал. Дефолтный обработчик завершает наш процесс (нить). Но мы можем сами определить обработчики для интересующих нас сигналов. Следует очень осторожно относится к написанию обработчика сигналов, это не просто функция, выполняющаяся по коллбеку, происходит прерывание текущего потока выполнения без какой либо подготовительной работы, таким образом глобальные объекты могут находится в неконсистентном состоянии. Автор не берется приводить свод правил, так как сам их не знает, и призывает последовать совету Kobolog (надеюсь он не против, что я ссылаюсь на него) и изучить хотя бы вот этот материал FAQ.

Установить новый обработчик сигнала можно двумя функциями

Которая принимает номер сигнала, указатель на функцию обработчик (или же SIG_IGN (игнорировать сигнал) или SIG_DFL (дефолтный обработчик)), и возвращает старый обработчик. Сигналы SIGKILL и SIGSTOP не могут быть «перехвачены» или проигнорированы. Использование этой функции крайне не приветствуется, потому что:

  • функция не блокирует получение других сигналов пока выполняется текущий обработчик, он будет прерван и начнет выполняться новый обработчик
  • после первого получения сигнала (для которого мы установили свой обработчик), его обработчик будет сброшен на SIG_DFL

Этих недостатков лишена функция

Которая также принимает номер сигнала (кроме SIGKILL и SIGSTOP). Второй аргумент это новое описание для сигнала, через третий возвращается старое значение. Структура struct sigaction имеет следующие интересующие нас поля

  • sa_handler — аналогичен sighandler_t в функции signal
  • sa_mask — маска сигналов который будут блокированы пока выполняется наш обработчик. + по дефолту блокируется и сам полученный сигнал
  • sa_flags — позволяет задать дополнительные действия при обработке сигнала о которых лучше почитать тут

Использование данной функции выглядит совсем просто

Здесь мы установили наш обработчик для сигналов SIGUSR1 и SUGUSR2, а также указали, что необходимо блокировать эти же сигналы пока выполняется обработчик.
С обработчиком сигналов есть один не очень удобный момент, он устанавливается на весь процесс и все порожденные нити сразу. Мы не имеет возможность для каждой нити установить свой обработчик сигналов.
Но при этом следует понимать что когда сигнал адресуется процессу, обработчик вызывается именно для главной нити (представляющей процесс). Если же сигнал адресуется для нити, то обработчик вызывается из контекста этой нити. См пример 1.

Читайте также:  Bootia32 efi windows 10

Блокирование сигналов

Для того, чтобы заблокировать некоторый сигналы для процесса, необходимо добавить их в маску сигналов данного процесса. Для этого используется функция

Мы можем к уже существующей маске сигналов добавить новые сигналы (SIG_BLOCK), можем из этой маски убрать часть сигналов (SIG_UNBLOCK), а так же установить полностью нашу маску сигналов (SIG_SETMASK).
Для работы с маской сигналов внутри нити используется функция

которая позволяет сделать все тоже, но уже для каждой нити в отдельности.
Невозможно заблокировать сигналы SIGKILL или SIGSTOP при помощи этих функций. Попытки это сделать будут игнорироваться.

sigwait

Данная функция позволяет приостановить выполнении процесса (или нити) до получения нужного сигнала (или одного из маски сигналов). Особенностью этой функции является то, что при получении сигнала не будет вызвана функции обработчик сигнала. См. пример 2.

Посыл сигнала

Для того, чтобы послать сигнал процессу можно использовать две функции

С первой все понятно. Вторая нужна для того, чтобы послать сигнал самому себе, и по сути равносильна kill(getpid(), signal). Функция getpid() возвращает PID текущего процесса.
Для того, чтобы послать сигнал отдельной нити, используется функция

Пример использования сигналов

Все, что я описал выше, не дает ответа на вопрос «Зачем мне использовать сигналы». Теперь я хотел бы привести реальный пример использования сигналов и где без них попросту не обойтись.
Представьте, что вы хотите читать или писать какие-то данные в какое то устройство, но это может привести к блокированию. Ну например, чтение в случае работы с сокетами. Или может быть запись в пайп. Вы можете вынести это в отдельный поток, чтобы не блокировать основную работу. Но что делать когда вам нужно завершить приложение? Как корректно прервать блокирующую операцию IO? Можно было бы задавать таймаут, но это не очень хорошее решение. Для этого есть более удобные средства: функции pselect и ppoll. Разница между ними исключительно в юзабельности, поведение у них одинаковое. В первую очередь эти функции нужны для мультиплексирования работы с IO (select/poll). Префикс ‘p’ в начале функции указывает на то, что данная функция может быть корректно прервана сигналом.

Итак, сформулируем требование:
Необходимо разработать приложение, открывающее сокет (для простоты UDP) и выполняющее в потоке операцию чтения. Данное приложение должно корректно без задержек завершаться по требованию пользователя.
Функция треда выглядит вот так

stop это глобальный булев флаг который устанавливается в true нашим обработчиком, что сообщает потоку о необходимости завершиться.
Логика работы такая:

  • проверяем, что пока стартовал тред его еще не пожелали завершить
  • блокируем завершающий сигнал
  • проверяем, что пока блокировали, нас не пожелали завершить
  • вызываем ppoll передавая в качестве последнего параметра маску сигналов по которой ждется сигнал
  • после выхода из ppoll проверяем что вышли не из за сигнала о завершении

Вот так выглядит главная функция

Устанавливаем наш обработчик для SIGINT, и когда нужно завершить дочерний поток шлем ему этот сигнал.
Полный листинг см. пример 3.

На мой взгляд, недостатком данного способа является то, что в случае нескольких потоков мы можем завершить их только все сразу. Нет возможности устанавливать свой обработчик сигналов для каждого треда. Таким образом, нет возможности реализовать полноценное межпоточное взаимодействие через сигналы. Linux way это не предусматривает.

Читайте также:  Это приложение не совместимо с данным устройством windows 10 mobile

PS. Исходные коды разместил на сервисе PasteBin (ссылку не даю, а то еще за рекламу посчитают).
PPS. Прошу простить за обилие ошибок. Язык, слабая моя сторона. Спасибо, всем кто помог их исправить.

Данная статья не претендует на полное (и глубокое) описание работы с сигналами и нацелена в первую очередь на тех, кто до этого момента не сталкивались с понятием «сигнал». Для более глубоко понимания работы сигналов автор призывает обратиться в более компетентные источники и ознакомиться с конструктивной критикой в комментариях.

Источник

Передача файла сигналами

Добрый день, хабражители. Наверняка все знают что такое сигналы в Linux и для чего они нужны. Но сегодня, я хотел бы рассказать о, как мне кажется, нетрадиционном их применении.

Задача очень надуманная и направленна на тренировку своих навыков работы с сигналами и, немножко, побитовыми операциями. В общем, задача:
Программа должна порождать процесс, который посредством только сигналов передавал родителю файл, указанный в качестве аргумента командной строки. Родитель выводит полученный файл в stdout.

Решение очень простое: будем пользоваться сигналами, как азбукой морзе, только использоваться будт SIGUSR1 и SIGUSR2 вместо «Точка» и «Тире».

Решение

Будем передавать файл побитово, с помощью сигналов SIGUSR2 и SIGUSR1
Пускай SIGUSR2 — бит равный нулю, SIGUSR1 — бит равный единице.

Отправка данных

Читаем байт из файла в переменную с.
Создаем переменную counter равную 0b10000000 или 128.
Если c И (имеется в виду «побитовое и») counter равно единице, то старший бит равен единице, посылаем SIGUSR1, иначе посылаем SIGUSR2.
Делим counter пополам (получаем 0b01000000 или 64), то есть переходим ко второму слева биту.
Повторяем до тех пор, пока counter не станет равен нулю. Затем читаем новый байт из файла.

На языке Си это выглядит следующим образом:

Прием данных

Принимать мы будем в переменную out_char, изначально равную нулю.
Пока counter не равен нулю обрабатываем сигналы следующим образом:
Если пришел SIGUSR1, то out_char += counter, затем counter /= 2.
Если пришел SIGUSR1, то counter /= 2.

Напишем обработчики для сигналов:

Рабочий вариант

Теперь нужно рассмотреть случаи непредвиденной смерти родителя или ребёнка. Если умрет ребёнок, то всё просто — родитель получит SIGCHLD.

С ребёнком будет немного сложнее, нет гарантии что ребёнка как либо известят о смерти его родителя. Поэтому попросим ядро отправить нам SIGALRM, если никаких других сигналов нам не отправят через заданный промежуток времени. Добавим это в отправляющий цикл:

Добавим механизм подтверждения получения сигнала от ребёнка родителем. То есть, пока родитель не подтвердит получение бита, ребёнок передавать следующий не будет.

Делается это просто, в функции one и zero надо добавить отправку ответа. Будем отвечать сигналом SIGUSR1. После изменений функции будут выглядеть следующим образом:

А для ожидания ребёнком подтверждения добавим sigsuspend(&set):

Функция выполняемая при приходе от родителя сигнала подтверждения хоть и пустая, но должна быть, иначе будет выполняться действие для сигнала по-умолчанию — Выход.

Собственно функция и set:

В родителе же маска сигналов должна быть следующей:

Так как в процессе работы программы произойдет порождение нового процесса, который сразу же начнет слать нам сигналы (данные), sigprocmask(SIG_BLOCK, &set, NULL ) нужно сделать обязательно до fork’а, иначе есть шанс получить ошибку из-за эффекта гонки (race condition).
В итоге программа будет выглядеть так:

Читайте также:  Astra linux login incorrect

Исходный код программы можно скачать тут.

Вот так можно передавать файлы от одной программы другой, с помощью одних лишь сигналов. Правда такой подход мало эффективен и я не думаю, что ему есть применение в реальных проектах.

Источник

Signal — достойный клиент для пользователей Linux

Signal, часто рассматривается как золотой стандарт, когда речь заходит о зашифрованных приложениях обмена сообщениями.

О Signal

Приложение предлагает ряд функций, которые делают его сопоставимым с WhatsApp. Здесь есть все необходимое, от текстовых звонков до видеозвонков, групповых чатов и смайликов. Клиент невероятно прост в использовании по сравнению с другими безопасными формами общения, такими как PGP.

Signal выделяется своей настройкой шифрования, которая организована таким образом, что компания, не получает доступ к вашим данным или ключам.

Одним из основных недостатков приложения для безопасности является то, что для регистрации требуется номер телефона. Это используется для проверки учетной записи пользователя, устраняя необходимость в именах пользователей и паролях. В результате, облегчается поиск контактов, которые используют мессенджер.

Некоторые пользователи не хотят передавать номер телефона, но это необходимо только для настройки учетной записи. Пользователи используют номер VoIP, стационарный или не персональный номер, так что есть обходные пути.

Приложение бесплатно без рекламы, и не собирает и не продает свои пользовательские данные. В настоящее время — финансируется за счет грантов и пожертвований.

Хотя эти детали не делают Signal автоматически заслуживающей доверия организацией, но делает его более надежным. Потому что, конкуренты полагаются на интеллектуальный анализ данных, чтобы заработать миллиарды.

Самый большой недостаток Signal заключается в том, что он далеко не так популярен, как приложения, такие как WhatsApp. Мессенджер популярен среди журналистов, активистов, политиков и других лиц, имеющих дело с конфиденциальной информацией. При этом клиент не получил такого же широкого распространения, как его более крупные конкуренты.

Это означает, что вы не сможете использовать его для сообщения многим своим друзьям, семье или коллегам. Хотя это один из лучших вариантов, когда вы имеете дело с конфиденциальной или ценной информацией. В результате, возможно, придется вернуться к менее безопасным альтернативам, таким как WhatsApp или Facebook Messenger, чтобы общаться с широким кругом пользователей.

Signal 4.53.6

Основные изменения которые произошли в последних редакциях:

  • Отправляйте отдельные фотографии и видео, которые не останутся в вашей истории разговоров.
  • Лучшая логика датчика приближения вызова помогает разочарованным пользователям Bluetooth.
  • Поддержка возобновления прерванных загрузок
  • Отправляйте стикеры в разговоре, добавляя их к изображениям с помощью графического редактора
  • Если вы используете клиент в качестве SMS-клиента по умолчанию, новая локально созданная панель мониторинга Insights может помочь вам определить, сколько ваших исходящих сообщений отправляется безопасно.

Установка

  1. sudo apt install curl
  2. curl -s https://updates.signal.org/desktop/apt/keys.asc | sudo apt-key add —
  3. echo «deb [arch=amd64] https://updates.signal.org/desktop/apt xenial main» | sudo tee -a /etc/apt/sources.list.d/signal-xenial.list
  4. echo «deb [arch=amd64] https://updates.signal.org/desktop/apt xenial main» | sudo tee -a /etc/apt/sources.list.d/signal-xenial.list

Вывод

К счастью, существует множество приложений для обмена сообщениями, в которых конфиденциальность ценится выше чем удобство. Наш мессенджер один из них.

Клиент делает почти все, что может WhatsApp. Signal использует подключение для передачи данных для отправки зашифрованных сообщений — или голосовых заметок, изображений или видео — отдельным лицам и группам. Как и в WhatsApp, мессенджер позволяет совершать голосовые и видеозвонки.

Источник

Оцените статью