1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2003 Naba Kumar <naba@gnome.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Library General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * SECTION:anjuta-children
23 * @title: Children management
24 * @short_description: Children management in Anjuta
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-children.h
29 * All child processes in anjuta are registred using API here. SIGCHLD should
30 * never be used directly. Use anjuta_children_register() or
31 * anjuta_children_unregister() to register or unregister a child process.
32 * Notifications are sent if callback function is given in
33 * anjuta_children_register(), which can be used in lieu of hooking SIGCHLD
36 * plugin developers should not bother about anjuta_children_init() and
37 * anjuta_children_finalize() functions. They are only for the shell
42 #include <libanjuta/anjuta-children.h>
43 #include <libanjuta/anjuta-debug.h>
44 #define EXIT_POLL_TIMEOUT 100 /* 100 ms */
46 static GList
*registered_child_processes
= NULL
;
47 static GList
*registered_child_processes_cb
= NULL
;
48 static GList
*registered_child_processes_cb_data
= NULL
;
49 static GList
*pending_exit_notifies
= NULL
;
50 static gint exit_poll_timeout
= 0;
58 on_notify_child_exit (gpointer user_data
)
61 int (*callback
) (int st
, gpointer d
);
63 ExitNotifyData
*idle_data
; /* = (ExitNotifyData*) user_data; */
67 /* If no child is currently registered, remove timer */
68 if (registered_child_processes
== NULL
)
70 DEBUG_PRINT ("No child process to monitor, destroying poll timer");
71 exit_poll_timeout
= 0;
75 /* If nothing pending, wait for next poll */
76 if (pending_exit_notifies
== NULL
)
79 idle_data
= pending_exit_notifies
->data
;
80 pending_exit_notifies
= g_list_remove_link (pending_exit_notifies
,
81 pending_exit_notifies
);
83 status
= idle_data
->status
;
86 idx
= g_list_index (registered_child_processes
, (int *) pid
);
88 return TRUE
; /* Continue polling */
91 g_list_nth_data (registered_child_processes_cb
, idx
);
92 g_return_val_if_fail (callback
!= NULL
, TRUE
);
94 cb_data
= g_list_nth_data (registered_child_processes_cb_data
, idx
);
96 (*callback
) (status
, cb_data
);
97 anjuta_children_unregister (pid
);
99 /* If no child is currently registered, remove timer */
100 if (registered_child_processes
== NULL
)
102 DEBUG_PRINT ("No child process to monitor, destroying poll timer");
103 exit_poll_timeout
= 0;
106 return TRUE
; /* Otherwise continue polling */
110 anjuta_child_terminated (int t
)
115 sigset_t set
, oldset
;
117 /* block other incoming SIGCHLD signals */
119 sigaddset(&set
, SIGCHLD
);
120 sigprocmask(SIG_BLOCK
, &set
, &oldset
);
124 ExitNotifyData
*idle_data
;
126 pid
= waitpid (-1, &status
, WNOHANG
);
130 idx
= g_list_index (registered_child_processes
, (int *) pid
);
134 idle_data
= g_new0 (ExitNotifyData
, 1);
135 idle_data
->pid
= pid
;
136 idle_data
->status
= status
;
138 /* Queue the exit notify so that it is handled in proper main loop
140 * FIXME: This is not thread safe. We should instead created a GSource
141 * class for this 'event'.
143 pending_exit_notifies
= g_list_append (pending_exit_notifies
,
146 /* re-install the signal handler (some systems need this) */
147 anjuta_children_recover ();
151 sigaddset(&set
, SIGCHLD
);
152 sigprocmask(SIG_UNBLOCK
, &set
, &oldset
);
156 * anjuta_children_recover:
158 * Recovers child management signaling.
161 anjuta_children_recover ()
163 signal(SIGCHLD
, anjuta_child_terminated
);
167 * anjuta_children_register:
168 * @pid: Process ID of the child (usually the value retured by fork or similar
170 * @ch_terminated: Callback function which will be called when this child
171 * exits. The callback should be defined as the
172 * type #AnjutaChildTerminatedCallback.
175 * Registers a child process with the manager. ch_terminated will be called
176 * when the child terminates. DO NOT use SIGCHLD directly, otherwise whole
177 * children management will fail.
180 anjuta_children_register (pid_t pid
,
181 AnjutaChildTerminatedCallback ch_terminated
,
184 /* Reinforce possible loss in signal callback */
185 anjuta_children_recover ();
189 registered_child_processes
=
190 g_list_append (registered_child_processes
, (int *) pid
);
191 registered_child_processes_cb
=
192 g_list_append (registered_child_processes_cb
, ch_terminated
);
193 registered_child_processes_cb_data
=
194 g_list_append (registered_child_processes_cb_data
, data
);
196 /* Start exit poll if not yet running */
198 /* Callback is notified in idle to ensure it is process in
199 * main loop. Otherwise a deadlock could occur if the SIGCHLD was
200 * received after a lock in mainloop and the callback tries to
201 * use mainloop again (e.g. adding/removing a idle/timeout function.
203 if (exit_poll_timeout
== 0)
205 DEBUG_PRINT ("Setting up child process monitor poll timer");
206 exit_poll_timeout
= g_timeout_add (EXIT_POLL_TIMEOUT
,
207 on_notify_child_exit
, NULL
);
212 * anjuta_children_unregister:
213 * @pid: Process ID of the child.
215 * Unregisters the child process (It should have been registred before with
216 * #anjuta_children_register() call). No child terminated callback will be
217 * executed for this child.
220 anjuta_children_unregister (pid_t pid
)
225 idx
= g_list_index (registered_child_processes
, (int *) pid
);
226 registered_child_processes
=
227 g_list_remove (registered_child_processes
, (int *) pid
);
229 ptr
= g_list_nth (registered_child_processes_cb
, idx
);
231 registered_child_processes_cb
=
232 g_list_delete_link (registered_child_processes_cb
, ptr
);
234 ptr
= g_list_nth (registered_child_processes_cb_data
, idx
);
236 registered_child_processes_cb_data
=
237 g_list_delete_link (registered_child_processes_cb_data
, ptr
);
241 * anjuta_children_foreach:
242 * @cb: Callback function.
245 * Calls the given callback function with the data for each child
246 * registered, that have not yet been terminated.
249 anjuta_children_foreach (GFunc cb
, gpointer data
)
251 g_list_foreach (registered_child_processes
, cb
, data
);
255 * anjuta_children_finalize:
257 * Shuts down the children management. Usually not required to call, if you
258 * you are anyway exiting the program.
261 anjuta_children_finalize()
263 signal(SIGCHLD
, SIG_DFL
);
264 if (exit_poll_timeout
)
265 g_source_remove (exit_poll_timeout
);
266 exit_poll_timeout
= 0;