Return-Path: From: Mikel Astiz To: linux-bluetooth@vger.kernel.org Cc: Mikel Astiz Subject: [RFC v0 05/11] device: Replace pending profile list with services Date: Tue, 19 Mar 2013 08:40:49 +0100 Message-Id: <1363678855-12765-6-git-send-email-mikel.astiz.oss@gmail.com> In-Reply-To: <1363678855-12765-1-git-send-email-mikel.astiz.oss@gmail.com> References: <1363678855-12765-1-git-send-email-mikel.astiz.oss@gmail.com> Sender: linux-bluetooth-owner@vger.kernel.org List-ID: From: Mikel Astiz Use btd_service pointers to represent the list of services pending for connection. This list doesn't reference count the btd_service instances, since the pending services should be a subset of the available services, and thus they should already be referenced by device->services. This means special care must be taken to make sure any removed service is also removed from the pending list, as addressed in service_remove(). --- src/device.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/device.c b/src/device.c index fa498d5..98f37a2 100644 --- a/src/device.c +++ b/src/device.c @@ -169,7 +169,7 @@ struct btd_device { GSList *uuids; GSList *primaries; /* List of primary services */ GSList *services; /* List of btd_service */ - GSList *pending; /* Pending profiles */ + GSList *pending; /* Pending services */ GSList *watches; /* List of disconnect_data */ gboolean temporary; guint disconn_timer; @@ -899,6 +899,7 @@ static void service_remove(struct btd_service *service) service_unavailable(service); profile->device_remove(profile, device); + device->pending = g_slist_remove(device->pending, service); btd_service_unref(service); } @@ -1081,29 +1082,32 @@ static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg, static int connect_next(struct btd_device *dev) { + struct btd_service *service; struct btd_profile *profile; int err = -ENOENT; while (dev->pending) { int err; - profile = dev->pending->data; + service = dev->pending->data; + profile = service_get_profile(service); + + if (service_get_state(service) != SERVICE_STATE_DISCONNECTED) { + dev->pending = g_slist_delete_link(dev->pending, + dev->pending); + continue; + } err = profile->connect(dev, profile); if (err == 0) { - GSList *l; - - l = g_slist_find_custom(dev->services, profile, - service_profile_cmp); - if (l != NULL) - service_connecting(l->data); - + service_connecting(service); return 0; } error("Failed to connect %s: %s", profile->name, strerror(-err)); - dev->pending = g_slist_remove(dev->pending, profile); + + dev->pending = g_slist_delete_link(dev->pending, dev->pending); } return err; @@ -1121,7 +1125,9 @@ void device_profile_connected(struct btd_device *dev, return; pending = dev->pending->data; - dev->pending = g_slist_remove(dev->pending, profile); + l = g_slist_find_custom(dev->pending, profile, service_profile_cmp); + if (l != NULL) + dev->pending = g_slist_delete_link(dev->pending, l); l = g_slist_find_custom(dev->services, profile, service_profile_cmp); if (l != NULL) @@ -1211,9 +1217,12 @@ static struct btd_service *find_connectable_service(struct btd_device *dev, return NULL; } -static gint profile_prio_cmp(gconstpointer a, gconstpointer b) +static gint service_prio_cmp(gconstpointer a, gconstpointer b) { - const struct btd_profile *p1 = a, *p2 = b; + struct btd_service *s1 = (gpointer) a; + struct btd_service *s2 = (gpointer) b; + struct btd_profile *p1 = service_get_profile(s1); + struct btd_profile *p2 = service_get_profile(s2); return p2->priority - p1->priority; } @@ -1246,8 +1255,7 @@ static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg, if (!service) return btd_error_invalid_args(msg); - p = service_get_profile(service); - dev->pending = g_slist_prepend(dev->pending, p); + dev->pending = g_slist_prepend(dev->pending, service); goto start_connect; } @@ -1259,14 +1267,14 @@ static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg, if (!p->auto_connect) continue; - if (g_slist_find(dev->pending, p)) + if (g_slist_find(dev->pending, service)) continue; if (service_get_state(service) != SERVICE_STATE_DISCONNECTED) continue; - dev->pending = g_slist_insert_sorted(dev->pending, p, - profile_prio_cmp); + dev->pending = g_slist_insert_sorted(dev->pending, service, + service_prio_cmp); } if (!dev->pending) @@ -2434,7 +2442,7 @@ void device_probe_profile(gpointer a, gpointer b) if (!profile->auto_connect || !device->general_connect) return; - device->pending = g_slist_append(device->pending, profile); + device->pending = g_slist_append(device->pending, service); if (g_slist_length(device->pending) == 1) connect_next(device); -- 1.8.1.4