On Fri, Jul 05, 2013 at 01:48:41PM +0100, Daniel P. Berrange wrote: > On Fri, Jul 05, 2013 at 07:16:03PM +0700, Alexey Dokuchaev wrote: > > [...] > > What I need to do, is first to reestablish new connection to newly run > > devd, and then g_io_channel_shutdown(...)/g_object_unref(oldsocket). > > IMHO the order you have here ought to be ok.
My thinking the reason for calling devd_init() first, then cleaning up is because it takes sertain time to devd to reappear and start serving again. In indication of this is a series of repeating failing connect() calls if perror()'ing them... But I might be wrong. > Can you send the code you currently have, so I can see the bigger > picture of how you now have it written. Sure, attached is the current version of entangle-device-manager.c. ./danfe
/* * Entangle: Tethered Camera Control & Capture * * Copyright (C) 2009-2012 Daniel P. Berrange * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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, see <http://www.gnu.org/licenses/>. * */ #include <config.h> #if defined(__FreeBSD__) #include <gio/gio.h> #include <gio/gunixsocketaddress.h> #include <glib.h> //#include <unistd.h> #else #define G_UDEV_API_IS_SUBJECT_TO_CHANGE #ifdef G_UDEV_API_IS_SUBJECT_TO_CHANGE #include <gudev/gudev.h> #endif #endif #include <string.h> #include <stdio.h> #include "entangle-debug.h" #include "entangle-device-manager.h" #define ENTANGLE_DEVICE_MANAGER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), ENTANGLE_TYPE_DEVICE_MANAGER, EntangleDeviceManagerPrivate)) struct _EntangleDeviceManagerPrivate { #if defined(__linux__) GUdevClient #elif defined(__FreeBSD__) GSocket #endif *ctx; }; G_DEFINE_TYPE(EntangleDeviceManager, entangle_device_manager, G_TYPE_OBJECT); static void entangle_device_manager_finalize (GObject *object) { EntangleDeviceManager *manager = ENTANGLE_DEVICE_MANAGER(object); EntangleDeviceManagerPrivate *priv = manager->priv; ENTANGLE_DEBUG("Finalize manager"); if (priv->ctx) g_object_unref(priv->ctx); G_OBJECT_CLASS (entangle_device_manager_parent_class)->finalize (object); } static void entangle_device_manager_class_init(EntangleDeviceManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = entangle_device_manager_finalize; g_signal_new("device-added", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(EntangleDeviceManagerClass, device_added), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_signal_new("device-removed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(EntangleDeviceManagerClass, device_removed), NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING); g_type_class_add_private(klass, sizeof(EntangleDeviceManagerPrivate)); } #if defined(__linux__) static void do_udev_event(GUdevClient *client G_GNUC_UNUSED, const char *action, GUdevDevice *dev, gpointer opaque) { EntangleDeviceManager *manager = opaque; const gchar *sysfs; const gchar *usbbus, *usbdev; const gchar *devtype; gchar *port; if (strcmp(action, "add") != 0 && strcmp(action, "remove") != 0) return; devtype = g_udev_device_get_devtype(dev); if ((devtype == NULL) || strcmp(devtype, "usb_device") != 0) return; sysfs = g_udev_device_get_sysfs_path(dev); usbbus = g_udev_device_get_property(dev, "BUSNUM"); usbdev = g_udev_device_get_property(dev, "DEVNUM"); if (sysfs == NULL || usbbus == NULL || usbdev == NULL) return; port = g_strdup_printf("usb:%s,%s", usbbus, usbdev); ENTANGLE_DEBUG("%s device '%s' '%s'", action, sysfs, port); if (strcmp(action, "add") == 0) { g_signal_emit_by_name(manager, "device-added", port); } else { g_signal_emit_by_name(manager, "device-removed", port); } g_free(port); } #elif defined(__FreeBSD__) static void devd_init(EntangleDeviceManager *manager); static gboolean do_devd_event(GIOChannel *source, GIOCondition condition, gpointer user_data) { EntangleDeviceManager *manager = user_data; char *event, *cutoff; gsize end; GIOStatus status; status = g_io_channel_read_line(source, &event, NULL, &end, NULL); switch (status) { case G_IO_STATUS_NORMAL: event[end] = '\0'; if (strncmp(event + 1, "ugen", 4)) break; if (!(cutoff = strchr(event + 5, ' '))) break; *cutoff = '\0'; if (*event == '+') { g_signal_emit_by_name(manager, "device-added", event + 1); } else if (*event == '-') { g_signal_emit_by_name(manager, "device-removed", event + 1); } g_free(event); break; case G_IO_STATUS_EOF: case G_IO_STATUS_AGAIN: /* * Apparently, devd(8) was reinited (perhaps restarted?). * Teardown previous connection and allocate new channel. */ if (manager->priv->ctx) { g_io_channel_shutdown(source, FALSE, NULL); g_object_unref(manager->priv->ctx); } devd_init(manager); return FALSE; case G_IO_STATUS_ERROR: default: /* XXX: what shall we do? */ break; } return TRUE; } static void devd_init(EntangleDeviceManager *manager) { EntangleDeviceManagerPrivate *priv = manager->priv; GSocketAddress *addr; GError *err = NULL; priv->ctx = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, 0, &err); if (priv->ctx == NULL) { ENTANGLE_DEBUG("g_socket_new: %s\n", err->message); g_error_free(err); return; } addr = g_unix_socket_address_new("/var/run/devd.pipe"); if (g_socket_connect(priv->ctx, addr, NULL, &err) == TRUE) { GIOChannel *channel = g_io_channel_unix_new(g_socket_get_fd(priv->ctx)); g_io_add_watch(channel, G_IO_IN, do_devd_event, manager); /* * We can reduce the refcount here so that when the watch is * removed, the channel will be destroyed. */ g_io_channel_unref(channel); } else { ENTANGLE_DEBUG("g_socket_connect: %s\n", err->message); g_error_free(err); g_object_unref(priv->ctx); priv->ctx = NULL; } } #endif EntangleDeviceManager *entangle_device_manager_new(void) { return ENTANGLE_DEVICE_MANAGER(g_object_new(ENTANGLE_TYPE_DEVICE_MANAGER, NULL)); } static void entangle_device_manager_init_devices(EntangleDeviceManager *manager) { EntangleDeviceManagerPrivate *priv = manager->priv; GList *devs, *tmp; #if defined(__linux__) const gchar *const subsys[] = { "usb/usb_device", NULL, }; ENTANGLE_DEBUG("Init udev"); priv->ctx = g_udev_client_new(subsys); g_signal_connect(priv->ctx, "uevent", G_CALLBACK(do_udev_event), manager); devs = g_udev_client_query_by_subsystem(priv->ctx, "usb"); tmp = devs; while (tmp) { GUdevDevice *dev = tmp->data; do_udev_event(priv->ctx, "add", dev, manager); g_object_unref(dev); tmp = tmp->next; } g_list_free(devs); #elif defined(__FreeBSD__) ENTANGLE_DEBUG("Init devd"); devd_init(manager); #endif } static void entangle_device_manager_init(EntangleDeviceManager *manager) { manager->priv = ENTANGLE_DEVICE_MANAGER_GET_PRIVATE(manager); entangle_device_manager_init_devices(manager); } /* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * indent-tabs-mode: nil * tab-width: 8 * End: */
_______________________________________________ Entangle-devel mailing list Entangle-devel@gna.org https://mail.gna.org/listinfo/entangle-devel