Implement basic asynchronous LUC startup without error handling
authorJannis Pohlmann <jannis.pohlmann@codethink.co.uk>
Tue, 19 Jun 2012 08:57:30 +0000 (09:57 +0100)
committerJannis Pohlmann <jannis.pohlmann@codethink.co.uk>
Tue, 19 Jun 2012 13:40:53 +0000 (14:40 +0100)
This commit adds support for LUC startup to LUCStarter. It first
creates the parallel startup groups, then sorts their names according
to PRIORITISED_LUC_TYPES and then asynchronously processes group by
group, starting all apps in a group in parallel.

The implementation does not support cancellation nor error handling
at this point.

boot-manager/luc-starter.c
boot-manager/main.c

index 0ebb16d..ed5b357 100644 (file)
@@ -30,16 +30,27 @@ enum
 
 
 
-static void luc_starter_constructed  (GObject      *object);
-static void luc_starter_finalize     (GObject      *object);
-static void luc_starter_get_property (GObject      *object,
-                                      guint         prop_id,
-                                      GValue       *value,
-                                      GParamSpec   *pspec);
-static void luc_starter_set_property (GObject      *object,
-                                      guint         prop_id,
-                                      const GValue *value,
-                                      GParamSpec   *pspec);
+static void luc_starter_constructed       (GObject            *object);
+static void luc_starter_finalize          (GObject            *object);
+static void luc_starter_get_property      (GObject            *object,
+                                           guint               prop_id,
+                                           GValue             *value,
+                                           GParamSpec         *pspec);
+static void luc_starter_set_property      (GObject            *object,
+                                           guint               prop_id,
+                                           const GValue       *value,
+                                           GParamSpec         *pspec);
+static gint luc_starter_compare_luc_types (gconstpointer       a,
+                                           gconstpointer       b,
+                                           gpointer            user_data);
+static void luc_starter_start_next_group  (LUCStarter         *starter);
+static void luc_starter_start_app         (const gchar        *app,
+                                           LUCStarter         *starter);
+static void luc_starter_start_app_finish  (BootManagerService *service,
+                                           const gchar        *unit,
+                                           const gchar        *result,
+                                           GError             *error,
+                                           gpointer            user_data);
 
 
 
@@ -56,6 +67,9 @@ struct _LUCStarter
   LUCHandler         *luc_handler;
 
   gchar             **prioritised_types;
+
+  GList              *start_order;
+  GHashTable         *start_groups;
 };
 
 
