2008-08-27 Dan Williams <dcbw@redhat.com>
Ensure zombie children get cleaned up. To get notifications when children die abnormally, g_spawn_async() requires G_SPAWN_DO_NOT_REAP_CHILD, but that requires calling waitpid() yourself if you've removed the child watch handler before the process has actually died, which NM needs to do in a few places. So ensure that everything uses G_SPAWN_DO_NOT_REAP_CHILD and also cleans up after the child when required. Should fix problems trying to activate mobile broadband connections after a previous failure. * src/dhcp-manager/nm-dhcp-dhclient.c src/dhcp-manager/nm-dhcp-dhcpcd.c - Use G_SPAWN_DO_NOT_REAP_CHILD * src/dhcp-manager/nm-dhcp-manager.c - (nm_dhcp_device_destroy): ensure child is cleaned up - (nm_dhcp_client_stop, nm_dhcp_manager_cancel_transaction_real): always block on child quitting, since the non-blocking functionality was never actually used * src/dnsmasq-manager/nm-dnsmasq-manager.c - (dm_watch_cb): child is already reaped here - (ensure_killed, nm_dnsmasq_manager_stop): block until child is dead * src/nm-device.c - (aipd_cleanup): block until child is dead * src/named-manager/nm-named-manager.c - (run_netconfig): don't use G_SPAWN_DO_NOT_REAP_CHILD if we aren't event bothering to watch the child * src/ppp-manager/nm-ppp-manager.c - (ppp_watch_cb): child is already reaped here - (ensure_killed, nm_ppp_manager_stop): block until child is dead * src/vpn-manager/nm-vpn-service.c - (vpn_service_watch_cb): child is already reaped here - (nm_vpn_service_daemon_exec): use G_SPAWN_DO_NOT_REAP_CHILD so that status of the child is actually tracked - (ensure_killed, finalize): block until child is dead git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4020 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
@@ -236,7 +236,7 @@ nm_dhcp_client_start (NMDHCPDevice *device, NMSettingIP4Config *s_ip4)
|
||||
unsigned long int tmp = strtoul (pid_contents, NULL, 10);
|
||||
|
||||
if (!((tmp == ULONG_MAX) && (errno == ERANGE)))
|
||||
nm_dhcp_client_stop (device->iface, (pid_t) tmp, TRUE);
|
||||
nm_dhcp_client_stop (device->iface, (pid_t) tmp);
|
||||
remove (device->pid_file);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ nm_dhcp_client_start (NMDHCPDevice *device, NMSettingIP4Config *s_ip4)
|
||||
g_ptr_array_add (dhclient_argv, (gpointer) device->iface);
|
||||
g_ptr_array_add (dhclient_argv, NULL);
|
||||
|
||||
if (!g_spawn_async (NULL, (char **) dhclient_argv->pdata, NULL, 0,
|
||||
if (!g_spawn_async (NULL, (char **) dhclient_argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
&dhclient_child_setup, NULL, &pid, &error)) {
|
||||
nm_warning ("dhclient failed to start. error: '%s'", error->message);
|
||||
g_error_free (error);
|
||||
|
@@ -83,7 +83,7 @@ nm_dhcp_client_start (NMDHCPDevice *device, NMSettingIP4Config *s_ip4)
|
||||
unsigned long int tmp = strtoul (pid_contents, NULL, 10);
|
||||
|
||||
if (!((tmp == ULONG_MAX) && (errno == ERANGE)))
|
||||
nm_dhcp_client_stop (device->iface, (pid_t) tmp, TRUE);
|
||||
nm_dhcp_client_stop (device->iface, (pid_t) tmp);
|
||||
remove (device->pid_file);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ nm_dhcp_client_start (NMDHCPDevice *device, NMSettingIP4Config *s_ip4)
|
||||
g_ptr_array_add (argv, (gpointer) device->iface);
|
||||
g_ptr_array_add (argv, NULL);
|
||||
|
||||
if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, 0,
|
||||
if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
&dhcpcd_child_setup, NULL, &pid, &error)) {
|
||||
nm_warning ("dhcpcd failed to start. error: '%s'", error->message);
|
||||
g_error_free (error);
|
||||
|
@@ -68,7 +68,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static NMDHCPManager *nm_dhcp_manager_new (void);
|
||||
|
||||
static void nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device, gboolean blocking);
|
||||
static void nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device);
|
||||
|
||||
NMDHCPManager *
|
||||
nm_dhcp_manager_get (void)
|
||||
@@ -171,6 +171,9 @@ nm_dhcp_device_destroy (NMDHCPDevice *device)
|
||||
nm_dhcp_device_timeout_cleanup (device);
|
||||
nm_dhcp_device_watch_cleanup (device);
|
||||
|
||||
if (device->pid)
|
||||
nm_dhcp_client_stop (device->iface, device->pid);
|
||||
|
||||
if (device->options)
|
||||
g_hash_table_destroy (device->options);
|
||||
|
||||
@@ -525,8 +528,6 @@ nm_dhcp_device_new (NMDHCPManager *manager, const char *iface)
|
||||
|
||||
device->manager = manager;
|
||||
|
||||
nm_dhcp_manager_cancel_transaction_real (device, FALSE);
|
||||
|
||||
/* Do this after the transaction cancel since that clears options out */
|
||||
device->options = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
@@ -590,7 +591,7 @@ nm_dhcp_manager_begin_transaction (NMDHCPManager *manager,
|
||||
|
||||
if (state_is_bound (device->state) || (device->state == DHC_START)) {
|
||||
/* Cancel any DHCP transaction already in progress */
|
||||
nm_dhcp_manager_cancel_transaction_real (device, TRUE);
|
||||
nm_dhcp_manager_cancel_transaction_real (device);
|
||||
}
|
||||
|
||||
nm_info ("Activation (%s) Beginning DHCP transaction.", iface);
|
||||
@@ -611,26 +612,26 @@ nm_dhcp_manager_begin_transaction (NMDHCPManager *manager,
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_client_stop (const char * iface,
|
||||
pid_t pid,
|
||||
gboolean blocking)
|
||||
nm_dhcp_client_stop (const char * iface, pid_t pid)
|
||||
{
|
||||
int i = 20; /* 4 seconds */
|
||||
int i = 15; /* 3 seconds */
|
||||
|
||||
/* Tell it to quit */
|
||||
/* Tell it to quit; maybe it wants to send out a RELEASE message */
|
||||
kill (pid, SIGTERM);
|
||||
|
||||
while (blocking && i-- > 0) {
|
||||
while (i-- > 0) {
|
||||
gint child_status;
|
||||
int ret;
|
||||
|
||||
ret = waitpid (pid, &child_status, WNOHANG);
|
||||
if (ret > 0) {
|
||||
if (ret > 0)
|
||||
break;
|
||||
} else if (ret == -1) {
|
||||
|
||||
if (ret == -1) {
|
||||
/* Child already exited */
|
||||
if (errno == ECHILD)
|
||||
break;
|
||||
/* Otherwise, force kill the process */
|
||||
/* Took too long; shoot it in the head */
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
@@ -640,16 +641,20 @@ nm_dhcp_client_stop (const char * iface,
|
||||
if (i <= 0) {
|
||||
nm_warning ("%s: dhcp client pid %d didn't exit, will kill it.", iface, pid);
|
||||
kill (pid, SIGKILL);
|
||||
|
||||
nm_debug ("waiting for dhcp client pid %d to exit", pid);
|
||||
waitpid (pid, NULL, 0);
|
||||
nm_debug ("dhcp client pid %d cleaned up", pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device, gboolean blocking)
|
||||
nm_dhcp_manager_cancel_transaction_real (NMDHCPDevice *device)
|
||||
{
|
||||
if (!device->pid)
|
||||
return;
|
||||
|
||||
nm_dhcp_client_stop (device->iface, device->pid, blocking);
|
||||
nm_dhcp_client_stop (device->iface, device->pid);
|
||||
|
||||
nm_info ("%s: canceled DHCP transaction, dhcp client pid %d",
|
||||
device->iface,
|
||||
@@ -705,7 +710,7 @@ nm_dhcp_manager_cancel_transaction (NMDHCPManager *manager,
|
||||
if (!device || !device->pid)
|
||||
return;
|
||||
|
||||
nm_dhcp_manager_cancel_transaction_real (device, TRUE);
|
||||
nm_dhcp_manager_cancel_transaction_real (device);
|
||||
}
|
||||
|
||||
|
||||
|
@@ -102,8 +102,6 @@ gboolean nm_dhcp_manager_set_dhcp4_config (NMDHCPManager *manager,
|
||||
gboolean nm_dhcp_manager_process_signal (NMDHCPManager *manager, DBusMessage *message);
|
||||
|
||||
gboolean nm_dhcp_client_start (NMDHCPDevice *device, NMSettingIP4Config *s_ip4);
|
||||
void nm_dhcp_client_stop (const char * iface,
|
||||
pid_t pid,
|
||||
gboolean blocking);
|
||||
void nm_dhcp_client_stop (const char *iface, pid_t pid);
|
||||
|
||||
#endif /* NM_DHCP_MANAGER_H */
|
||||
|
Reference in New Issue
Block a user