fix app terminate fail issue in TaskManager
[framework/appfw/debug-launchpad.git] / src / sigchild.h
1 /*
2  *  debug-launchpad
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jungmin Cho <chivalry.cho@samsung.com>, Gwangho Hwang <gwang.hwang@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22
23 #include <pthread.h>
24 #include "app_signal.h"
25
26 static struct sigaction old_sigchild;
27 static DBusConnection *bus = NULL;
28 sigset_t oldmask;
29 static int gdbserver_pid;
30 static int gdbserver_app_pid;
31
32 static inline void __socket_garbage_collector()
33 {
34         DIR *dp;
35         struct dirent *dentry;
36         char tmp[MAX_LOCAL_BUFSZ];
37
38         dp = opendir(AUL_SOCK_PREFIX);
39         if (dp == NULL)
40                 return;
41
42         while ((dentry = readdir(dp)) != NULL) {
43                 if (!isdigit(dentry->d_name[0]))
44                         continue;
45
46                 snprintf(tmp, MAX_LOCAL_BUFSZ, "/proc/%s", dentry->d_name);
47                 if (access(tmp, F_OK) < 0) {    /* Flawfinder: ignore */
48                         snprintf(tmp, MAX_LOCAL_BUFSZ, "%s/%s", AUL_SOCK_PREFIX,
49                                  dentry->d_name);
50                         unlink(tmp);
51                         continue;
52                 }
53         }
54         closedir(dp);
55 }
56
57 static inline int __send_app_dead_signal(int dead_pid)
58 {
59         DBusMessage *message;
60
61         if (bus == NULL)
62                 return -1;
63
64         message = dbus_message_new_signal(AUL_DBUS_PATH,
65                                           AUL_DBUS_SIGNAL_INTERFACE,
66                                           AUL_DBUS_APPDEAD_SIGNAL);
67
68         if (dbus_message_append_args(message,
69                                      DBUS_TYPE_UINT32, &dead_pid,
70                                      DBUS_TYPE_INVALID) == FALSE) {
71                 _E("Failed to load data error");
72                 return -1;
73         }
74
75         if (dbus_connection_send(bus, message, NULL) == FALSE) {
76                 _E("dbus send error");
77                 return -1;
78         }
79
80         dbus_connection_flush(bus);
81         dbus_message_unref(message);
82
83         _D("send dead signal done\n");
84
85         return 0;
86 }
87
88 static inline int __send_app_launch_signal(int launch_pid)
89 {
90         DBusMessage *message;
91
92         if (bus == NULL)
93                 return -1;
94
95         message = dbus_message_new_signal(AUL_DBUS_PATH,
96                                           AUL_DBUS_SIGNAL_INTERFACE,
97                                           AUL_DBUS_APPLAUNCH_SIGNAL);
98
99         if (dbus_message_append_args(message,
100                                      DBUS_TYPE_UINT32, &launch_pid,
101                                      DBUS_TYPE_INVALID) == FALSE) {
102                 _E("Failed to load data error");
103                 return -1;
104         }
105
106         if (dbus_connection_send(bus, message, NULL) == FALSE) {
107                 _E("dbus send error");
108                 return -1;
109         }
110
111         dbus_connection_flush(bus);
112         dbus_message_unref(message);
113
114         _D("send launch signal done\n");
115
116         return 0;
117 }
118
119 static int __sigchild_action(void *data)
120 {
121         pid_t dead_pid;
122         char buf[MAX_LOCAL_BUFSZ];
123
124         dead_pid = (pid_t) data;
125         if (dead_pid <= 0)
126                 goto end;
127
128         /* send app pid instead of gdbserver pid */
129         if(dead_pid == gdbserver_pid)
130                 dead_pid = gdbserver_app_pid;
131
132         __send_app_dead_signal(dead_pid);
133
134         snprintf(buf, MAX_LOCAL_BUFSZ, "%s/%d", AUL_SOCK_PREFIX, dead_pid);
135         unlink(buf);
136
137         __socket_garbage_collector();
138  end:
139         return 0;
140 }
141
142 static void __launchpad_sig_child(int signo, siginfo_t *info, void *data)
143 {
144         int status;
145         pid_t child_pid;
146         pid_t child_pgid;
147
148         child_pgid = getpgid(info->si_pid);
149         _D("dead_pid = %d pgid = %d", info->si_pid, child_pgid);
150
151         while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
152                 if (child_pid == child_pgid)
153                         killpg(child_pgid, SIGKILL);
154                 __sigchild_action((void *)child_pid);
155         }
156
157         return;
158 }
159
160 static inline int __signal_init(void)
161 {
162         int i;
163         for (i = 0; i < _NSIG; i++) {
164                 switch (i) {
165                         /* controlled by sys-assert package*/
166                 case SIGQUIT:
167                 case SIGILL:
168                 case SIGABRT:
169                 case SIGBUS:
170                 case SIGFPE:
171                 case SIGSEGV:
172                 case SIGPIPE:
173                         break;
174                 default:
175                         signal(i, SIG_DFL);
176                         break;
177                 }
178         }
179
180         return 0;
181 }
182
183 static inline int __signal_set_sigchld(void)
184 {
185         struct sigaction act;
186         DBusError error;
187
188         dbus_error_init(&error);
189         dbus_threads_init_default();
190         bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
191         if (!bus) {
192                 _E("Failed to connect to the D-BUS daemon: %s", error.message);
193                 dbus_error_free(&error);
194                 return -1;
195         }
196         /* TODO: if process stop mechanism is included, 
197         should be modified (SA_NOCLDSTOP)*/
198         act.sa_handler = NULL;
199         act.sa_sigaction = __launchpad_sig_child;
200         sigemptyset(&act.sa_mask);
201         act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
202
203         if (sigaction(SIGCHLD, &act, &old_sigchild) < 0)
204                 return -1;
205
206         return 0;
207 }
208
209 static inline int __signal_unset_sigchld(void)
210 {
211         struct sigaction dummy;
212
213         if (bus == NULL)
214                 return 0;
215
216         dbus_connection_close(bus);
217         if (sigaction(SIGCHLD, &old_sigchild, &dummy) < 0)
218                 return -1;
219
220         return 0;
221 }
222
223 static inline int __signal_block_sigchld(void)
224 {
225         sigset_t newmask;
226
227         sigemptyset(&newmask);
228         sigaddset(&newmask, SIGCHLD);
229
230         if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) {
231                 _E("SIG_BLOCK error");
232                 return -1;
233         }
234
235         _D("SIGCHLD blocked");
236
237         return 0;
238 }
239
240 static inline int __signal_unblock_sigchld(void)
241 {
242         if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
243                 _E("SIG_SETMASK error");
244                 return -1;
245         }
246
247         _D("SIGCHLD unblocked");
248         return 0;
249 }
250
251 static inline int __signal_fini(void)
252 {
253 #ifndef PRELOAD_ACTIVATE
254         int i;
255         for (i = 0; i < _NSIG; i++)
256                 signal(i, SIG_DFL);
257 #endif
258         return 0;
259 }
260