@@ -183,6 +197,136 @@ luc_starter_set_property (GObject      *object,
 
 
 
+static gint
+luc_starter_compare_luc_types (gconstpointer a,
+                               gconstpointer b,
+                               gpointer      user_data)
+{
+  LUCStarter *starter = LUC_STARTER (user_data);
+  gchar      *type_a;
+  gchar      *type_b;
+  gint        n;
+  gint        pos_a = G_MAXINT;
+  gint        pos_b = G_MAXINT;
+
+  /* try to find the first type in the prioritised types list */
+  for (n = 0; pos_a < 0 && starter->prioritised_types[n] != NULL; n++)
+    if (g_strcmp0 (starter->prioritised_types[n], type_a) == 0)
+      pos_a = n;
+
+  /* try to find the second type in the prioritised types list */
+  for (n = 0; pos_b < 0 && starter->prioritised_types[n] != NULL; n++)
+    if (g_strcmp0 (starter->prioritised_types[n], type_b) == 0)
+      pos_b = n;
+
+  /* this statement has the following effect when sorting:
+   * - a and b are prioritised     -> prioritization order is preserved
+   * - a is prioritised, b isn't   -> negative return value, a comes first
+   * - b is prioritised, a isn't   -> positive return value, b comes first
+   * - neither a nor b prioritised -> return value is 0, arbitrary order
+   */
+  return pos_a - pos_b;
+}
+
+
+
+static void
+luc_starter_start_next_group (LUCStarter *starter)
+{
+  const gchar *group_name;
+  GPtrArray   *group;
+
+  g_return_if_fail (IS_LUC_STARTER (starter));
+  g_return_if_fail (starter->start_order != NULL);
+
+  group_name = starter->start_order->data;
+
+  g_debug ("start group '%s'", group_name);
+
+  /* look up the group with this name */
+  group = g_hash_table_lookup (starter->start_groups, group_name);
+  if (group != NULL)
+    {
+      /* launch all the applications in the group asynchronously */
+      g_ptr_array_foreach (group, (GFunc) luc_starter_start_app, starter);
+    }
+}
+
+
+
+static void
+luc_starter_start_app (const gchar *app,
+                       LUCStarter  *starter)
+{
+  g_return_if_fail (app != NULL && *app != '\0');
+  g_return_if_fail (IS_LUC_STARTER (starter));
+
+  g_debug ("start app '%s'", app);
+
+  boot_manager_service_start (starter->boot_manager, app, NULL,
+                              luc_starter_start_app_finish,
+                              starter);
+}
+
+
+
+static void
+luc_starter_start_app_finish (BootManagerService *service,
+                              const gchar        *unit,
+                              const gchar        *result,
+                              GError             *error,
+                              gpointer            user_data)
+{
+  const gchar *group_name;
+  LUCStarter  *starter = LUC_STARTER (user_data);
+  GPtrArray   *group;
+  gboolean     app_found = FALSE;
+  guint        n;
+
+  g_return_if_fail (BOOT_MANAGER_IS_SERVICE (service));
+  g_return_if_fail (unit != NULL && *unit != '\0');
+  g_return_if_fail (IS_LUC_STARTER (user_data));
+  g_return_if_fail (starter->start_order != NULL);
+
+  g_debug ("start app '%s' finish", unit);
+
+  /* get the current start group */
+  group_name = starter->start_order->data;
+
+  /* look up the apps for this group */
+  group = g_hash_table_lookup (starter->start_groups, group_name);
+  if (group != NULL)
+    {
+      /* try to find the current app in the group */
+      for (n = 0; !app_found && n < group->len; n++)
+        {
+          if (g_strcmp0 (unit, g_ptr_array_index (group, n)) == 0)
+            app_found = TRUE;
+        }
+
+      /* remove the app from the group */
+      if (app_found)
+        g_ptr_array_remove_index (group, n-1);
+
+      /* check if this was the last app in the group to be started */
+      if (group->len == 0)
+        {
+          g_debug ("start group %s finish", group_name);
+
+          /* remove the group from the groups and the order */
+          g_hash_table_remove (starter->start_groups, group_name);
+          starter->start_order = g_list_delete_link (starter->start_order,
+                                                     starter->start_order);
+
+          /* start the next group if there are any left */
+          if (starter->start_order != NULL)
+            luc_starter_start_next_group (starter);
+        }
+    }
+}
+
+
+
 LUCStarter *
 luc_starter_new (BootManagerService *boot_manager,
                  LUCHandler         *luc_handler)
@@ -201,10 +345,68 @@ luc_starter_new (BootManagerService *boot_manager,
 void
 luc_starter_start_groups (LUCStarter *starter)
 {
-  guint n;
-
-  g_debug ("start LUC types in the following order:");
-
+  GVariantIter iter;
+  GPtrArray   *group;
+  GVariant    *context;
+  GList       *lp;
+  gchar      **apps;
+  gchar       *type;
+  guint        n;
+
+  g_debug ("prioritised types:");
   for (n = 0; starter->prioritised_types[n] != NULL; n++)
     g_debug ("  %s",  starter->prioritised_types[n]);
+
+  /* clear the start order */
+  if (starter->start_order != NULL)
+    {
+      g_list_free (starter->start_order);
+      starter->start_order = NULL;
+    }
+
+  /* clear the start groups */
+  if (starter->start_groups != NULL)
+    {
+      g_hash_table_remove_all (starter->start_groups);
+    }
+  else
+    {
+      starter->start_groups = 
+        g_hash_table_new_full (g_str_hash, g_str_equal,
+                               g_free, (GDestroyNotify) g_ptr_array_free);
+    }
+
+  /* get the current last user context */
+  context = luc_handler_get_last_user_context (starter->luc_handler);
+  type = g_variant_print (context, TRUE);
+  g_debug ("context: %s", type);
+
+  /* create groups for all types in the LUC */
+  g_variant_iter_init (&iter, context);
+  while (g_variant_iter_loop (&iter, "{s^as}", &type, &apps))
+    {
+      group = g_ptr_array_new_with_free_func (g_free);
+
+      for (n = 0; apps != NULL && apps[n] != NULL; n++)
+        {
+          g_debug ("  group %s app %s", type, apps[n]);
+          g_ptr_array_add (group, g_strdup (apps[n]));
+        }
+
+      g_hash_table_insert (starter->start_groups, g_strdup (type), group);
+    }
+
+  /* generate the start order by sorting the LUC types according to
+   * the prioritised types */
+  starter->start_order = g_hash_table_get_keys (starter->start_groups);
+  starter->start_order = g_list_sort_with_data (starter->start_order,
+                                                luc_starter_compare_luc_types,
+                                                starter);
+
+  g_debug ("start groups (ordered):");
+  for (lp = starter->start_order; lp != NULL; lp = lp->next)
+    g_debug ("  %s", (gchar *)lp->data);
+
+  if (starter->start_order != NULL)
+    luc_starter_start_next_group (starter);
 }
index 723d23c..fba6152 100644 (file)
@@ -85,8 +85,8 @@ main (int    argc,
   luc_handler =
     luc_handler_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
                                         G_DBUS_PROXY_FLAGS_NONE,
-                                        "org.freedesktop.LUCHandler1",
-                                        "/org/freedesktop/LUCHandler1",
+                                        "org.genivi.LUCHandler1",
+                                        "/org/genivi/LUCHandler1",
                                         NULL, &error);
   if (luc_handler == NULL)
     {