import gdb-1999-05-25 snapshot
[deliverable/binutils-gdb.git] / gdb / event-loop.c
1 /* Event loop machinery for GDB, the GNU debugger.
2 Copyright 1999 Free Software Foundation, Inc.
3 Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include "event-loop.h"
22 #include <readline/readline.h>
23 #include <setjmp.h>
24 #include "top.h"
25
26 /* For config.h which may define HAVE_POLL */
27 #include "defs.h"
28
29 #ifdef HAVE_POLL
30 #include <sys/poll.h>
31 #endif
32 #include <errno.h>
33
34 /* Event queue:
35 - the first event in the queue is the head of the queue.
36 It will be the next to be serviced.
37 - the last event in the queue
38
39 Events can be inserted at the front of the queue or at the end of
40 the queue. Events will be extracted from the queue for processing
41 starting from the head. Therefore, events inserted at the head of
42 the queue will be processed in a last in first out fashoin, while
43 those inserted at the tail of the queue will be processed in a first
44 in first out manner. All the fields are NULL if the queue is
45 empty. */
46
47 static struct
48 {
49 gdb_event *first_event; /* First pending event */
50 gdb_event *last_event; /* Last pending event */
51 }
52 event_queue;
53
54 /* Gdb_notifier is just a list of file descriptors gdb is interested in.
55 These are the input file descriptor, and the target file
56 descriptor. We have two flavors of the notifier, one for platforms
57 that have the POLL function, the other for those that don't, and
58 only support SELECT. Each of the elements in the gdb_notifier list is
59 basically a description of what kind of events gdb is interested
60 in, for each fd. */
61
62 /* As of 1999-04-30 only the input file descriptor is registered with the
63 event loop. */
64
65 #ifdef HAVE_POLL
66 /* Poll based implementation of the notifier. */
67
68 static struct
69 {
70 /* Ptr to head of file handler list. */
71 file_handler *first_file_handler;
72
73 /* Ptr to array of pollfd structures. */
74 struct pollfd *poll_fds;
75
76 /* Number of file descriptors to monitor. */
77 int num_fds;
78
79 }
80 gdb_notifier;
81
82 #else /* ! HAVE_POLL */
83
84 /* Select based implementation of the notifier. */
85
86 static struct
87 {
88 /* Ptr to head of file handler list. */
89 file_handler *first_file_handler;
90
91 /* Masks to be used in the next call to select.
92 Bits are set in response to calls to create_file_handler. */
93 fd_mask check_masks[3 * MASK_SIZE];
94
95 /* What file descriptors were found ready by select. */
96 fd_mask ready_masks[3 * MASK_SIZE];
97
98 /* Number of valid bits (highest fd value + 1). */
99 int num_fds;
100
101 }
102 gdb_notifier;
103
104 #endif /* HAVE_POLL */
105
106 /* All the async_signal_handlers gdb is interested in are kept onto
107 this list. */
108 static struct
109 {
110 /* Pointer to first in handler list. */
111 async_signal_handler *first_handler;
112
113 /* Pointer to last in handler list. */
114 async_signal_handler *last_handler;
115 }
116 sighandler_list;
117
118 /* Is any of the handlers ready? Check this variable using
119 check_async_ready. This is used by process_event, to determine
120 whether or not to invoke the invoke_async_signal_handler
121 function. */
122 static int async_handler_ready = 0;
123
124 static void invoke_async_signal_handler PARAMS ((void));
125 static int gdb_wait_for_event PARAMS ((void));
126 static int check_async_ready PARAMS ((void));
127 \f
128
129 /* Insert an event object into the gdb event queue at
130 the specified position.
131 POSITION can be head or tail, with values TAIL, HEAD.
132 EVENT_PTR points to the event to be inserted into the queue.
133 The caller must allocate memory for the event. It is freed
134 after the event has ben handled.
135 Events in the queue will be processed head to tail, therefore,
136 events inserted at the head of the queue will be processed
137 as last in first out. Event appended at the tail of the queue
138 will be processed first in first out. */
139 static void
140 async_queue_event (event_ptr, position)
141 gdb_event *event_ptr;
142 queue_position position;
143 {
144 if (position == TAIL)
145 {
146 /* The event will become the new last_event. */
147
148 event_ptr->next_event = NULL;
149 if (event_queue.first_event == NULL)
150 event_queue.first_event = event_ptr;
151 else
152 event_queue.last_event->next_event = event_ptr;
153 event_queue.last_event = event_ptr;
154 }
155 else if (position == HEAD)
156 {
157 /* The event becomes the new first_event. */
158
159 event_ptr->next_event = event_queue.first_event;
160 if (event_queue.first_event == NULL)
161 event_queue.last_event = event_ptr;
162 event_queue.first_event = event_ptr;
163 }
164 }
165
166 /* Process one event.
167 The event can be the next one to be serviced in the event queue,
168 or an asynchronous event handler can be invoked in response to
169 the reception of a signal.
170 If an event was processed (either way), 1 is returned otherwise
171 0 is returned.
172 Scan the queue from head to tail, processing therefore the high
173 priority events first, by invoking the associated event handler
174 procedure. */
175 static int
176 process_event ()
177 {
178 gdb_event *event_ptr, *prev_ptr;
179 event_handler_func *proc;
180 int fd;
181
182 /* First let's see if there are any asynchronous event handlers that
183 are ready. These would be the result of invoking any of the
184 signal handlers. */
185
186 if (check_async_ready ())
187 {
188 invoke_async_signal_handler ();
189 return 1;
190 }
191
192 /* Look in the event queue to find an event that is ready
193 to be processed. */
194
195 for (event_ptr = event_queue.first_event; event_ptr != NULL;
196 event_ptr = event_ptr->next_event)
197 {
198 /* Call the handler for the event. */
199
200 proc = event_ptr->proc;
201 fd = event_ptr->fd;
202
203 /* Let's get rid of the event from the event queue. We need to
204 do this now because while processing the event, the proc
205 function could end up calling 'error' and therefore jump out
206 to the caller of this function, gdb_do_one_event. In that
207 case, we would have on the event queue an event wich has been
208 processed, but not deleted. */
209
210 if (event_queue.first_event == event_ptr)
211 {
212 event_queue.first_event = event_ptr->next_event;
213 if (event_ptr->next_event == NULL)
214 event_queue.last_event = NULL;
215 }
216 else
217 {
218 prev_ptr = event_queue.first_event;
219 while (prev_ptr->next_event != event_ptr)
220 prev_ptr = prev_ptr->next_event;
221
222 prev_ptr->next_event = event_ptr->next_event;
223 if (event_ptr->next_event == NULL)
224 event_queue.last_event = prev_ptr;
225 }
226 free ((char *) event_ptr);
227
228 /* Now call the procedure associted with the event. */
229 (*proc) (fd);
230 return 1;
231 }
232
233 /* this is the case if there are no event on the event queue. */
234 return 0;
235 }
236
237 /* Process one high level event. If nothing is ready at this time,
238 wait for something to happen (via gdb_wait_for_event), then process
239 it. Returns 1 if something was done otherwise returns 0 (this can
240 happen if there are no event sources to wait for). */
241 int
242 gdb_do_one_event ()
243 {
244 int result = 0;
245
246 while (1)
247 {
248 if (!SET_TOP_LEVEL ())
249 {
250 /* Any events already waiting in the queue? */
251 if (process_event ())
252 {
253 result = 1;
254 break;
255 }
256
257 /* Wait for a new event. If gdb_wait_for_event returns -1,
258 we should get out because this means that there are no
259 event sources left. This will make the event loop stop,
260 and the application exit. */
261
262 result = gdb_wait_for_event ();
263 if (result < 0)
264 {
265 result = 0;
266 break;
267 }
268
269 /* Handle any new events occurred while waiting. */
270 if (process_event ())
271 {
272 result = 1;
273 break;
274 }
275
276 /* If gdb_wait_for_event has returned 1, it means that one
277 event has been handled. We break out of the loop. */
278 if (result)
279 break;
280 } /* end of if !set_top_level */
281 else
282 {
283 display_gdb_prompt (0);
284 /* Maybe better to set a flag to be checked somewhere as to
285 whether display the prompt or not. */
286 }
287 }
288 return result;
289 }
290 \f
291
292 /* Add a file handler/descriptor to the list of descriptors we are
293 interested in.
294 FD is the file descriptor for the file/stream to be listened to.
295 For the poll case, MASK is a combination (OR) of
296 POLLIN, POLLRDNORM, POLLRDBAND, POLLPRI, POLLOUT, POLLWRNORM,
297 POLLWRBAND: these are the events we are interested in. If any of them
298 occurs, proc should be called.
299 For the select case, MASK is a combination of READABLE, WRITABLE, EXCEPTION.
300 PROC is the procedure that will be called when an event occurs for
301 FD. CLIENT_DATA is the argument to pass to PROC. */
302 void
303 create_file_handler (fd, mask, proc, client_data)
304 int fd;
305 int mask;
306 file_handler_func *proc;
307 gdb_client_data client_data;
308 {
309 file_handler *file_ptr;
310
311 #ifndef HAVE_POLL
312 int index, bit;
313 #endif
314
315 /* Do we already have a file handler for this file? (We may be
316 changing its associated procedure). */
317 for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
318 file_ptr = file_ptr->next_file)
319 {
320 if (file_ptr->fd == fd)
321 break;
322 }
323
324 /* It is a new file descriptor. */
325 if (file_ptr == NULL)
326 {
327 file_ptr = (file_handler *) xmalloc (sizeof (file_handler));
328 file_ptr->fd = fd;
329 file_ptr->ready_mask = 0;
330 file_ptr->next_file = gdb_notifier.first_file_handler;
331 gdb_notifier.first_file_handler = file_ptr;
332 }
333 file_ptr->proc = proc;
334 file_ptr->client_data = client_data;
335 file_ptr->mask = mask;
336
337 #ifdef HAVE_POLL
338
339 gdb_notifier.num_fds++;
340 gdb_notifier.poll_fds =
341 (struct pollfd *) realloc (gdb_notifier.poll_fds,
342 (gdb_notifier.num_fds) * sizeof (struct pollfd));
343 (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->fd = fd;
344 (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->events = mask;
345 (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->revents = 0;
346
347 #else /* ! HAVE_POLL */
348
349 index = fd / (NBBY * sizeof (fd_mask));
350 bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
351
352 if (mask & GDB_READABLE)
353 gdb_notifier.check_masks[index] |= bit;
354 else
355 gdb_notifier.check_masks[index] &= ~bit;
356
357 if (mask & GDB_WRITABLE)
358 (gdb_notifier.check_masks + MASK_SIZE)[index] |= bit;
359 else
360 (gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
361
362 if (mask & GDB_EXCEPTION)
363 (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] |= bit;
364 else
365 (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
366
367 if (gdb_notifier.num_fds <= fd)
368 gdb_notifier.num_fds = fd + 1;
369
370 #endif /* HAVE_POLL */
371 }
372
373 /* Remove the file descriptor FD from the list of monitored fd's:
374 i.e. we don't care anymore about events on the FD. */
375 void
376 delete_file_handler (fd)
377 int fd;
378 {
379 file_handler *file_ptr, *prev_ptr = NULL;
380 int i, j;
381 struct pollfd *new_poll_fds;
382 #ifndef HAVE_POLL
383 int index, bit;
384 unsigned long flags;
385 #endif
386
387 /* Find the entry for the given file. */
388
389 for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
390 file_ptr = file_ptr->next_file)
391 {
392 if (file_ptr->fd == fd)
393 break;
394 }
395
396 if (file_ptr == NULL)
397 return;
398
399 /* Deactivate the file descriptor, by clearing its mask,
400 so that it will not fire again. */
401
402 file_ptr->mask = 0;
403
404 #ifdef HAVE_POLL
405 /* Create a new poll_fds array by copying every fd's information but the
406 one we want to get rid of. */
407
408 new_poll_fds =
409 (struct pollfd *) xmalloc ((gdb_notifier.num_fds - 1) * sizeof (struct pollfd));
410
411 for (i = 0, j = 0; i < gdb_notifier.num_fds; i++)
412 {
413 if ((gdb_notifier.poll_fds + i)->fd != fd)
414 {
415 (new_poll_fds + j)->fd = (gdb_notifier.poll_fds + i)->fd;
416 (new_poll_fds + j)->events = (gdb_notifier.poll_fds + i)->events;
417 (new_poll_fds + j)->revents = (gdb_notifier.poll_fds + i)->revents;
418 j++;
419 }
420 }
421 free (gdb_notifier.poll_fds);
422 gdb_notifier.poll_fds = new_poll_fds;
423 gdb_notifier.num_fds--;
424
425 #else /* ! HAVE_POLL */
426
427 index = fd / (NBBY * sizeof (fd_mask));
428 bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
429
430 if (file_ptr->mask & GDB_READABLE)
431 gdb_notifier.check_masks[index] &= ~bit;
432 if (file_ptr->mask & GDB_WRITABLE)
433 (gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
434 if (file_ptr->mask & GDB_EXCEPTION)
435 (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
436
437 /* Find current max fd. */
438
439 if ((fd + 1) == gdb_notifier.num_fds)
440 {
441 for (gdb_notifier.num_fds = 0; index >= 0; index--)
442 {
443 flags = gdb_notifier.check_masks[index]
444 | (gdb_notifier.check_masks + MASK_SIZE)[index]
445 | (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index];
446 if (flags)
447 {
448 for (i = (NBBY * sizeof (fd_mask)); i > 0; i--)
449 {
450 if (flags & (((unsigned long) 1) << (i - 1)))
451 break;
452 }
453 gdb_notifier.num_fds = index * (NBBY * sizeof (fd_mask)) + i;
454 break;
455 }
456 }
457 }
458 #endif /* HAVE_POLL */
459
460 /* Get rid of the file handler in the file handler list. */
461 if (file_ptr == gdb_notifier.first_file_handler)
462 gdb_notifier.first_file_handler = file_ptr->next_file;
463 else
464 {
465 for (prev_ptr = gdb_notifier.first_file_handler;
466 prev_ptr->next_file == file_ptr;
467 prev_ptr = prev_ptr->next_file)
468 ;
469 prev_ptr->next_file = file_ptr->next_file;
470 }
471 free ((char *) file_ptr);
472 }
473
474 /* Handle the given event by calling the procedure associated to the
475 corresponding file handler. Called by process_event indirectly,
476 through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the
477 event in the front of the event queue. */
478 static void
479 handle_file_event (event_file_desc)
480 int event_file_desc;
481 {
482 file_handler *file_ptr;
483 int mask, error_mask;
484
485 /* Search the file handler list to find one that matches the fd in
486 the event. */
487 for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
488 file_ptr = file_ptr->next_file)
489 {
490 if (file_ptr->fd == event_file_desc)
491 {
492 /* With poll, the ready_mask could have any of three events
493 set to 1: POLLHUP, POLLERR, POLLNVAL. These events cannot
494 be used in the requested event mask (events), but they
495 can be returned in the return mask (revents). We need to
496 check for those event too, and add them to the mask which
497 will be passed to the handler. */
498
499 /* See if the desired events (mask) match the received
500 events (ready_mask). */
501
502 #ifdef HAVE_POLL
503 error_mask = POLLHUP | POLLERR | POLLNVAL;
504 mask = (file_ptr->ready_mask & file_ptr->mask) |
505 (file_ptr->ready_mask & error_mask);
506
507 #else /* ! HAVE_POLL */
508 mask = file_ptr->ready_mask & file_ptr->mask;
509 #endif /* HAVE_POLL */
510
511 /* Clear the received events for next time around. */
512 file_ptr->ready_mask = 0;
513
514 /* If there was a match, then call the handler. */
515 if (mask != 0)
516 (*file_ptr->proc) (file_ptr->client_data, mask);
517 break;
518 }
519 }
520 }
521
522 /* Called by gdb_do_one_event to wait for new events on the
523 monitored file descriptors. Queue file events as they are
524 detected by the poll.
525 If there are no events, this function will block in the
526 call to poll.
527 Return -1 if there are no files descriptors to monitor,
528 otherwise return 0. */
529 static int
530 gdb_wait_for_event ()
531 {
532 file_handler *file_ptr;
533 gdb_event *file_event_ptr;
534 int num_found, i;
535
536 #ifndef HAVE_POLL
537 int mask, bit, index;
538 #endif
539
540 if (gdb_notifier.num_fds == 0)
541 return -1;
542
543 #ifdef HAVE_POLL
544 num_found =
545 poll (gdb_notifier.poll_fds, (unsigned long) gdb_notifier.num_fds, -1);
546
547 #else /* ! HAVE_POLL */
548 memcpy (gdb_notifier.ready_masks,
549 gdb_notifier.check_masks,
550 3 * MASK_SIZE * sizeof (fd_mask));
551 num_found = select (gdb_notifier.num_fds,
552 (SELECT_MASK *) & gdb_notifier.ready_masks[0],
553 (SELECT_MASK *) & gdb_notifier.ready_masks[MASK_SIZE],
554 (SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
555 NULL);
556
557 /* Clear the masks after an error from select. */
558 if (num_found == -1)
559 memset (gdb_notifier.ready_masks,
560 0, 3 * MASK_SIZE * sizeof (fd_mask));
561
562 #endif /* HAVE_POLL */
563
564 /* Enqueue all detected file events. */
565
566 #ifdef HAVE_POLL
567
568 for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
569 {
570 if ((gdb_notifier.poll_fds + i)->revents)
571 num_found--;
572 else
573 continue;
574
575 for (file_ptr = gdb_notifier.first_file_handler;
576 file_ptr != NULL;
577 file_ptr = file_ptr->next_file)
578 {
579 if (file_ptr->fd == (gdb_notifier.poll_fds + i)->fd)
580 break;
581 }
582
583 if (file_ptr)
584 {
585 /* Enqueue an event only if this is still a new event for
586 this fd. */
587 if (file_ptr->ready_mask == 0)
588 {
589 file_event_ptr =
590 (gdb_event *) xmalloc (sizeof (gdb_event));
591 file_event_ptr->proc = handle_file_event;
592 file_event_ptr->fd = file_ptr->fd;
593 async_queue_event (file_event_ptr, TAIL);
594 }
595 }
596
597 file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
598 }
599
600 #else /* ! HAVE_POLL */
601 for (file_ptr = gdb_notifier.first_file_handler;
602 (file_ptr != NULL) && (num_found > 0);
603 file_ptr = file_ptr->next_file)
604 {
605 index = file_ptr->fd / (NBBY * sizeof (fd_mask));
606 bit = 1 << (file_ptr->fd % (NBBY * sizeof (fd_mask)));
607 mask = 0;
608
609 if (gdb_notifier.ready_masks[index] & bit)
610 mask |= GDB_READABLE;
611 if ((gdb_notifier.ready_masks + MASK_SIZE)[index] & bit)
612 mask |= GDB_WRITABLE;
613 if ((gdb_notifier.ready_masks + 2 * (MASK_SIZE))[index] & bit)
614 mask |= GDB_EXCEPTION;
615
616 if (!mask)
617 continue;
618 else
619 num_found--;
620
621 /* Enqueue an event only if this is still a new event for
622 this fd. */
623
624 if (file_ptr->ready_mask == 0)
625 {
626 file_event_ptr =
627 (gdb_event *) xmalloc (sizeof (gdb_event));
628 file_event_ptr->proc = handle_file_event;
629 file_event_ptr->fd = file_ptr->fd;
630 async_queue_event (file_event_ptr, TAIL);
631 }
632 file_ptr->ready_mask = mask;
633 }
634 #endif /* HAVE_POLL */
635
636 return 0;
637 }
638 \f
639
640 /* Create an asynchronous handler, allocating memory for it.
641 Return a pointer to the newly created handler.
642 This pointer will be used to invoke the handler by
643 invoke_async_signal_handler.
644 PROC is the function to call with CLIENT_DATA argument
645 whenever the handler is invoked. */
646 async_signal_handler *
647 create_async_signal_handler (proc, client_data)
648 async_handler_func *proc;
649 gdb_client_data client_data;
650 {
651 async_signal_handler *async_handler_ptr;
652
653 async_handler_ptr =
654 (async_signal_handler *) xmalloc (sizeof (async_signal_handler));
655 async_handler_ptr->ready = 0;
656 async_handler_ptr->next_handler = NULL;
657 async_handler_ptr->proc = proc;
658 async_handler_ptr->client_data = client_data;
659 if (sighandler_list.first_handler == NULL)
660 sighandler_list.first_handler = async_handler_ptr;
661 else
662 sighandler_list.last_handler->next_handler = async_handler_ptr;
663 sighandler_list.last_handler = async_handler_ptr;
664 return async_handler_ptr;
665 }
666
667 /* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information will
668 be used when the handlers are invoked, after we have waited for
669 some event. The caller of this function is the interrupt handler
670 associated with a signal. */
671 void
672 mark_async_signal_handler (async_handler_ptr)
673 async_signal_handler *async_handler_ptr;
674 {
675 ((async_signal_handler *) async_handler_ptr)->ready = 1;
676 async_handler_ready = 1;
677 }
678
679 /* Call all the handlers that are ready. */
680 static void
681 invoke_async_signal_handler ()
682 {
683 async_signal_handler *async_handler_ptr;
684
685 if (async_handler_ready == 0)
686 return;
687 async_handler_ready = 0;
688
689 /* Invoke ready handlers. */
690
691 while (1)
692 {
693 for (async_handler_ptr = sighandler_list.first_handler;
694 async_handler_ptr != NULL;
695 async_handler_ptr = async_handler_ptr->next_handler)
696 {
697 if (async_handler_ptr->ready)
698 break;
699 }
700 if (async_handler_ptr == NULL)
701 break;
702 async_handler_ptr->ready = 0;
703 (*async_handler_ptr->proc) (async_handler_ptr->client_data);
704 }
705
706 return;
707 }
708
709 /* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
710 Free the space allocated for it. */
711 void
712 delete_async_signal_handler (async_handler_ptr)
713 async_signal_handler *async_handler_ptr;
714 {
715 async_signal_handler *prev_ptr;
716
717 if (sighandler_list.first_handler == async_handler_ptr)
718 {
719 sighandler_list.first_handler = async_handler_ptr->next_handler;
720 if (sighandler_list.first_handler == NULL)
721 sighandler_list.last_handler = NULL;
722 }
723 else
724 {
725 prev_ptr = sighandler_list.first_handler;
726 while (prev_ptr->next_handler != async_handler_ptr)
727 prev_ptr = prev_ptr->next_handler;
728 prev_ptr->next_handler = async_handler_ptr->next_handler;
729 if (sighandler_list.last_handler == async_handler_ptr)
730 sighandler_list.last_handler = prev_ptr;
731 }
732 free ((char *) async_handler_ptr);
733 }
734
735 /* Is it necessary to call invoke_async_signal_handler? */
736 static int
737 check_async_ready ()
738 {
739 return async_handler_ready;
740 }
This page took 0.05137 seconds and 4 git commands to generate.