* scripttempl/elf.sc (WRITABLE_RODATA): New variable for
[deliverable/binutils-gdb.git] / gdb / event-loop.c
CommitLineData
b5a0ac70
SS
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
47static struct
48 {
49 gdb_event *first_event; /* First pending event */
50 gdb_event *last_event; /* Last pending event */
51 }
52event_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
392a587b 62/* As of 1999-04-30 only the input file descriptor is registered with the
b5a0ac70
SS
63 event loop. */
64
65#ifdef HAVE_POLL
66/* Poll based implementation of the notifier. */
67
68static 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 }
80gdb_notifier;
81
82#else /* ! HAVE_POLL */
83
84/* Select based implementation of the notifier. */
85
86static 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 }
102gdb_notifier;
103
104#endif /* HAVE_POLL */
105
106/* All the async_signal_handlers gdb is interested in are kept onto
107 this list. */
108static 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 }
116sighandler_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. */
122static int async_handler_ready = 0;
123
124static void invoke_async_signal_handler PARAMS ((void));
125static int gdb_wait_for_event PARAMS ((void));
126static int check_async_ready PARAMS ((void));
b5a0ac70
SS
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. */
139static void
140async_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. */
175static int
176process_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). */
241int
242gdb_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. */
302void
303create_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. */
375void
376delete_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. */
478static void
479handle_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. */
529static int
530gdb_wait_for_event ()
531{
532 file_handler *file_ptr;
533 gdb_event *file_event_ptr;
0f71a2f6
JM
534 int num_found = 0;
535 int i;
b5a0ac70
SS
536
537#ifndef HAVE_POLL
538 int mask, bit, index;
539#endif
540
541 if (gdb_notifier.num_fds == 0)
542 return -1;
543
544#ifdef HAVE_POLL
545 num_found =
546 poll (gdb_notifier.poll_fds, (unsigned long) gdb_notifier.num_fds, -1);
547
548#else /* ! HAVE_POLL */
549 memcpy (gdb_notifier.ready_masks,
550 gdb_notifier.check_masks,
551 3 * MASK_SIZE * sizeof (fd_mask));
552 num_found = select (gdb_notifier.num_fds,
553 (SELECT_MASK *) & gdb_notifier.ready_masks[0],
554 (SELECT_MASK *) & gdb_notifier.ready_masks[MASK_SIZE],
555 (SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
556 NULL);
557
558 /* Clear the masks after an error from select. */
559 if (num_found == -1)
560 memset (gdb_notifier.ready_masks,
561 0, 3 * MASK_SIZE * sizeof (fd_mask));
562
563#endif /* HAVE_POLL */
564
565 /* Enqueue all detected file events. */
566
567#ifdef HAVE_POLL
568
569 for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
570 {
571 if ((gdb_notifier.poll_fds + i)->revents)
572 num_found--;
573 else
574 continue;
575
576 for (file_ptr = gdb_notifier.first_file_handler;
577 file_ptr != NULL;
578 file_ptr = file_ptr->next_file)
579 {
580 if (file_ptr->fd == (gdb_notifier.poll_fds + i)->fd)
581 break;
582 }
583
584 if (file_ptr)
585 {
586 /* Enqueue an event only if this is still a new event for
587 this fd. */
588 if (file_ptr->ready_mask == 0)
589 {
590 file_event_ptr =
591 (gdb_event *) xmalloc (sizeof (gdb_event));
592 file_event_ptr->proc = handle_file_event;
593 file_event_ptr->fd = file_ptr->fd;
594 async_queue_event (file_event_ptr, TAIL);
595 }
596 }
597
598 file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
599 }
600
601#else /* ! HAVE_POLL */
602 for (file_ptr = gdb_notifier.first_file_handler;
603 (file_ptr != NULL) && (num_found > 0);
604 file_ptr = file_ptr->next_file)
605 {
606 index = file_ptr->fd / (NBBY * sizeof (fd_mask));
607 bit = 1 << (file_ptr->fd % (NBBY * sizeof (fd_mask)));
608 mask = 0;
609
610 if (gdb_notifier.ready_masks[index] & bit)
611 mask |= GDB_READABLE;
612 if ((gdb_notifier.ready_masks + MASK_SIZE)[index] & bit)
613 mask |= GDB_WRITABLE;
614 if ((gdb_notifier.ready_masks + 2 * (MASK_SIZE))[index] & bit)
615 mask |= GDB_EXCEPTION;
616
617 if (!mask)
618 continue;
619 else
620 num_found--;
621
622 /* Enqueue an event only if this is still a new event for
623 this fd. */
624
625 if (file_ptr->ready_mask == 0)
626 {
627 file_event_ptr =
628 (gdb_event *) xmalloc (sizeof (gdb_event));
629 file_event_ptr->proc = handle_file_event;
630 file_event_ptr->fd = file_ptr->fd;
631 async_queue_event (file_event_ptr, TAIL);
632 }
633 file_ptr->ready_mask = mask;
634 }
635#endif /* HAVE_POLL */
636
637 return 0;
638}
639\f
640
641/* Create an asynchronous handler, allocating memory for it.
642 Return a pointer to the newly created handler.
643 This pointer will be used to invoke the handler by
644 invoke_async_signal_handler.
645 PROC is the function to call with CLIENT_DATA argument
646 whenever the handler is invoked. */
647async_signal_handler *
648create_async_signal_handler (proc, client_data)
649 async_handler_func *proc;
650 gdb_client_data client_data;
651{
652 async_signal_handler *async_handler_ptr;
653
654 async_handler_ptr =
655 (async_signal_handler *) xmalloc (sizeof (async_signal_handler));
656 async_handler_ptr->ready = 0;
657 async_handler_ptr->next_handler = NULL;
658 async_handler_ptr->proc = proc;
659 async_handler_ptr->client_data = client_data;
660 if (sighandler_list.first_handler == NULL)
661 sighandler_list.first_handler = async_handler_ptr;
662 else
663 sighandler_list.last_handler->next_handler = async_handler_ptr;
664 sighandler_list.last_handler = async_handler_ptr;
665 return async_handler_ptr;
666}
667
668/* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information will
669 be used when the handlers are invoked, after we have waited for
670 some event. The caller of this function is the interrupt handler
671 associated with a signal. */
672void
673mark_async_signal_handler (async_handler_ptr)
674 async_signal_handler *async_handler_ptr;
675{
676 ((async_signal_handler *) async_handler_ptr)->ready = 1;
677 async_handler_ready = 1;
678}
679
680/* Call all the handlers that are ready. */
681static void
682invoke_async_signal_handler ()
683{
684 async_signal_handler *async_handler_ptr;
685
686 if (async_handler_ready == 0)
687 return;
688 async_handler_ready = 0;
689
690 /* Invoke ready handlers. */
691
692 while (1)
693 {
694 for (async_handler_ptr = sighandler_list.first_handler;
695 async_handler_ptr != NULL;
696 async_handler_ptr = async_handler_ptr->next_handler)
697 {
698 if (async_handler_ptr->ready)
699 break;
700 }
701 if (async_handler_ptr == NULL)
702 break;
703 async_handler_ptr->ready = 0;
704 (*async_handler_ptr->proc) (async_handler_ptr->client_data);
705 }
706
707 return;
708}
709
710/* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
711 Free the space allocated for it. */
712void
713delete_async_signal_handler (async_handler_ptr)
714 async_signal_handler *async_handler_ptr;
715{
716 async_signal_handler *prev_ptr;
717
718 if (sighandler_list.first_handler == async_handler_ptr)
719 {
720 sighandler_list.first_handler = async_handler_ptr->next_handler;
721 if (sighandler_list.first_handler == NULL)
722 sighandler_list.last_handler = NULL;
723 }
724 else
725 {
726 prev_ptr = sighandler_list.first_handler;
727 while (prev_ptr->next_handler != async_handler_ptr)
728 prev_ptr = prev_ptr->next_handler;
729 prev_ptr->next_handler = async_handler_ptr->next_handler;
730 if (sighandler_list.last_handler == async_handler_ptr)
731 sighandler_list.last_handler = prev_ptr;
732 }
733 free ((char *) async_handler_ptr);
734}
735
736/* Is it necessary to call invoke_async_signal_handler? */
737static int
738check_async_ready ()
739{
740 return async_handler_ready;
741}
This page took 0.050702 seconds and 4 git commands to generate.