Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * Copyright (C) 2005-2006 Voice Sistem S.R.L |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips 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 | | * opensips 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | * |
21 | | */ |
22 | | |
23 | | #include <sys/types.h> |
24 | | #include <sys/wait.h> |
25 | | #include <stdlib.h> |
26 | | #include <signal.h> |
27 | | #include <unistd.h> |
28 | | |
29 | | #include "lib/dbg/profiling.h" |
30 | | #include "config.h" |
31 | | #include "dprint.h" |
32 | | #include "daemonize.h" |
33 | | #include "globals.h" |
34 | | #include "pt.h" |
35 | | #include "route.h" |
36 | | #include "script_cb.h" |
37 | | #include "blacklists.h" |
38 | | #include "status_report.h" |
39 | | #include "mem/shm_mem.h" |
40 | | #include "db/db_insertq.h" |
41 | | #include "net/net_udp.h" |
42 | | #include "net/net_tcp.h" |
43 | | #include "shutdown.h" |
44 | | |
45 | | /** |
46 | | * Clean up on exit. This should be called before exiting. |
47 | | * \param show_status set to one to display the mem status |
48 | | */ |
49 | | void cleanup(int show_status) |
50 | 0 | { |
51 | 0 | LM_INFO("cleanup\n"); |
52 | | |
53 | | /*clean-up*/ |
54 | |
|
55 | | #ifdef DBG_MALLOC |
56 | | if (shm_memlog_size && mem_dbg_lock) |
57 | | shm_dbg_unlock(); |
58 | | #endif |
59 | |
|
60 | 0 | handle_ql_shutdown(); |
61 | 0 | destroy_modules(); |
62 | 0 | udp_destroy(); |
63 | 0 | tcp_destroy(); |
64 | 0 | destroy_timer(); |
65 | 0 | if (shm_memlog_size) |
66 | 0 | shm_mem_disable_dbg(); |
67 | 0 | destroy_stats_collector(); |
68 | 0 | destroy_script_cb(); |
69 | 0 | pv_free_extra_list(); |
70 | 0 | tr_free_extra_list(); |
71 | 0 | destroy_argv_list(); |
72 | 0 | destroy_black_lists(); |
73 | 0 | free_route_lists(sroutes); // this is just for testing purposes |
74 | | #ifdef PKG_MALLOC |
75 | | if (show_status){ |
76 | | LM_GEN1(memdump, "Memory status (pkg):\n"); |
77 | | pkg_status(); |
78 | | } |
79 | | #endif |
80 | 0 | cleanup_log_level(); |
81 | |
|
82 | 0 | if (pt && (0 |
83 | 0 | #if defined F_MALLOC || defined Q_MALLOC |
84 | 0 | || mem_lock |
85 | 0 | #endif |
86 | | #ifdef HP_MALLOC |
87 | | || mem_locks |
88 | | #endif |
89 | 0 | )) |
90 | 0 | shm_free(pt); |
91 | 0 | pt=0; |
92 | 0 | if (show_status){ |
93 | 0 | LM_GEN1(memdump, "Memory status (shm):\n"); |
94 | 0 | shm_status(); |
95 | 0 | } |
96 | | |
97 | 0 | cleanup_log_cons_shm_table(); |
98 | | |
99 | | /* zero all shmem alloc vars that we still use */ |
100 | 0 | shm_mem_destroy(); |
101 | 0 | if (pid_file) unlink(pid_file); |
102 | 0 | if (pgid_file) unlink(pgid_file); |
103 | 0 | } |
104 | | |
105 | | |
106 | | /** |
107 | | * Send a signal to all child processes |
108 | | * \param signum signal for killing the children |
109 | | */ |
110 | | void kill_all_children(int signum) |
111 | 0 | { |
112 | 0 | int r; |
113 | |
|
114 | 0 | if (!pt) |
115 | 0 | return; |
116 | | |
117 | 0 | for (r = 1; r < counted_max_processes; r++) { |
118 | 0 | if (pt[r].pid == -1 || (pt[r].flags & OSS_PROC_DOING_DUMP)) |
119 | 0 | continue; |
120 | | |
121 | | /* as the PIDs are filled in by child processes, a 0 PID means |
122 | | * an un-initalized procees; killing an uninitialized proc is |
123 | | * very dangerous, so better wait for it to finish its init |
124 | | * sequence by blocking until the pid is populated */ |
125 | 0 | while (pt[r].pid == 0) |
126 | 0 | usleep(1000); |
127 | |
|
128 | 0 | kill(pt[r].pid, signum); |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | | |
133 | | /** |
134 | | * SIGALRM "timeout" handler during the attendant's final cleanup, |
135 | | * try to leave a core for future diagnostics. |
136 | | */ |
137 | | static void sig_alarm_abort(int signo) |
138 | 0 | { |
139 | | /* LOG is not signal safe, but who cares, we are abort-ing anyway :-) */ |
140 | 0 | LM_CRIT("BUG - shutdown timeout triggered, dying...\n"); |
141 | 0 | abort(); |
142 | 0 | } |
143 | | |
144 | | |
145 | | /* RPC function send by main process to all worker processes supporting |
146 | | * IPC in order to force a gracefull termination |
147 | | */ |
148 | | static void rpc_process_terminate(int sender_id, void *code) |
149 | 0 | { |
150 | | #ifdef PKG_MALLOC |
151 | | LM_GEN1(memdump, "Memory status (pkg):\n"); |
152 | | pkg_status(); |
153 | | #endif |
154 | | |
155 | | /* simply terminate the process */ |
156 | 0 | LM_DBG("Process %d exiting with code %d...\n", |
157 | 0 | process_no, (int)(long)code); |
158 | |
|
159 | 0 | _ProfilerStop(); |
160 | 0 | exit( (int)(long)code ); |
161 | 0 | } |
162 | | |
163 | | |
164 | | /* Implements full shutdown sequence (terminate processes and cleanup) |
165 | | * To be called ONLY from MAIN process, not from workers !!! |
166 | | */ |
167 | | void shutdown_opensips( int status ) |
168 | 0 | { |
169 | 0 | pid_t proc; |
170 | 0 | int i, n, p; |
171 | 0 | int chld_status; |
172 | |
|
173 | 0 | sr_set_core_status_terminating(); |
174 | |
|
175 | 0 | distroy_log_event_cons(); |
176 | | |
177 | | /* terminate all processes */ |
178 | | |
179 | | /* first we try to terminate the processes via the IPC channel */ |
180 | 0 | for( i=1,n=0 ; i<counted_max_processes; i++) { |
181 | | /* Depending on the processes status, its PID may be: |
182 | | * -1 - process not forked yet |
183 | | * 0 - process forked but not fully configured by core |
184 | | * >0 - process fully running |
185 | | */ |
186 | 0 | if (pt[i].pid!=-1) { |
187 | | /* use IPC (if avaiable) for a graceful termination */ |
188 | 0 | if ( IPC_FD_WRITE(i)>0 ) { |
189 | 0 | LM_DBG("Asking process %d [%s] to terminate\n", i, pt[i].desc); |
190 | 0 | if (ipc_send_rpc( i, rpc_process_terminate, (void*)0)<0) { |
191 | 0 | LM_ERR("failed to trigger RPC termination for " |
192 | 0 | "process %d\n", i ); |
193 | 0 | } |
194 | 0 | } else { |
195 | 0 | while (pt[i].pid==0) usleep(1000); |
196 | 0 | kill(pt[i].pid, SIGTERM); |
197 | 0 | } |
198 | 0 | n++; |
199 | 0 | } |
200 | 0 | } |
201 | | |
202 | | /* now wait for the processes to finish */ |
203 | 0 | i = GRACEFUL_SHUTDOWN_TIMEOUT * 100; |
204 | 0 | while( i && n ) { |
205 | 0 | proc = waitpid( -1, &chld_status, WNOHANG); |
206 | 0 | if (proc<=0) { |
207 | | /* no process exited so far, do a small sleep before retry */ |
208 | 0 | usleep(10000); |
209 | 0 | i--; |
210 | 0 | } else { |
211 | 0 | if ( (p=get_process_ID_by_PID(proc)) == -1 ) { |
212 | 0 | LM_DBG("unknown child process %d ended. Ignoring\n",proc); |
213 | 0 | } else { |
214 | 0 | LM_INFO("process %d(%d) [%s] terminated, " |
215 | 0 | "still waiting for %d more\n", p, proc, pt[p].desc, n-1); |
216 | | /* mark the child process as terminated / not running */ |
217 | 0 | pt[p].pid = -1; |
218 | 0 | status |= chld_status; |
219 | 0 | n--; |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | |
|
224 | 0 | if (i==0 && n!=0) { |
225 | 0 | LM_DBG("force termination for all processes\n"); |
226 | 0 | kill_all_children(SIGKILL); |
227 | 0 | } |
228 | |
|
229 | 0 | _ProfilerStop(); |
230 | | |
231 | | /* Only one process is running now. Clean up and return overall status */ |
232 | | |
233 | | /* hack: force-unlock the shared memory lock(s) in case |
234 | | some process crashed and let it locked; this will |
235 | | allow an almost gracious shutdown */ |
236 | 0 | shm_force_unlock(); |
237 | |
|
238 | 0 | signal(SIGALRM, sig_alarm_abort); |
239 | 0 | alarm(SHUTDOWN_TIMEOUT - i / 100); |
240 | 0 | cleanup(1); |
241 | 0 | alarm(0); |
242 | 0 | signal(SIGALRM, SIG_IGN); |
243 | |
|
244 | 0 | stderr_dprint_tmp("Thank you for running " NAME "\n"); |
245 | 0 | exit( status ); |
246 | 0 | } |