Восстановить атрибуты последовательного порта даже после control-C? - PullRequest
3 голосов
/ 24 октября 2010

При использовании последовательного порта через POSIX рекомендуется сохранить исходные атрибуты с помощью tcgetattr(), прежде чем изменять их с помощью tcsetattr(), а затем восстановить их перед закрытием порта. Как насчет того, когда программа завершается нажатием клавиши control-C или когда программа получает SIGINT? Я не видел этого ни в одном из серийных уроков.

Очевидно, что функции atexit() было бы недостаточно, потому что она не вызывается обработчиком по умолчанию SIGINT. Таким образом, кажется, что необходима установка обработчика сигнала, который восстанавливает атрибуты любых последовательных портов, которые все еще открыты. Насколько безопасно вызывать tcsetattr() из обработчика сигнала?

Кто-то может просто отклонить эту проблему как несущественную, но обычно завершают программу с помощью control-C, особенно той, которая может завершать операции десятками секунд. Если в этом случае нормально не сохранять настройки последовательного порта, то, по-видимому, нет оснований их вообще сохранять. Во всяком случае, лучше не беспокоиться, чем делать это непоследовательно.

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

1 Ответ

1 голос
/ 25 октября 2010

После дальнейших исследований, я думаю, что я ответил на это к моему удовлетворению.

Во-первых, на справочной странице для сигнала я заметил, что обработчику сигнала специально разрешено вызывать tcsetattr(), наряду с несколькими другими:

Процедура обработчика сигнала должна быть очень осторожной, поскольку обработка в другом месте была прервана в некоторой произвольной точке.POSIX имеет понятие «безопасная функция».Если сигнал прерывает небезопасную функцию, а обработчик вызывает небезопасную функцию, то поведение не определено.Безопасные функции четко перечислены в различных стандартах.Список POSIX.1-2003 выглядит следующим образом: ... Повышение () `...` signal () `...` tcsetattr () `[обрезается до соответствующих]

Это настоятельно предполагает, что POSIXкомитет имел в виду именно этот тип вещей и приводит к прямому подходу, при котором вы изменяете обработчик SIGINT после того, как вы открыли серийный номер и сохранили его атрибуты, затем в своем обработчике восстановите их и старый обработчик SIGINT, затем повторно подайте сигнал:

static void (*prev_sigint)( int );
static termios saved_attr;
static int fd;

static void cleanup( int ignored )
{
    tcsetattr( fd, TCSANOW, &saved_attr );
    signal( SIGINT, prev_sigint );
    raise( SIGINT );
}

int main( void )
{
    open_serial_and_save_attrs();
    prev_sigint = signal( SIGINT, cleanup );
    ...
}
...