1 /*	$Id: Termination.c,v 1.5 2004/12/15 11:27:03 mva Exp $	*/
2 /*  Provides procedures for program finalization.
3     Copyright (C) 1997, 1999, 2000, 2002  Michael van Acken
4 
5     This module is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public License
7     as published by the Free Software Foundation; either version 2 of
8     the License, or (at your option) any later version.
9 
10     This module is distributed in the hope that it will be useful, but
11     WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with OOC. If not, write to the Free Software Foundation,
17     59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <sys/types.h>
23 
24 #include <Termination.d>
25 #include <__config.h>
26 
27 #if HAVE_UNISTD_H
28 #include <unistd.h>
29 #elif HAVE_IO_H
30 #include <io.h>
31 #endif
32 
33 
34 #if !HAVE_ATEXIT  /* assume this is a SunOS 4, use on_exit instead */
35 extern int on_exit(void (*procp)(void),void* arg);
36 #endif
37 
38 static Termination__Proc *proc_list = NULL;
39 static int proc_count = 0;
40 static int max_proc_count = 0;
41 static volatile int /*sig_atomic_t*/ noSignalHandlerInProgress = 1;
42 
Termination__RegisterProc(Termination__Proc proc)43 void Termination__RegisterProc(Termination__Proc proc) {
44   int i;
45 
46   if (proc_count == 0) {
47     max_proc_count = 32;
48     proc_list = RT0__NewBlock(sizeof(Termination__Proc)*max_proc_count);
49     for (i=0; i<max_proc_count; i++) {
50       proc_list[i] = (Termination__Proc)NULL;
51     }
52   } else if (proc_count == max_proc_count) {
53     static Termination__Proc *new;
54 
55     max_proc_count += 32;
56     new = RT0__NewBlock(sizeof(Termination__Proc)*max_proc_count);
57     for (i=0; i<proc_count; i++) {
58       new[i] = proc_list[i];
59     }
60     for (i=proc_count; i<max_proc_count; i++) {
61       new[i] = (Termination__Proc)NULL;
62     }
63     proc_list = new;
64   }
65 
66   proc_list[proc_count] = proc;
67   proc_count++;
68 }
69 
Termination__UnregisterProc(Termination__Proc proc)70 void Termination__UnregisterProc(Termination__Proc proc) {
71   int i, j;
72 
73   i = proc_count;
74   while (i != 0) {
75     i--;
76     if (proc_list[i] == proc) {
77       j = i+1;
78       while (j != proc_count) {
79 	proc_list[j-1] = proc_list[j];
80 	j++;
81       }
82       proc_count--;
83       return;
84     }
85   }
86 }
87 
88 
run_term_procs(void)89 static void run_term_procs (void) {
90   int i;
91   Termination__Proc ptr;
92 
93   i = proc_count;
94   while (i != 0) {
95     i--;
96     ptr = proc_list[i];
97     if (ptr) {
98       proc_list[i] = (Termination__Proc)NULL;
99       (*ptr)();
100     }
101   }
102 }
103 
signal_handler(int sig)104 static RETSIGTYPE signal_handler (int sig) {
105   signal(sig, SIG_DFL);  /* install default handler, necessary for SunOS 4 */
106   if (noSignalHandlerInProgress) {
107     noSignalHandlerInProgress = 0;
108     run_term_procs();
109   }
110 #if HAVE_RAISE
111   raise(sig);
112 #else
113   (void)kill(getpid(), sig);	/* raise signal to call default handler */
114 #endif
115 }
116 
catch_signal(int sig)117 static void catch_signal (int sig) {
118   void (*func)(int);
119 
120   func = signal (sig, signal_handler);
121   if (func == SIG_IGN) {
122     signal (sig, SIG_IGN);
123   }
124 }
125 
OOC_Termination_init(void)126 void OOC_Termination_init(void) {
127   /* error signals */
128   catch_signal(SIGFPE);
129   catch_signal(SIGILL);
130   catch_signal(SIGSEGV);
131   catch_signal(SIGABRT);
132 #ifdef SIGBUS
133   catch_signal(SIGBUS);
134 #endif
135 #ifdef SIGIOT
136   catch_signal(SIGIOT);
137 #endif
138 #ifdef SIGSTKFLT
139   catch_signal(SIGSTKFLT);
140 #endif
141 
142   /* termination signals */
143 #ifdef SIGHUP
144   catch_signal(SIGHUP);
145 #endif
146   catch_signal(SIGINT);
147 #ifdef SIGQUIT
148   catch_signal(SIGQUIT);
149 #endif
150   catch_signal(SIGTERM);
151 
152   /* normal program exit */
153 #if HAVE_ATEXIT
154   (void)atexit(&run_term_procs);
155 #else
156   (void)on_exit(&run_term_procs,NULL);
157 #endif
158 }
159 
OOC_Termination_destroy(void)160 void OOC_Termination_destroy(void) {
161   /* FIXME... if we ever to module unloading  */
162 }
163