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