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