* plugins/debug-manager/plugin.c:
[anjuta-git-plugin.git] / libanjuta / anjuta-children.c
blob50180122121d24b975b43a4b1e6fedf1d0e84c59
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-children.c
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.
21 /**
22 * SECTION:anjuta-children
23 * @title: Children management
24 * @short_description: Children management in Anjuta
25 * @see_also:
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
34 * signal.
36 * plugin developers should not bother about anjuta_children_init() and
37 * anjuta_children_finalize() functions. They are only for the shell
38 * implementor.
41 #include <signal.h>
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;
52 typedef struct {
53 int status;
54 pid_t pid;
55 } ExitNotifyData;
57 static gboolean
58 on_notify_child_exit (gpointer user_data)
60 gint idx;
61 int (*callback) (int st, gpointer d);
62 gpointer cb_data;
63 ExitNotifyData *idle_data; /* = (ExitNotifyData*) user_data; */
64 pid_t pid;
65 int status;
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;
72 return FALSE;
75 /* If nothing pending, wait for next poll */
76 if (pending_exit_notifies == NULL)
77 return TRUE;
79 idle_data = pending_exit_notifies->data;
80 pending_exit_notifies = g_list_remove_link (pending_exit_notifies,
81 pending_exit_notifies);
82 pid = idle_data->pid;
83 status = idle_data->status;
84 g_free (idle_data);
86 idx = g_list_index (registered_child_processes, (int *) pid);
87 if (idx < 0)
88 return TRUE; /* Continue polling */
90 callback =
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);
95 if (callback)
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;
104 return FALSE;
106 return TRUE; /* Otherwise continue polling */
109 static void
110 anjuta_child_terminated (int t)
112 gint idx;
113 int status;
114 pid_t pid;
115 sigset_t set, oldset;
117 /* block other incoming SIGCHLD signals */
118 sigemptyset(&set);
119 sigaddset(&set, SIGCHLD);
120 sigprocmask(SIG_BLOCK, &set, &oldset);
122 while (1)
124 ExitNotifyData *idle_data;
126 pid = waitpid (-1, &status, WNOHANG);
128 if (pid < 1)
129 return;
130 idx = g_list_index (registered_child_processes, (int *) pid);
131 if (idx < 0)
132 continue;
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
139 * context.
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,
144 idle_data);
146 /* re-install the signal handler (some systems need this) */
147 anjuta_children_recover ();
149 /* and unblock it */
150 sigemptyset(&set);
151 sigaddset(&set, SIGCHLD);
152 sigprocmask(SIG_UNBLOCK, &set, &oldset);
156 * anjuta_children_recover:
158 * Recovers child management signaling.
160 void
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
169 * system calls.
170 * @ch_terminated: Callback function which will be called when this child
171 * exits. The callback should be defined as the
172 * type #AnjutaChildTerminatedCallback.
173 * @data: User data.
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.
179 void
180 anjuta_children_register (pid_t pid,
181 AnjutaChildTerminatedCallback ch_terminated,
182 gpointer data)
184 /* Reinforce possible loss in signal callback */
185 anjuta_children_recover ();
187 if (pid < 1)
188 return;
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.
219 void
220 anjuta_children_unregister (pid_t pid)
222 gint idx;
223 GList *ptr;
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.
243 * @data: User data.
245 * Calls the given callback function with the data for each child
246 * registered, that have not yet been terminated.
248 void
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.
260 void
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;