1 /* unix_main.c -- Miscellaneous functions for Unix
2 Copyright (C) 1993, 1994 John Harper <john@dcs.warwick.ac.uk>
3 $Id$
4
5 This file is part of Jade.
6
7 Jade is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 Jade is distributed in the hope that it will be useful, but
13 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 Jade; see the file COPYING. If not, write to
19 the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20
21 #define _GNU_SOURCE
22
23 #include "repint.h"
24
25 #include <string.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <limits.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 #include <pwd.h>
32 #include <netdb.h>
33 #include <signal.h>
34
35 #ifdef HAVE_FCNTL_H
36 # include <fcntl.h>
37 #endif
38
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46
47 #ifdef HAVE_SYS_UTSNAME_H
48 # include <sys/utsname.h>
49 #endif
50
51 #ifdef HAVE_STRERROR
52 # include <errno.h>
53 #else
54 extern int sys_nerr, errno;
55 extern char *sys_errlist[];
56 #endif
57
58 #ifdef ENVIRON_UNDECLARED
59 extern char **environ;
60 #endif
61
62 void (*rep_redisplay_fun)(void);
63 long (*rep_wait_for_input_fun)(void *inputs, unsigned long timeout_msecs);
64 int rep_input_timeout_secs = 1;
65
66
67 /* Support functions */
68
69 #ifndef HAVE_STRERROR
70 DEFSTRING(unknown_err, "Unknown system error");
71 #endif
72 repv
rep_lookup_errno(void)73 rep_lookup_errno(void)
74 {
75 #ifdef HAVE_STRERROR
76 return rep_string_dup(strerror(errno));
77 #else
78 if(errno >= sys_nerr)
79 return rep_string_dup(sys_errlist[errno]);
80 else
81 return rep_VAL(&unknown_err);
82 #endif
83 }
84
85 unsigned long
rep_getpid(void)86 rep_getpid (void)
87 {
88 return getpid ();
89 }
90
91 unsigned long
rep_time(void)92 rep_time(void)
93 {
94 return time(0);
95 }
96
97 rep_long_long
rep_utime(void)98 rep_utime (void)
99 {
100 rep_long_long t;
101 #ifdef HAVE_GETTIMEOFDAY
102 struct timeval time;
103 gettimeofday (&time, 0);
104 t = ((rep_long_long) time.tv_sec * 1000000) + time.tv_usec;
105 #else
106 t = (rep_long_long) rep_time () * 1000000;
107 #endif
108 return t;
109 }
110
111 void
rep_sleep_for(long secs,long msecs)112 rep_sleep_for(long secs, long msecs)
113 {
114 struct timeval timeout;
115 timeout.tv_sec = secs + msecs / 1000;
116 timeout.tv_usec = (msecs % 1000) * 1000;
117 select(FD_SETSIZE, NULL, NULL, NULL, &timeout);
118 }
119
120 repv
rep_user_login_name(void)121 rep_user_login_name(void)
122 {
123 /* Just look this up once, then use the saved copy. */
124 static repv user_login_name;
125 char *tmp;
126 if(user_login_name)
127 return user_login_name;
128
129 if(!(tmp = getlogin()))
130 {
131 struct passwd *pwd;
132 if(!(pwd = getpwuid(geteuid())))
133 return rep_NULL;
134 tmp = pwd->pw_name;
135 }
136 user_login_name = rep_string_dup(tmp);
137 rep_mark_static(&user_login_name);
138 return user_login_name;
139 }
140
141 repv
rep_user_full_name(void)142 rep_user_full_name(void)
143 {
144 struct passwd *pwd;
145 static repv user_full_name;
146 if(user_full_name)
147 return user_full_name;
148
149 if(!(pwd = getpwuid(geteuid())))
150 return rep_NULL;
151 #ifndef FULL_NAME_TERMINATOR
152 user_full_name = rep_string_dup(pwd->pw_gecos);
153 #else
154 {
155 char *end = strchr(pwd->pw_gecos, FULL_NAME_TERMINATOR);
156 if(end)
157 user_full_name = rep_string_dupn(pwd->pw_gecos, end - pwd->pw_gecos);
158 else
159 user_full_name = rep_string_dup(pwd->pw_gecos);
160 }
161 #endif
162 rep_mark_static(&user_full_name);
163 return user_full_name;
164 }
165
166 DEFSTRING(no_home, "Can't find home directory");
167 repv
rep_user_home_directory(repv user)168 rep_user_home_directory(repv user)
169 {
170 static repv user_home_directory;
171 if(rep_NILP(user) && user_home_directory)
172 return user_home_directory;
173 else
174 {
175 repv dir;
176 char *src = 0;
177 int len;
178
179 if(rep_NILP(user))
180 src = getenv("HOME");
181
182 if(src == 0)
183 {
184 struct passwd *pwd;
185 if(rep_NILP(user))
186 pwd = getpwuid(geteuid());
187 else
188 pwd = getpwnam(rep_STR(user));
189
190 if(pwd == 0 || pwd->pw_dir == 0)
191 return Fsignal(Qerror, rep_LIST_2(rep_VAL(&no_home), user));
192
193 src = pwd->pw_dir;
194 }
195
196 len = strlen(src);
197 if(src[len] != '/')
198 {
199 dir = rep_string_dupn(src, len + 1);
200 rep_STR(dir)[len] = '/';
201 rep_STR(dir)[len+1] = 0;
202 }
203 else
204 dir = rep_string_dup(src);
205
206 if(rep_NILP(user))
207 {
208 user_home_directory = dir;
209 rep_mark_static(&user_home_directory);
210 }
211
212 return dir;
213 }
214 }
215
216 repv
rep_system_name(void)217 rep_system_name(void)
218 {
219 char buf[256];
220 struct hostent *h;
221
222 static repv system_name;
223 if(system_name)
224 return system_name;
225
226 #ifdef HAVE_GETHOSTNAME
227 if(gethostname(buf, 256))
228 return rep_NULL;
229 #else
230 {
231 struct utsname uts;
232 uname(&uts);
233 strncpy(buf, uts.nodename, 256);
234 }
235 #endif
236 h = gethostbyname(buf);
237 if(h)
238 {
239 if(!strchr(h->h_name, '.'))
240 {
241 /* The official name is not fully qualified. Try looking
242 through the list of alternatives. */
243 char **aliases = h->h_aliases;
244 while(*aliases && !strchr(*aliases, '.'))
245 aliases++;
246 system_name = rep_string_dup(*aliases ? *aliases : h->h_name);
247 }
248 else
249 system_name = rep_string_dup((char *)h->h_name);
250 }
251 else
252 system_name = rep_string_dup(buf);
253 rep_mark_static(&system_name);
254 return system_name;
255 }
256
257
258 /* Main input loop */
259
260 /* This is the set of fds we're waiting for input from. */
261 static fd_set input_fdset;
262
263 /* For every bit set in unix_fd_read_set there should be a corresponding
264 function in here that will be called when input becomes available.
265 -- Is this really such a good idea, it's a lot of wasted space.. */
266 static void (*input_actions[FD_SETSIZE])(int);
267
268 /* A bit set in this array means that the corresponding fd has input read
269 but not yet handled. */
270 static fd_set input_pending;
271 static int input_pending_count;
272
273 void (*rep_register_input_fd_fun)(int fd, void (*callback)(int fd)) = 0;
274 void (*rep_deregister_input_fd_fun)(int fd) = 0;
275
276 #define MAX_EVENT_LOOP_CALLBACKS 16
277 static int next_event_loop_callback;
278 static rep_bool (*event_loop_callbacks[MAX_EVENT_LOOP_CALLBACKS])(void);
279
280 void
rep_register_input_fd(int fd,void (* callback)(int fd))281 rep_register_input_fd(int fd, void (*callback)(int fd))
282 {
283 FD_SET(fd, &input_fdset);
284 input_actions[fd] = callback;
285
286 if (rep_register_input_fd_fun != 0)
287 (*rep_register_input_fd_fun) (fd, callback);
288
289 rep_unix_set_fd_cloexec(fd);
290 }
291
292 void
rep_deregister_input_fd(int fd)293 rep_deregister_input_fd(int fd)
294 {
295 FD_CLR(fd, &input_fdset);
296 input_actions[fd] = NULL;
297
298 if (rep_deregister_input_fd_fun != 0)
299 (*rep_deregister_input_fd_fun) (fd);
300 }
301
302 void
rep_map_inputs(void (* fun)(int fd,void (* callback)(int)))303 rep_map_inputs (void (*fun)(int fd, void (*callback)(int)))
304 {
305 int i;
306 for (i = 0; i < FD_SETSIZE; i++)
307 {
308 if (input_actions[i] != 0)
309 fun (i, input_actions[i]);
310 }
311 }
312
313 void
rep_mark_input_pending(int fd)314 rep_mark_input_pending(int fd)
315 {
316 if(!FD_ISSET(fd, &input_pending))
317 {
318 FD_SET(fd, &input_pending);
319 input_pending_count++;
320 }
321 }
322
323 void
rep_unix_set_fd_nonblocking(int fd)324 rep_unix_set_fd_nonblocking(int fd)
325 {
326 int flags = fcntl(fd, F_GETFL, 0);
327 if(flags != -1)
328 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
329 }
330
331 void
rep_unix_set_fd_blocking(int fd)332 rep_unix_set_fd_blocking(int fd)
333 {
334 int flags = fcntl(fd, F_GETFL, 0);
335 if(flags != -1)
336 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
337 }
338
339 void
rep_unix_set_fd_cloexec(int fd)340 rep_unix_set_fd_cloexec(int fd)
341 {
342 /* Set close on exec flag. */
343 int tem = fcntl(fd, F_GETFD, 0);
344 if(tem != -1)
345 fcntl(fd, F_SETFD, tem | FD_CLOEXEC);
346 }
347
348 /* Turns on or off restarted system calls for SIG */
349 void
rep_sig_restart(int sig,rep_bool flag)350 rep_sig_restart(int sig, rep_bool flag)
351 {
352 #if defined (HAVE_SIGINTERRUPT)
353 siginterrupt (sig, !flag);
354 #else
355 struct sigaction act;
356 sigaction (sig, 0, &act);
357 if(flag)
358 {
359 # if defined (SA_RESTART)
360 act.sa_flags |= SA_RESTART;
361 # elif defined (SA_INTERRUPT)
362 act.sa_flags &= ~SA_INTERRUPT;
363 # endif
364 }
365 else
366 {
367 # if defined (SA_RESTART)
368 act.sa_flags &= ~SA_RESTART;
369 # elif defined (SA_INTERRUPT)
370 act.sa_flags |= SA_INTERRUPT;
371 # endif
372 }
373 sigaction(sig, &act, 0);
374 #endif /* !HAVE_SIGINTERRUPT */
375 }
376
377 void
rep_add_event_loop_callback(rep_bool (* callback)(void))378 rep_add_event_loop_callback (rep_bool (*callback)(void))
379 {
380 if (next_event_loop_callback == MAX_EVENT_LOOP_CALLBACKS)
381 abort ();
382 event_loop_callbacks [next_event_loop_callback++] = callback;
383 }
384
385 rep_bool
rep_proc_periodically(void)386 rep_proc_periodically (void)
387 {
388 rep_bool ret = rep_FALSE;
389 int i;
390 for (i = 0; i < next_event_loop_callback; i++)
391 {
392 if (event_loop_callbacks[i] ())
393 ret = rep_TRUE;
394 }
395 return ret;
396 }
397
398 /* Wait for input for no longer than TIMEOUT-MSECS for input fds defined
399 by INPUTS. If input arrived return the number of ready fds, with the
400 actual fds defined by the fdset INPUTS. Return zero if the timeout
401 was reached. */
402 static int
wait_for_input(fd_set * inputs,unsigned long timeout_msecs)403 wait_for_input(fd_set *inputs, unsigned long timeout_msecs)
404 {
405 fd_set copy;
406 int ready = -1;
407
408 if(input_pending_count > 0)
409 {
410 /* Check the pending inputs first.. */
411 fd_set out;
412 int i, count = 0, seen = 0;
413 for(i = 0; seen < input_pending_count && i < FD_SETSIZE; i++)
414 {
415 if(FD_ISSET(i, &input_pending))
416 {
417 seen++;
418 if(FD_ISSET(i, inputs))
419 {
420 if(count == 0)
421 FD_ZERO(&out);
422 FD_SET(i, &out);
423 count++;
424 }
425 }
426 }
427 if(count > 0)
428 {
429 memcpy(inputs, &out, sizeof(out));
430 return count;
431 }
432 }
433
434 /* Allow embedders to override this part of the function. */
435
436 if (rep_wait_for_input_fun != 0)
437 return (*rep_wait_for_input_fun) (inputs, timeout_msecs);
438
439 /* Break the timeout into one-second chunks, then check for
440 interrupt between each call to select. */
441 do {
442 struct timeval timeout;
443 unsigned long max_sleep = rep_max_sleep_for ();
444 unsigned long this_timeout_msecs = MIN (timeout_msecs,
445 rep_input_timeout_secs * 1000);
446 unsigned long actual_timeout_msecs = MIN (this_timeout_msecs, max_sleep);
447
448 timeout.tv_sec = actual_timeout_msecs / 1000;
449 timeout.tv_usec = (actual_timeout_msecs % 1000) * 1000;
450 memcpy (©, inputs, sizeof (copy));
451
452 /* Don't test for interrupts before the first call to select() */
453 if (ready == 0)
454 {
455 rep_TEST_INT_SLOW;
456 if (rep_INTERRUPTP)
457 break;
458 }
459
460 /* Don't want select() to restart after a SIGCHLD or SIGALRM;
461 there may be a notification to dispatch. */
462 rep_sig_restart(SIGCHLD, rep_FALSE);
463 rep_sig_restart(SIGALRM, rep_FALSE);
464 ready = select(FD_SETSIZE, ©, NULL, NULL, &timeout);
465 rep_sig_restart(SIGALRM, rep_TRUE);
466 rep_sig_restart(SIGCHLD, rep_TRUE);
467
468 if (ready == 0 && actual_timeout_msecs < this_timeout_msecs)
469 {
470 Fthread_suspend (Qnil, rep_MAKE_INT (this_timeout_msecs
471 - actual_timeout_msecs));
472 }
473
474 timeout_msecs -= this_timeout_msecs;
475 } while (ready == 0 && timeout_msecs > 0);
476
477 memcpy (inputs, ©, sizeof (copy));
478 return ready;
479 }
480
481 /* Handle the READY fds with pending input (defined by fdset INPUTS).
482 Return true if the display might require updating. Returns immediately
483 if a Lisp error has occurred. */
484 static rep_bool
handle_input(fd_set * inputs,int ready)485 handle_input(fd_set *inputs, int ready)
486 {
487 static long idle_period;
488 rep_bool refreshp = rep_FALSE;
489
490 if(ready > 0)
491 {
492 int i;
493
494 idle_period = 0;
495
496 for(i = 0; i < FD_SETSIZE && ready > 0 && !rep_INTERRUPTP; i++)
497 {
498 if(FD_ISSET(i, inputs))
499 {
500 ready--;
501 if(FD_ISSET(i, &input_pending))
502 {
503 FD_CLR(i, &input_pending);
504 input_pending_count--;
505 }
506 if(input_actions[i] != NULL)
507 {
508 input_actions[i](i);
509 refreshp = rep_TRUE;
510 }
511 }
512 }
513 }
514 else if(ready == 0)
515 {
516 /* A timeout. */
517 if(rep_INTERRUPTP || rep_on_idle(idle_period))
518 refreshp = rep_TRUE;
519
520 idle_period++;
521 }
522
523 if(!rep_INTERRUPTP && rep_proc_periodically())
524 refreshp = rep_TRUE;
525
526 return refreshp;
527 }
528
529 /* The input handler loop. */
530 repv
rep_event_loop(void)531 rep_event_loop(void)
532 {
533 repv result = Qnil;
534
535 if (rep_redisplay_fun != 0)
536 (*rep_redisplay_fun)();
537
538 while(1)
539 {
540 int ready;
541 rep_bool refreshp = rep_FALSE;
542 fd_set copy;
543
544 if (rep_throw_value == rep_NULL)
545 {
546 memcpy(©, &input_fdset, sizeof(copy));
547 ready = wait_for_input(©, rep_input_timeout_secs * 1000);
548 refreshp = handle_input(©, ready);
549 }
550
551 /* Check for exceptional conditions. */
552 if(rep_throw_value != rep_NULL)
553 {
554 if(rep_handle_input_exception(&result))
555 return result;
556 else
557 refreshp = rep_TRUE;
558 }
559
560 if(refreshp && rep_redisplay_fun != 0)
561 (*rep_redisplay_fun)();
562 }
563
564 return result;
565 }
566
567 repv
rep_sit_for(unsigned long timeout_msecs)568 rep_sit_for(unsigned long timeout_msecs)
569 {
570 fd_set copy;
571 int ready;
572 if(timeout_msecs != 0 && rep_redisplay_fun != 0)
573 (*rep_redisplay_fun)();
574 memcpy(©, &input_fdset, sizeof(copy));
575 ready = wait_for_input(©, timeout_msecs);
576 if(rep_INTERRUPTP)
577 return rep_NULL;
578 else
579 return (ready > 0) ? Qnil : Qt;
580 }
581
582 /* Wait TIMEOUT_MSECS for input, ignoring any input fds that would
583 invoke any callback function except CALLBACKS. Return Qnil if any
584 input was serviced, Qt if the timeout expired, rep_NULL for an error. */
585 repv
rep_accept_input_for_callbacks(unsigned long timeout_msecs,int ncallbacks,void (** callbacks)(int))586 rep_accept_input_for_callbacks (unsigned long timeout_msecs, int ncallbacks,
587 void (**callbacks)(int))
588 {
589 fd_set copy;
590 int ready, i;
591 FD_ZERO(©);
592 for(i = 0; i < FD_SETSIZE; i++)
593 {
594 if(FD_ISSET(i, &input_fdset))
595 {
596 int j;
597 for (j = 0; j < ncallbacks; j++)
598 {
599 if (input_actions[i] == callbacks[j])
600 {
601 FD_SET(i, ©);
602 break;
603 }
604 }
605 }
606 }
607 ready = wait_for_input(©, timeout_msecs);
608 if(ready > 0 && !rep_INTERRUPTP)
609 handle_input(©, ready);
610 if(rep_INTERRUPTP)
611 return rep_NULL;
612 else
613 return ready > 0 ? Qnil : Qt;
614 }
615
616 /* Wait TIMEOUT_MSECS for input from the NFDS file descriptors stored in FDS.
617 Return Qnil if any input was serviced, Qt if the timeout expired, rep_NULL
618 for an error. */
619 repv
rep_accept_input_for_fds(unsigned long timeout_msecs,int nfds,int * fds)620 rep_accept_input_for_fds (unsigned long timeout_msecs, int nfds, int *fds)
621 {
622 fd_set copy;
623 int ready, i;
624 FD_ZERO(©);
625 for(i = 0; i < nfds; i++)
626 {
627 if(FD_ISSET(fds[i], &input_fdset))
628 FD_SET(fds[i], ©);
629 }
630 ready = wait_for_input(©, timeout_msecs);
631 if(ready > 0 && !rep_INTERRUPTP)
632 handle_input(©, ready);
633 if(rep_INTERRUPTP)
634 return rep_NULL;
635 else
636 return ready > 0 ? Qnil : Qt;
637 }
638
639 /* obsolete, for compatibility only */
640 repv
rep_accept_input(unsigned long timeout_msecs,void (* callback)(int))641 rep_accept_input(unsigned long timeout_msecs, void (*callback)(int))
642 {
643 return rep_accept_input_for_callbacks (timeout_msecs, 1, &callback);
644 }
645
646 rep_bool
rep_poll_input(int fd)647 rep_poll_input(int fd)
648 {
649 fd_set in;
650 FD_ZERO(&in);
651 FD_SET(fd, &in);
652 return wait_for_input(&in, 0);
653 }
654
655
656 /* Memory allocation; most of these are normally macros in unix_defs.h */
657
658 #ifdef DEBUG_SYS_ALLOC
659 struct alloc_data {
660 struct alloc_data *next;
661 size_t size;
662 void *function;
663 double unused; /* double to force good alignment */
664 };
665
666 #define SIZEOF_ALLOC_DATA (sizeof (struct alloc_data) - sizeof (double))
667
668 static struct alloc_data *allocations;
669
670 void *
rep_alloc(unsigned int length)671 rep_alloc(unsigned int length)
672 {
673 void *mem;
674 length += SIZEOF_ALLOC_DATA;
675 mem = malloc(length);
676 if(mem != 0)
677 {
678 struct alloc_data *x = mem;
679
680 /* Check that the alignment promised actually occurs */
681 assert((((rep_PTR_SIZED_INT)mem) & (rep_MALLOC_ALIGNMENT - 1)) == 0);
682
683 mem = ((char *)mem) + SIZEOF_ALLOC_DATA;
684 x->next = allocations;
685 allocations = x;
686 x->size = length - SIZEOF_ALLOC_DATA;
687 x->function = rep_db_return_address();
688 }
689 return mem;
690 }
691
692 void *
rep_realloc(void * ptr,unsigned int length)693 rep_realloc(void *ptr, unsigned int length)
694 {
695 void *mem;
696 length += SIZEOF_ALLOC_DATA;
697 ptr = (void *)(((char *)ptr) - SIZEOF_ALLOC_DATA);
698 mem = realloc(ptr, length);
699 if(mem != 0)
700 {
701 struct alloc_data *x = mem;
702
703 /* Check that the alignment promised actually occurs */
704 assert((((rep_PTR_SIZED_INT)mem) & (rep_MALLOC_ALIGNMENT - 1)) == 0);
705
706 if(allocations == ptr)
707 allocations = x;
708 else
709 {
710 struct alloc_data *p = allocations;
711 while(p->next != ptr)
712 p = p->next;
713 p->next = x;
714 }
715 mem = ((char *)mem) + SIZEOF_ALLOC_DATA;
716 x->size = length - SIZEOF_ALLOC_DATA;
717 x->function = rep_db_return_address();
718 }
719 return mem;
720 }
721
722 void
rep_free(void * ptr)723 rep_free(void *ptr)
724 {
725 struct alloc_data *x = (struct alloc_data *)(((char *)ptr) - SIZEOF_ALLOC_DATA);
726 struct alloc_data **p = &allocations;
727 while(*p != 0 && (*p) != x)
728 p = &((*p)->next);
729 assert(*p != 0);
730 (*p) = x->next;
731 free(x);
732 }
733
734 void
rep_print_allocations(void)735 rep_print_allocations(void)
736 {
737 if(allocations != 0)
738 {
739 struct alloc_data *x = allocations;
740 fprintf(stderr, "\n\nOutstanding allocations:\n\n");
741 while(x != 0)
742 {
743 char *sname;
744 void *saddr;
745 fprintf(stderr, "\t(%p, %d)",
746 ((char *)x) + SIZEOF_ALLOC_DATA, x->size);
747 if(rep_find_c_symbol(x->function, &sname, &saddr))
748 fprintf(stderr, "\t\t<%s+%d>", sname, x->function - saddr);
749 fprintf(stderr, "\n");
750 x = x->next;
751 }
752 }
753 }
754
755 DEFUN("unix-print-allocations", Funix_print_allocations,
756 Sunix_print_allocations, (void), rep_Subr0) /*
757 ::doc:rep.lang.debug#unix-print-allocations::
758 unix-print-allocations
759
760 Output a list of all allocated memory blocks to standard error.
761 ::end:: */
762 {
763 rep_print_allocations();
764 return Qt;
765 }
766 #endif
767
768
769 /* Standard signal handlers */
770
771 static volatile rep_bool in_fatal_signal_handler;
772
773 /* Invoked by any of the handlable error reporting signals */
774 static RETSIGTYPE
fatal_signal_handler(int sig)775 fatal_signal_handler(int sig)
776 {
777 /* Sometimes this function can get in an infinite loop, even with the
778 in_fatal_signal_handler exclusion? Does this help..? */
779 signal(sig, SIG_DFL);
780
781 /* Check for nested calls to this function */
782 if(in_fatal_signal_handler)
783 raise(sig);
784 in_fatal_signal_handler = rep_TRUE;
785
786 #ifdef HAVE_PSIGNAL
787 psignal(sig, "rep: received fatal signal");
788 #else
789 # ifdef HAVE_STRSIGNAL
790 fprintf(stderr, "rep: received fatal signal: %s\n", strsignal(sig));
791 # else
792 fprintf(stderr, "rep: received fatal signal: %d\n", sig);
793 # endif
794 #endif
795
796 /* Save the C backtrace */
797 rep_db_print_backtrace(rep_common_db, "fatal_signal_handler");
798
799 /* Output all debug buffers */
800 rep_db_spew_all();
801
802 /* Try and output the Lisp call stack; this may or may not
803 provoke another error, but who cares.. */
804 fprintf(stderr, "\nLisp backtrace:\n");
805 Fbacktrace(Fstderr_file());
806 fputs("\n", stderr);
807
808 /* Now reraise the signal, since it's currently blocked
809 the default action will occur, i.e. termination */
810 raise(sig);
811 }
812
813 /* Invoked by SIGINT (i.e. ^C) */
814 static RETSIGTYPE
interrupt_signal_handler(int sig)815 interrupt_signal_handler(int sig)
816 {
817 if (rep_throw_value == rep_int_cell)
818 {
819 signal (sig, SIG_DFL);
820 raise (sig);
821 }
822 else
823 {
824 rep_throw_value = rep_int_cell;
825 signal (sig, interrupt_signal_handler);
826 }
827 }
828
829 /* Invoked by trappable termination signals */
830 static RETSIGTYPE
termination_signal_handler(int sig)831 termination_signal_handler(int sig)
832 {
833 if (rep_throw_value == rep_term_cell)
834 {
835 signal (sig, SIG_DFL);
836 raise (sig);
837 }
838 else
839 {
840 rep_throw_value = rep_term_cell;
841 signal (sig, termination_signal_handler);
842 }
843 }
844
845 /* Invoked by SIGUSR1 or SIGUSR2 */
846 static RETSIGTYPE
usr_signal_handler(int sig)847 usr_signal_handler (int sig)
848 {
849 switch (sig)
850 {
851 case SIGUSR1:
852 fprintf(stderr, "\n\nLisp backtrace:\n");
853 Fbacktrace(Fstderr_file());
854 fputs("\n\n", stderr);
855 break;
856
857 case SIGUSR2:
858 fprintf (stderr, "\n\nDebug buffers:\n");
859 rep_db_spew_all ();
860 fputc ('\n', stderr);
861 break;
862 }
863 signal (sig, usr_signal_handler);
864 }
865
866
867 /* Initialisation */
868
869 /* This function is called _before_ almost anything else; but
870 most importantly, it's called before sys_init() (i.e. we
871 start opening displays) */
872 void
rep_pre_sys_os_init(void)873 rep_pre_sys_os_init(void)
874 {
875 FD_ZERO(&input_fdset);
876 FD_ZERO(&input_pending);
877
878 /* First the error signals */
879 #ifndef IGNORE_FATAL_SIGNALS
880 #ifdef SIGFPE
881 if(signal(SIGFPE, fatal_signal_handler) == SIG_IGN)
882 signal(SIGFPE, SIG_IGN);
883 #endif
884 #ifdef SIGILL
885 if(signal(SIGILL, fatal_signal_handler) == SIG_IGN)
886 signal(SIGILL, SIG_IGN);
887 #endif
888 #ifdef SIGSEGV
889 if(signal(SIGSEGV, fatal_signal_handler) == SIG_IGN)
890 signal(SIGSEGV, SIG_IGN);
891 #endif
892 #ifdef SIGBUS
893 if(signal(SIGBUS, fatal_signal_handler) == SIG_IGN)
894 signal(SIGBUS, SIG_IGN);
895 #endif
896 #ifdef SIGQUIT
897 if(signal(SIGQUIT, fatal_signal_handler) == SIG_IGN)
898 signal(SIGQUIT, SIG_IGN);
899 #endif
900 #ifdef SIGABRT
901 if(signal(SIGABRT, fatal_signal_handler) == SIG_IGN)
902 signal(SIGABRT, SIG_IGN);
903 #endif
904 #endif
905
906 /* Install the interrupt handler */
907 #ifdef SIGINT
908 if(signal(SIGINT, interrupt_signal_handler) == SIG_IGN)
909 signal(SIGINT, SIG_IGN);
910 else
911 rep_sig_restart (SIGINT, rep_FALSE);
912 #endif
913
914 /* Finally, the termination signals */
915 #ifdef SIGTERM
916 if(signal(SIGTERM, termination_signal_handler) == SIG_IGN)
917 signal(SIGTERM, SIG_IGN);
918 else
919 rep_sig_restart (SIGTERM, rep_FALSE);
920 #endif
921 #ifdef SIGHUP
922 if(signal(SIGHUP, termination_signal_handler) == SIG_IGN)
923 signal(SIGHUP, SIG_IGN);
924 else
925 rep_sig_restart (SIGHUP, rep_FALSE);
926 #endif
927
928 #ifdef SIGUSR1
929 signal(SIGUSR1, usr_signal_handler);
930 #endif
931 #ifdef SIGUSR2
932 signal(SIGUSR2, usr_signal_handler);
933 #endif
934 }
935
936 /* More normal initialisation. */
937 void
rep_sys_os_init(void)938 rep_sys_os_init(void)
939 {
940 repv env;
941 char **ptr;
942
943 /* Initialise process-environment variable */
944 env = Qnil;
945 if (environ != 0)
946 {
947 ptr = environ;
948 while(*ptr != 0)
949 env = Fcons(rep_string_dup(*ptr++), env);
950 }
951 Fset (Qprocess_environment, env);
952
953 #ifdef DEBUG_SYS_ALLOC
954 { repv tem = rep_push_structure ("rep.lang.debug");
955 rep_ADD_SUBR(Sunix_print_allocations);
956 rep_pop_structure (tem); }
957 #endif
958
959 rep_proc_init();
960 }
961
962 void
rep_sys_os_kill(void)963 rep_sys_os_kill(void)
964 {
965 rep_proc_kill();
966 }
967