1gl_io_mode(3TECLIAn)teractive Command-line Input Library Functiognls_io_mode(3TECLA)
2
3
4

NAME

6       gl_io_mode,  gl_raw_io,  gl_normal_io, gl_tty_signals, gl_abandon_line,
7       gl_handle_signal, gl_pending_io - use gl_get_line()  from  an  external
8       event loop
9

SYNOPSIS

11       cc [ flag... ] file... -ltecla [ library... ]
12       #include <libtecla.h>
13
14       int gl_io_mode(GetLine *gl, GlIOMode mode);
15
16
17       int gl_raw_io(GetLine *gl);
18
19
20       int gl_normal_io(GetLine *gl);
21
22
23       int gl_tty_signals(void (*term_handler)(int), void (*susp_handler)(int),
24            void (*cont_handler)(int), void (*size_handler)(int));
25
26
27       void gl_abandon_line(GetLine *gl);
28
29
30       void gl_handle_signal(int signo, GetLine *gl, int ngl);
31
32
33       GlPendingIO gl_pending_io(GetLine *gl);
34
35

DESCRIPTION

37       The  gl_get_line(3TECLA)  function  supports  two  different I/O modes.
38       These are selected by calling the gl_io_mode() function. The mode argu‐
39       ment  of gl_io_mode() specifies the new I/O mode and must be one of the
40       following.
41
42       GL_NORMAL_MODE    Select the normal blocking-I/O  mode.  In  this  mode
43                         gl_get_line()  does  not return until either an error
44                         occurs of the user finishes entering a new line.
45
46
47       GL_SERVER_MODE    Select non-blocking server I/O mode.  In  this  mode,
48                         since non-blocking terminal I/O is used, the entry of
49                         each new input line typically requires many calls  to
50                         gl_get_line() from an external I/O-driven event loop.
51
52
53
54       Newly created GetLine objects start in normal I/O mode, so to switch to
55       non-blocking server mode requires an initial call to gl_io_mode().
56
57   Server I/O Mode
58       In non-blocking server I/O mode, the application is required to have an
59       event loop that calls gl_get_line() whenever the terminal file descrip‐
60       tor can perform the type I/O that  gl_get_line()  is  waiting  for.  To
61       determine  which type of I/O gl_get_line() is waiting for, the applica‐
62       tion calls the gl_pending_io() function.  The return value  is  one  of
63       the following two enumerated values.
64
65       GLP_READ     gl_get_line()  is waiting to write a character to the ter‐
66                    minal.
67
68
69       GLP_WRITE    gl_get_line() is waiting to read a character from the key‐
70                    boad.
71
72
73
74       If  the  application is using either the select(3C) or poll(2) function
75       to watch for I/O on a group of file descriptors, then  it  should  call
76       the  gl_pending_io()  function  before  each call to these functions to
77       determine which direction of I/O it should tell them to watch for,  and
78       configure  their  arguments  accordingly.  In  the case of the select()
79       function, this means using the FD_SET() macro to add the terminal  file
80       descriptor  either  to  the  set  of file descriptors to be watched for
81       readability or the set to be watched for writability.
82
83
84       As in normal I/O mode, the return value of gl_get_line()  is  either  a
85       pointer  to  a completed input line or NULL. However, whereas in normal
86       I/O mode a NULL return value always means that an  error  occurred,  in
87       non-blocking server mode, NULL is also returned when gl_get_line() can‐
88       not read or write to the terminal without blocking. Thus in  non-block‐
89       ing  server mode, in order to determine when a NULL return value signi‐
90       fies that an error occurred  or  not,  it  is  necessary  to  call  the
91       gl_return_status()  function.  If  this function returns the enumerated
92       value GLR_BLOCKED, gl_get_line() is waiting for I/O and  no  error  has
93       occurred.
94
95
96       When  gl_get_line()  returns NULL and gl_return_status() indicates that
97       this is due to  blocked  terminal  I/O,  the  application  should  call
98       gl_get_line()  again  when  the type of I/O reported by gl_pending_io()
99       becomes possible. The prompt, start_line  and  start_pos  arguments  of
100       gl_get_line() will be ignored on these calls. If you need to change the
101       prompt of the line that is currently being edited,  you  can  call  the
102       gl_replace_prompt(3TECLA) function between calls to gl_get_line().
103
104   Giving Up The Terminal
105       A  complication  that  is unique to non-blocking server mode is that it
106       requires that the terminal  be  left  in  raw  mode  between  calls  to
107       gl_get_line(). If this were not the case, the external event loop would
108       not be able to detect individual key-presses, and the basic line  edit‐
109       ing  implemented  by  the  terminal driver would clash with the editing
110       provided by gl_get_line(). When the terminal needs to be used for  pur‐
111       poses other than entering a new input line with gl_get_line(), it needs
112       to be restored to a usable state. In particular, whenever  the  process
113       is  suspended  or terminated, the terminal must be returned to a normal
114       state. If this is not done, then depending on  the  characteristics  of
115       the  shell  that  was used to invoke the program, the user could end up
116       with a hung terminal. To this end, the gl_normal_io() function is  pro‐
117       vided  for switching the terminal back to the state that it was in when
118       raw mode was last established.
119
120
121       The gl_normal_io() function first flushes any  pending  output  to  the
122       terminal, then moves the cursor to the start of the terminal line which
123       follows the end of the incompletely entered input line. At  this  point
124       it  is safe to suspend or terminate the process, and it is safe for the
125       application to read and write to the terminal. To resume entry  of  the
126       input line, the application should call the gl_raw_io() function.
127
128
129       The gl_normal_io() function starts a new line, redisplays the partially
130       completed input line (if any), restores the cursor position within this
131       line to where it was when gl_normal_io() was called, then switches back
132       to raw, non-blocking terminal mode ready to continue entry of the input
133       line when gl_get_line() is next called.
134
135
136       Note that in non-blocking server mode, if gl_get_line() is called after
137       a call to gl_normal_io(), without an intervening call  to  gl_raw_io(),
138       gl_get_line()  will  call  gl_raw_mode()  itself, and the terminal will
139       remain in this mode when gl_get_line() returns.
140
141   Signal Handling
142       In the previous section it was pointed out that in non-blocking  server
143       mode,  the  terminal must be restored to a sane state whenever a signal
144       is received that either suspends or terminates the process.  In  normal
145       I/O  mode,  this  is done for you by gl_get_line(), but in non-blocking
146       server mode, since the terminal is left in raw mode  between  calls  to
147       gl_get_line(),  this signal handling has to be done by the application.
148       Since there are many signals that can suspend or terminate  a  process,
149       as  well  as other signals that are important to gl_get_line(), such as
150       the SIGWINCH signal, which tells it when the terminal size has changed,
151       the  gl_tty_signals()  function  is provided for installing signal han‐
152       dlers for all pertinent signals.
153
154
155       The gl_tty_signals() function uses  gl_get_line()'s  internal  list  of
156       signals  to  assign specified signal handlers to groups of signals. The
157       arguments of this function are as follows.
158
159       term_handler    This is the signal handler that is used to trap signals
160                       that  by  default  terminate  any process that receives
161                       them (for example, SIGINT or SIGTERM).
162
163
164       susp_handler    This is the signal handler that is used to trap signals
165                       that by default suspend any process that receives them,
166                       (for example, SIGTSTP or SIGTTOU).
167
168
169       cont_handler    This is the signal handler that is used to trap signals
170                       that  are  usually  sent  when  a process resumes after
171                       being suspended (usually SIGCONT). Beware that there is
172                       nothing  to  stop a user from sending one of these sig‐
173                       nals at other times.
174
175
176       size_handler    This signal handler is used to trap  signals  that  are
177                       sent  to processes when their controlling terminals are
178                       resized by the user (for example, SIGWINCH).
179
180
181
182       These arguments can all be the same, if so desired, and SIG_IGN (ignore
183       this  signal)  or  SIG_DFL (use the system-provided default signal han‐
184       dler) can be specified instead of a function where pertinent.  In  par‐
185       ticular, it is rarely useful to trap SIGCONT, so the cont_handler argu‐
186       ment will usually be SIG_DFL or SIG_IGN.
187
188
189       The gl_tty_signals() function uses the POSIX sigaction(2)  function  to
190       install  these  signal  handlers,  and it is careful to use the sa_mask
191       member of each sigaction structure to ensure that  only  one  of  these
192       signals  is  ever  delivered  at  a time. This guards against different
193       instances of these signal handlers from simultaneously trying to  write
194       to  common global data, such as a shared sigsetjmp(3C) buffer or a sig‐
195       nal-received flag. The  signal  handlers  installed  by  this  function
196       should call the gl_handle_signal().
197
198
199       The  signo  argument tells this function which signal it is being asked
200       to respond to, and the gl argument should be a  pointer  to  the  first
201       element  of  an  array  of ngl GetLine objects. If your application has
202       only one of these objects, pass its pointer  as  the  gl  argument  and
203       specify ngl as 1.
204
205
206       Depending  on the signal that is being handled, this function does dif‐
207       ferent things.
208
209   Process termination signals
210       If the signal that was caught is one of those that  by  default  termi‐
211       nates  any  process  that receives it, then gl_handle_signal() does the
212       following steps.
213
214           1.     First it blocks the delivery of  all  signals  that  can  be
215                  blocked (ie. SIGKILL and SIGSTOP cannot be blocked).
216
217           2.     Next  it  calls  gl_normal_io()  for each of the ngl GetLine
218                  objects. Note that this does nothing to any of  the  GetLine
219                  objects that are not currently in raw mode.
220
221           3.     Next  it  sets  the  signal  handler  of  the  signal to its
222                  default, process-termination disposition.
223
224           4.     Next it re-sends the process the signal that was caught.
225
226           5.     Finally it unblocks delivery of this signal,  which  results
227                  in the process being terminated.
228
229   Process suspension signals
230       If the default disposition of the signal is to suspend the process, the
231       same steps are executed as for process termination signals, except that
232       when  the  process  is later resumed, gl_handle_signal() continues, and
233       does the following steps.
234
235           1.     It re-blocks delivery of the signal.
236
237           2.     It reinstates the signal handler of the signal  to  the  one
238                  that  was displaced when its default disposition was substi‐
239                  tuted.
240
241           3.     For any of the GetLine objects that were in  raw  mode  when
242                  gl_handle_signal() was called, gl_handle_signal() then calls
243                  gl_raw_io(), to resume entry of the  input  lines  on  those
244                  terminals.
245
246           4.     Finally,  it  restores the signal process mask to how it was
247                  when gl_handle_signal() was called.
248
249
250       Note that the process is suspended or  terminated  using  the  original
251       signal  that  was caught, rather than using the uncatchable SIGSTOP and
252       SIGKILL signals. This is important, because when a process is suspended
253       or  terminated,  the  parent  of the process may wish to use the status
254       value returned by the wait system call to figure out which  signal  was
255       responsible. In particular, most shells use this information to print a
256       corresponding message to the terminal. Users would be rightly  confused
257       if  when their process received a SIGPIPE signal, the program responded
258       by sending itself a SIGKILL signal, and the shell then printed out  the
259       provocative statement, "Killed!".
260
261   Interrupting The Event Loop
262       If  a signal is caught and handled when the application's event loop is
263       waiting in select() or poll(), these functions  will  be  aborted  with
264       errno  set  to  EINTR.  When  this  happens  the event loop should call
265       gl_pending_io() before calling select() or poll() again. It should then
266       arrange  for  select()  or  poll()  to  wait  for  the type of I/O that
267       gl_pending_io() reports. This is necessary because any  signal  handler
268       that  calls  gl_handle_signal()  will frequently change the type of I/O
269       that gl_get_line() is waiting for.
270
271
272       If a signal arrives between the statements that configure the arguments
273       of select() or poll() and the calls to these functions, the signal will
274       not be seen by these functions, which will  then  not  be  aborted.  If
275       these  functions  are waiting for keyboard input from the user when the
276       signal is received, and the signal handler arranges to redraw the input
277       line to accommodate a terminal resize or the resumption of the process.
278       This redisplay will be delayed until the user  presses  the  next  key.
279       Apart  from  puzzling  the user, this clearly is not a serious problem.
280       However there is a way, albeit complicated, to  completely  avoid  this
281       race condition. The following steps illustrate this.
282
283           1.     Block  all  of  the  signals  that gl_get_line() catches, by
284                  passing the signal set returned by gl_list_signals() to sig‐
285                  procmask(2).
286
287           2.     Call gl_pending_io() and set up the arguments of select() or
288                  poll() accordingly.
289
290           3.     Call sigsetjmp(3C) with a non-zero savemask argument.
291
292           4.     Initially this sigsetjmp() statement will return zero, indi‐
293                  cating  that  control is not resuming there after a matching
294                  call to siglongjmp(3C).
295
296           5.     Replace  all  of  the   handlers   of   the   signals   that
297                  gl_get_line()  is configured to catch, with a signal handler
298                  that first records the number of the signal that was caught,
299                  in  a  file-scope  variable,  then calls siglongjmp() with a
300                  non-zero val argument, to  return  execution  to  the  above
301                  sigsetjmp() statement. Registering these signal handlers can
302                  conveniently be done using the gl_tty_signals() function.
303
304           6.     Set the file-scope variable that the  above  signal  handler
305                  uses  to  record any signal that is caught to -1, so that we
306                  can check whether a signal was caught by seeing if  it  con‐
307                  tains a valid signal number.
308
309           7.     Now  unblock  the  signals  that were blocked in step 1. Any
310                  signal that was received by the process in  between  step  1
311                  and  now  will now be delivered, and trigger our signal han‐
312                  dler, as will any signal that is  received  until  we  block
313                  these signals again.
314
315           8.     Now call select() or poll().
316
317           9.     When  select  returns,  again  block  the  signals that were
318                  unblocked in step 7.
319
320                  If a signal is arrived any time during the above steps,  our
321                  signal handler will be triggered and cause control to return
322                  to the sigsetjmp() statement, where this  time,  sigsetjmp()
323                  will  return  non-zero, indicating that a signal was caught.
324                  When this happens we simply skip the above block  of  state‐
325                  ments, and continue with the following statements, which are
326                  executed regardless of whether or not a  signal  is  caught.
327                  Note  that  when  sigsetjmp()  returns, regardless of why it
328                  returned, the process signal mask is returned to how it  was
329                  when  sigsetjmp()  was called. Thus the following statements
330                  are always executed with all of our signals blocked.
331
332           10.    Reinstate the signal handlers that were displaced in step 5.
333
334           11.    Check wether a signal was caught, by checking the file-scope
335                  variable that the signal handler records signal numbers in.
336
337           12.    If  a signal was caught, send this signal to the application
338                  again and unblock only this signal so that  it  invokes  the
339                  signal handler which was just reinstated in step 10.
340
341           13.    Unblock all of the signals that were blocked in step 7.
342
343   Signals Caught By gl_get_line()
344       Since  the  application  is  expected to handle signals in non-blocking
345       server mode, gl_get_line() does not attempt to duplicate this  when  it
346       is  being  called. If one of the signals that it is configured to catch
347       is sent  to  the  application  while  gl_get_line()  is  being  called,
348       gl_get_line() reinstates the caller's signal handlers, then immediately
349       before returning, re-sends the signal to the process to let the  appli‐
350       cation's  signal handler handle it. If the process is not terminated by
351       this signal, gl_get_line()  returns  NULL,  and  a  following  call  to
352       gl_return_status() returns the enumerated value GLR_SIGNAL.
353
354   Aborting Line Input
355       Often,  rather  than  letting  it  terminate  the process, applications
356       respond to the SIGINT user-interrupt signal  by  aborting  the  current
357       input line. This can be accomplished in non-blocking server-I/O mode by
358       not calling gl_handle_signal() when this signal is caught, but by call‐
359       ing instead the gl_abandon_line() function. This function arranges that
360       when gl_get_line() is next called, it first flushes any pending  output
361       to the terminal, discardes the current input line, outputs a new prompt
362       on the next line, and finally starts accepting input  of  a  new  input
363       line from the user.
364
365   Signal Safe Functions
366       Provided   that   certain   rules  are  followed,  the  gl_normal_io(),
367       gl_raw_io(), gl_handle_signal(), and gl_abandon_line() functions can be
368       written  to be safely callable from signal handlers. Other functions in
369       this library should not be called from signal handlers. For this to  be
370       true,  all signal handlers that call these functions must be registered
371       in such a way that only one instance of any one of them can be  running
372       at  one  time. The way to do this is to use the POSIX sigaction() func‐
373       tion to register all signal handlers, and  when  doing  this,  use  the
374       sa_mask  member  of  the  corresponding sigaction structure to indicate
375       that all of the signals  whose  handlers  invoke  the  above  functions
376       should  be  blocked when the current signal is being handled. This pre‐
377       vents two signal handlers from operating on a  GetLine  object  at  the
378       same time.
379
380
381       To  prevent  signal  handlers  from  accessing  a  GetLine object while
382       gl_get_line() or any of its associated public functions  are  operating
383       on  it,  all  public functions associated with gl_get_line(), including
384       gl_get_line() itself, temporarily block the delivery  of  signals  when
385       they  are  accessing GetLine objects. Beware that the only signals that
386       they block are the signals that gl_get_line() is  currently  configured
387       to  catch,  so be sure that if you call any of the above functions from
388       signal handlers, that the signals that these handlers are  assigned  to
389       are   configured  to  be  caught  by  gl_get_line().  See  gl_trap_sig‐
390       nal(3TECLA).
391
392   Using Timeouts To Poll
393       If instead of using select() or poll() to wait for I/O your application
394       needs only to get out of gl_get_line() periodically to briefly do some‐
395       thing else before returning to accept input  from  the  user,  use  the
396       gl_inactivity_timeout(3TECLA)  function  in non-blocking server mode to
397       specify that a callback function that returns GLTO_CONTINUE  should  be
398       called  whenever gl_get_line() has been waiting for I/O for more than a
399       specified  amount  of  time.   When   this   callback   is   triggered,
400       gl_get_line()  will  return NULL and a following call to gl_return_sta‐
401       tus() will return GLR_BLOCKED.
402
403
404       The gl_get_line() function will not return until the user has not typed
405       a  key  for  the specified interval, so if the interval is long and the
406       user keeps typing, gl_get_line() might not return for a while. There is
407       no guarantee that it will return in the time specified.
408

ATTRIBUTES

410       See attributes(5) for descriptions of the following attributes:
411
412
413
414
415       ┌─────────────────────────────┬─────────────────────────────┐
416       │      ATTRIBUTE TYPE         │      ATTRIBUTE VALUE        │
417       ├─────────────────────────────┼─────────────────────────────┤
418       │Interface Stability          │Evolving                     │
419       ├─────────────────────────────┼─────────────────────────────┤
420       │MT-Level                     │MT-Safe                      │
421       └─────────────────────────────┴─────────────────────────────┘
422

SEE ALSO

424       cpl_complete_word(3TECLA), ef_expand_file(3TECLA), gl_get_line(3TECLA),
425       libtecla(3LIB), pca_lookup_file(3TECLA), attributes(5), tecla(5)
426
427
428
429SunOS 5.11                        1 Jun 2004                gl_io_mode(3TECLA)
Impressum