table of contents
- NAME
- SYNOPSIS
- DESCRIPTION
- SERVER I/O MODE
- GIVING UP THE TERMINAL
- SIGNAL HANDLING
- Process termination signals.
- Process suspension signals.
- INTERRUPTING THE EVENT LOOP
- SIGNALS CAUGHT BY GL_GET_LINE
- ABORTING LINE INPUT
- SIGNAL SAFE FUNCTIONS
- USING TIMEOUTS TO POLL
- THE SERVER DEMO PROGRAM
- FILES
- SEE ALSO
- AUTHOR
other versions
- wheezy 1.6.1-5
gl_io_mode(3) | Library Functions Manual | gl_io_mode(3) |
NAME¶
gl_io_mode, gl_raw_io, gl_normal_io, gl_tty_signals, gl_abandon_line,
gl_handle_signal, gl_pending_io - How to use gl_get_line() from an external event loop.
SYNOPSIS¶
#include <libtecla.h> int gl_io_mode(GetLine *gl, GlIOMode mode); int gl_raw_io(GetLine *gl); int gl_normal_io(GetLine *gl); int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int), void (*cont_handler)(int), void (*size_handler)(int)); void gl_abandon_line(GetLine *gl); void gl_handle_signal(int signo, GetLine *gl, int ngl); GlPendingIO gl_pending_io(GetLine *gl);
DESCRIPTION¶
The gl_get_line() function, which is documented separately in the gl_get_line(3) man page, supports two different I/O modes. These are selected by calling the gl_io_mode() function.int gl_io_mode(GetLine *gl, GlIOMode mode);
GL_NORMAL_MODE - Select the normal blocking-I/O mode. In this mode gl_get_line() doesn't return until either an error occurs of the user finishes entering a new line. This mode is the focus of the gl_get_line(3) man page. GL_SERVER_MODE - Select non-blocking server I/O mode. In this mode, since non-blocking terminal I/O is used, the entry of each new input line typically requires many calls to gl_get_line() from an external I/O-driven event loop. This mode is the focus of this man page.
SERVER I/O MODE¶
In non-blocking server I/O mode, the application is required to have an event loop which calls gl_get_line() whenever the terminal file descriptor can do the type I/O that gl_get_line() is waiting for. To determine which type of I/O gl_get_line() is waiting for, the application calls the gl_pending_io() function.GlPendingIO gl_pending_io(GetLine *gl);
GLP_READ - gl_get_line() is waiting to write a character to the terminal. GLP_WRITE - gl_get_line() is waiting to read a character from the keyboad.
GIVING UP THE TERMINAL¶
A complication that is unique to non-blocking server mode is that it requires that the terminal be left in raw mode between calls to gl_get_line(). If this weren't the case, the external event loop wouldn't be able to detect individual key-presses, and the basic line editing implemented by the terminal driver would clash with the editing provided by gl_get_line(). What this means is that any time that the terminal needs to be used for other things than entering a new input line with gl_get_line(), it needs to be restored to a usable state. In particular, whenever the process is suspended or terminated, the terminal must be returned to a normal state. If this isn't done, then depending on the characteristics of the shell that was used to invoke the program, the user may end up with a hung terminal. To this end, the gl_normal_io() function is provided for switching the terminal back to the state that it was in when raw mode was last established.int gl_normal_io(GetLine *gl);
int gl_raw_io(GetLine *gl);
SIGNAL HANDLING¶
In the previous section it was pointed out that in non-blocking server mode, the terminal must be restored to a sane state whenever a signal is received that either suspends or terminates the process. In normal I/O mode, this is done for you by gl_get_line(), but in non-blocking server mode, since the terminal is left in raw mode between calls to gl_get_line(), this signal handling has to be done by the application. Since there are many signals that can suspend or terminate a process, as well as other signals that are important to gl_get_line(), such as the SIGWINCH signal, which tells it when the terminal size has changed, the gl_tty_signals() function is provided for installing signal handlers for all pertinent signals.int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int), void (*cont_handler)(int), void (*size_handler)(int));
term_handler - This is the signal handler that is to be used to trap signals that by default terminate any process that receives them (eg. SIGINT or SIGTERM). susp_handler - This is the signal handler that is to be used to trap signals that by default suspend any process that receives them, (eg. SIGTSTP or SIGTTOU). cont_handler - This is the signal handler that is to be used to trap signals that are usually sent when a process resumes after being suspended (usually SIGCONT). Beware that there is nothing to stop a user from sending one of these signals at other times. size_handler - This signal handler is used to trap signals that are sent to processes when their controlling terminals are resized by the user (eg. SIGWINCH).
void gl_handle_signal(int signo, GetLine *gl, int ngl);
Terminal resize signals (SIGWINCH)¶
If the signal indicates that the terminal was resized, then it arranges for the next call to gl_get_line() to ask the terminal for its new size and redraw the input line accordingly. In order that gl_get_line() be called as soon as possible to do this, gl_handle_signal() also arranges that the next call to gl_pending_io() will return GLP_WRITE. Thus if the application waits for I/O in select() or poll(), then the application needs to ensure that these functions will be reliably aborted when a signal is caught and handled by the application. More on this below.Process termination signals.¶
If the signal that was caught is one of those that by default terminates any process that receives it, then gl_handle_signal() does the following steps.blocked (ie. SIGKILL and SIGSTOP can't be blocked)
GetLine objects. Note that this does nothing to any of the
GetLine objects that aren't currently in raw mode.
process-termination disposition.
results in the process being terminated.
Process suspension signals.¶
If the default disposition of the signal is to suspend the process, the same steps are executed as for process termination signals, except that when the process is later resumed, gl_handle_signal() continues, and does the following steps.that was displaced when its default disposition was substituted.
gl_handle_signal() was called, gl_handle_signal() then
calls gl_raw_io(), to resume entry of the input lines on
those terminals.
was when gl_handle_signal() was called.
INTERRUPTING THE EVENT LOOP¶
If a signal is caught and handled when the application's event loop is waiting in select() or poll(), these functions will be aborted with errno set to EINTR. When this happens the event loop should call gl_pending_io(), before calling select() or poll() again. It should then arrange for select() or poll() to wait for the type of I/O that this reports. This is necessary, because any signal handler which calls gl_handle_signal(), will frequently change the type of I/O that gl_get_line() is waiting for.by passing the signal set returned by gl_list_signals() to
sigprocmask().
select() or poll() accordingly.
indicating that control isn't resuming there after a matching
call to siglongjmp().
is configured to catch, with a signal handler that first records
the number of the signal that was caught, in a file-scope variable,
then calls siglongjmp() with a non-zero value argument, to
return execution to the above sigsetjmp()
statement. Registering these signal handlers can conveniently be
done using the gl_tty_signals() function.
record any signal that is caught to -1, so that we can check
whether a signal was caught by seeing if it contains a valid signal
number.
that was received by the process in between step 1 and now will
now be delivered, and trigger our signal handler, as will any
signal that is received until we block these signals again.
unblocked in step 7.
variable that the signal handler records signal numbers in.
again, and unblock just this signal, so that it invokes the
signal handler which we just reinstated in step 10.
SIGNALS CAUGHT BY GL_GET_LINE¶
Since the application is expected to handle signals in non-blocking server mode, gl_get_line() doesn't attempt to duplicate this when it is being called. If one of the signals that it is configured to catch is sent to the application while gl_get_line() is being called, gl_get_line() reinstates the caller's signal handlers, then just before returning, re-sends the signal to the process to let the application's signal handler handle it. If the process isn't terminated by this signal, gl_get_line() returns NULL, and a following call to gl_return_status() returns the enumerated value GLR_SIGNAL.ABORTING LINE INPUT¶
Often, rather than letting it terminate the process, applications respond to the SIGINT user-interrupt signal by aborting the current input line. The way to do this in non-blocking server-I/O mode is to not call gl_handle_signal() when this signal is caught, but instead to call the gl_abandon_line().void gl_abandon_line(GetLine *gl);
SIGNAL SAFE FUNCTIONS¶
Provided that certain rules are followed, the following functions can have been written to be safely callable from signal handlers. Other functions in this library should not be called from signal handlers.gl_normal_io() gl_raw_io() gl_handle_signal() gl_abandon_line()
USING TIMEOUTS TO POLL¶
If instead of using select() or poll() to wait for I/O, your application just needs to get out of gl_get_line() periodically to briefly do something else before returning to accept input from the user, this can be done in non-blocking server mode by using the gl_inactivity_timeout() function (see gl_get_line(3)), to specify that a callback function that returns GLTO_CONTINUE should be called whenever gl_get_line() has been waiting for I/O for more than a specified amount of time.THE SERVER DEMO PROGRAM¶
The demo3 program that is distributed with the library, provides a working example of how to use non-blocking server I/O mode in a real program. As far as the user is concerned, this program operates identically to the main demo program (called demo), except that whereas the main demo program uses the normal blocking I/O mode, demo3 using non-blocking I/O and an external event loop. The source code can be found in demo3.c, and the comments therein explain the various steps.FILES¶
libtecla.a - The tecla library libtecla.h - The tecla header file.
SEE ALSO¶
libtecla(3), gl_get_line(3), tecla(7), ef_expand_file(3), cpl_complete_word(3), pca_lookup_file(3)