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