20.5. Управление переключением виртуальных консолей
Для того чтобы найти неиспользуемую VC (другими словами, консоль, на которую в данный момент не ссылается ни один открытый файловый дескриптор в процессах) и активизировать ее, используется команда управления вводом-выводом VT_OPENQRY
.
retcode = ioctl(fd, VT_OPENQRY, &vtnum);
if ((retcode < 0) || (vtnum == -1)) {
perror("myapp: нет доступных виртуальных терминалов");
/* выполнить соответствующее действие */
}
Если в настоящее время используется менее 63 VC, и все из них заняты, то ядро автоматически выделяет память для новой VC[152].
Для запуска переключения на другую VC (например, на ту свободную консоль, которую вы только что обнаружили) используется команда управления вводом-выводом VT_ACTIVATE
. Если нужно подождать до тех пор, пока консоль не станет активной, применяется команда VT_WAITACTIVE
. Смена консоли может занять некоторое время, возможно, несколько секунд. Это объясняется тем, что активизируемая консоль может находиться в графическом режиме, при этом содержимое экрана нужно реконструировать из памяти, выбрать из буфера обмена или восстановить каким-то другим способом, отнимающим немало времени[153].
ioctl(fd, VT_ACТIVATE, vtnum);
ioctl(fd, VT_WAITACTIVE, vtnum);
Для осуществления контроля над переключениями VC или для получения уведомлений о подобных переключениях необходимо предусмотреть надежные обработчики сигналов с sigaction
, как обсуждалось в главе 12. Здесь мы применяем SIGUSR1
и SIGUSR2
; если нужно, вы можете использовать любые другие два сигнала, которые не предназначены для других целей (например, SIGPROF
и SIGURG
). Просто убедитесь, что выбранные вами сигналы удовлетворяют перечисленным ниже критериям.
• Они не требуются остальным системным функциям, особенно это касается тех сигналов, которые не могут быть перехвачены или проигнорированы.
• Они нигде не используются в вашем приложении для других целей.
• Они не представляют один и тот же сигнальный номер с двумя различными именами, как SIGPOLL
и SIGIO
(определения смотрите в /usr/include/asm/signal.h
, либо ограничьте себя использованием сигналов из табл. 12.1).
void relsig(int signo) {
/* выполнить соответствующее действие для освобождения VC */
}
void acqsig(int signo) {
/* выполнить соответствующее действие для запроса VC */
}
void setup_signals(void) { struct sigaction sact;
/* He маскировать никаких сигналов в то время,
* когда активизированы данные обработчики. */
sigemptyset(&sact.sa_mask);
/* Здесь может понадобиться добавление вызовов sigaddset(),
* если существуют сигналы, которые нужно маскировать
* при переключении VC. */
sact.flags = 0;
sact.sa_handler = relsig;
sigaction(SIGUSR1, &sact, NULL);
sact.sa_handler = acqsig;
sigaction(SIGUSR2, &sact, NULL);
}
После этого потребуется изменить стандартный режим VC (mode
) с VT_AUTO
на VT_PROGRESS
, пока консоль уведомляется об обработчиках сигналов путем установки relsig
и acqsig
.
void control_vc_switching(int fd) {
struct vt_mode vtmode;
vtmode.mode = VT_PROCESS;
vtmode.waitv = 1;
vtmode.relsig = SIGUSR1;
vtmode.acqsig = SIGUSR2;
vtmode.frsig = 0;
ioctl(fd, VT_SETMODE, &vtmode);
}