Section 20.5. Managing VC Switching

   


20.5. Managing VC Switching

To find an unused VC (that is, a VC currently referenced by no processes' open file descriptors) to activate, use the VT_OPENQRY ioctl:

 retcode = ioctl(fd, VT_OPENQRY, &vtnum); if ((retcode < 0) || (vtnum == -1)) {     perror("myapp: no available virtual terminals");     /* take appropriate action /* } 


If fewer than 63 VCs are in use and all the currently allocated VCs are in use, a new VC is allocated dynamically by the kernel.[4]

[4] Most other systems with virtual consoles or virtual terminals do not dynamically allocate them.

To trigger a switch to another VC (perhaps the available one that you just found), use the VT_ACTIVATE ioctl. Use the VT_WAITACTIVE ioctl if you wish to wait for the VC to become active. Changing VCs can take some time possibly several seconds because the console to which you are switching may be in graphical mode and the contents of the screen may have to be reconstructed from memory, fetched from swap, or rebuilt in some other time-consuming manner.[5]

[5] Certain systems (but not Linux) initiate a switch automatically if one is not in progress and VT_WAITACTIVE is called.

 ioctl(fd, VT_ACTIVATE, vtnum); ioctl(fd, VT_WAITACTIVE, vtnum); 


To exercise control over when VC switches take place, or simply to be notified of such switches, you must provide reliable signal handlers with sigaction, as discussed in Chapter 12. We use SIGUSR1 and SIGUSR2 here; if you prefer, you can reuse almost any other two signals that you do not intend to use otherwise, such as SIGPROF or SIGURG. Just make sure that the signals you choose meet the following criteria:

  • They are not needed for other system functions, especially signals that cannot be trapped or ignored.

  • They are not used elsewhere in your application for other purposes.

  • They are not the same signal number with two different names, such as SIGPOLL and SIGIO (see the definitions in /usr/include/asm/signal.h, or restrict yourself to signals from Table 12.1 on page 217).

 void relsig (int signo) {     /* take appropriate action to release VC */ } void acqsig (int signo) {     /* take appropriate action to acquire VC */ } void setup_signals(void) {     struct sigaction sact;     /* Do not mask any signals while these      * handlers are being called. */     sigemptyset(&sact.sa_mask);     /* You may wish to add calls to sigaddset()      * here if there are signals that you wish to mask      * during VC switching. */     sact.flags = 0;     sact.sa_handler = relsig;     sigaction(SIGUSR1, &sact, NULL);     sact.sa_handler = acqsig;     sigaction(SIGUSR2, &sact, NULL); } 


You then need to change the VC mode from VT_AUTO (the default) to VT_PROCESS, while telling the VC about your signal handlers by setting relsig and 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); } 


The signal handlers that are called when a VC is in VT_PROCESS mode do not have to agree to the switch. More precisely, the relsig handler may refuse to allow the VC switch to take place. The acqsig handler usually manages the process of taking over the console, but it could conceivably initiate a switch to yet another VC. Be careful in coding your signal handlers not to call any nonreentrant library functions that cannot be called from a signal handler. POSIX.1 specifies that the functions listed in Table 12.2 are reentrant; you should consider all others nonreentrant, especially if you wish to write a portable program. Note in particular that malloc() and printf() are nonreentrant.

Here are examples of relsig() and acqsig() functions that do useful work. Note that, for the relsig() function, calling VT_RELDISP is required, but for the acqsig() function, calling VT_RELDISP is recommended only for the sake of portability.

 void relsig (int signo) {     if (change_vc_ok()) {         /* VC switch allowed */         save_state();         ioctl(fd, VT_RELDISP, 1);     } else {         /* VC switch disallowed */         ioctl(fd, VT_RELDISP, 0);     } } void acqsig (int signo) {     restore_state();     ioctl(fd, VT_RELDISP, VT_ACKACQ); } 


It is up to you to implement the change_vc_ok(), save_state(), and restore_state() code.

VCs are allocated dynamically when they are opened, but they are not reaped automatically when they are closed. To reap the kernel memory used to store the state of a VC, you need to call an ioctl:

 ioctl(fd, VT_DISALLOCATE, vtnum); 


You can disable and reenable VC switching completely with a few simple ioctls:

 void disallow_vc_switch(int fd) {     ioctl(fd, VT_LOCKSWITCH, 0); } void allow_vc_switch(int fd) {     ioctl(fd, VT_UNLOCKSWITCH, 0); } 



       
    top
     


    Linux Application Development
    Linux Application Development (paperback) (2nd Edition)
    ISBN: 0321563220
    EAN: 2147483647
    Year: 2003
    Pages: 168

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net