[ostree] sysroot: Add a try_lock() API



commit 2dfe24632a4d1d73ca5676b503135090f092db22
Author: Colin Walters <walters verbum org>
Date:   Wed May 6 22:19:05 2015 -0400

    sysroot: Add a try_lock() API
    
    The blocking locking API wasn't sufficient for use in the rpm-ostree
    daemon; it really wants to know if the lock is held, then continue to
    do other things (like service DBus requests), and get notification
    when the lock is available.
    
    We also add an async variant that can be called if the lock is not
    available.
    
    Implement a higher level "loop until lock is available" method in the
    `ostree admin` commandline.

 doc/ostree-sections.txt              |    3 +
 libglnx                              |    2 +-
 src/libostree/ostree-sysroot.c       |  107 ++++++++++++++++++++++++++++++++++
 src/libostree/ostree-sysroot.h       |   10 +++
 src/ostree/ot-admin-builtin-deploy.c |    2 +-
 src/ostree/ot-admin-functions.c      |   59 +++++++++++++++++++
 src/ostree/ot-admin-functions.h      |    4 +
 7 files changed, 185 insertions(+), 2 deletions(-)
---
diff --git a/doc/ostree-sections.txt b/doc/ostree-sections.txt
index b1b86f0..2cfc8fa 100644
--- a/doc/ostree-sections.txt
+++ b/doc/ostree-sections.txt
@@ -368,6 +368,9 @@ ostree_sysroot_new_default
 ostree_sysroot_get_path
 ostree_sysroot_load
 ostree_sysroot_lock
+ostree_sysroot_try_lock
+ostree_sysroot_lock_async
+ostree_sysroot_lock_finish
 ostree_sysroot_unlock
 ostree_sysroot_get_fd
 ostree_sysroot_ensure_initialized
diff --git a/libglnx b/libglnx
index cf8ae27..900b25f 160000
--- a/libglnx
+++ b/libglnx
@@ -1 +1 @@
-Subproject commit cf8ae27bab717621f1edf8ab6ae3dd89da4d8d4f
+Subproject commit 900b25f7018878ab64bd04751d8f15c6d83ba823
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index bdd6791..ebcb632 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -1171,6 +1171,55 @@ ostree_sysroot_lock (OstreeSysroot     *self,
 }
 
 /**
+ * ostree_sysroot_try_lock:
+ * @self: Self
+ * @out_acquired: (out): Whether or not the lock has been acquired
+ * @error: Error
+ *
+ * Try to acquire an exclusive multi-process write lock for @self.  If
+ * another process holds the lock, this function will return
+ * immediately, setting @out_acquired to %FALSE, and returning %TRUE
+ * (and no error).
+ *
+ * Release the lock with ostree_sysroot_unlock().  The lock will also
+ * be released if @self is deallocated.
+ */
+gboolean
+ostree_sysroot_try_lock (OstreeSysroot         *self,
+                         gboolean              *out_acquired,
+                         GError               **error)
+{
+  gboolean ret = FALSE;
+  GError *local_error = NULL;
+
+  if (!ensure_sysroot_fd (self, error))
+    goto out;
+
+  /* Note use of LOCK_NB */
+  if (!glnx_make_lock_file (self->sysroot_fd, OSTREE_SYSROOT_LOCKFILE,
+                            LOCK_EX | LOCK_NB, &self->lock, &local_error))
+    {
+      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+        {
+          *out_acquired = FALSE;
+        }
+      else
+        {
+          g_propagate_error (error, local_error);
+          goto out;
+        }
+    }
+  else
+    {
+      *out_acquired = TRUE;
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+/**
  * ostree_sysroot_unlock:
  * @self: Self
  *
@@ -1184,6 +1233,64 @@ ostree_sysroot_unlock (OstreeSysroot  *self)
   glnx_release_lock_file (&self->lock);
 }
 
+static void
+lock_in_thread (GTask            *task,
+                gpointer          source,
+                gpointer          task_data,
+                GCancellable     *cancellable)
+{
+  GError *local_error = NULL;
+  OstreeSysroot *self = source;
+
+  if (!ostree_sysroot_lock (self, &local_error))
+    goto out;
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, &local_error))
+    ostree_sysroot_unlock (self);
+  
+ out:
+  if (local_error)
+    g_task_return_error (task, local_error);
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+/**
+ * ostree_sysroot_lock_async:
+ * @self: Self
+ * @cancellable: Cancellable
+ * @callback: Callback
+ * @user_data: User data
+ * 
+ * An asynchronous version of ostree_sysroot_lock().
+ */
+void
+ostree_sysroot_lock_async (OstreeSysroot         *self,
+                           GCancellable          *cancellable,
+                           GAsyncReadyCallback    callback,
+                           gpointer               user_data)
+{
+  g_autoptr(GTask) task = g_task_new (self, cancellable, callback, user_data);
+  g_task_run_in_thread (task, lock_in_thread);
+}
+
+/**
+ * ostree_sysroot_lock_finish:
+ * @self: Self
+ * @result: Result
+ * @error: Error
+ * 
+ * Call when ostree_sysroot_lock_async() is ready.
+ */
+gboolean
+ostree_sysroot_lock_finish (OstreeSysroot         *self,
+                            GAsyncResult          *result,
+                            GError               **error)
+{
+  g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
+  return g_task_propagate_boolean ((GTask*)result, error);
+}
+
 /**
  * ostree_sysroot_simple_write_deployment:
  * @sysroot: Sysroot
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index e7f6e48..ce128bb 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -63,6 +63,16 @@ char *ostree_sysroot_get_deployment_dirpath (OstreeSysroot    *self,
 GFile * ostree_sysroot_get_deployment_origin_path (GFile   *deployment_path);
 
 gboolean ostree_sysroot_lock (OstreeSysroot  *self, GError **error);
+gboolean ostree_sysroot_try_lock (OstreeSysroot         *self,
+                                  gboolean              *out_acquired,
+                                  GError               **error);
+void     ostree_sysroot_lock_async (OstreeSysroot         *self,
+                                    GCancellable          *cancellable,
+                                    GAsyncReadyCallback    callback,
+                                    gpointer               user_data);
+gboolean ostree_sysroot_lock_finish (OstreeSysroot         *self,
+                                     GAsyncResult          *result,
+                                     GError               **error);
 void ostree_sysroot_unlock (OstreeSysroot  *self);
 
 gboolean ostree_sysroot_cleanup (OstreeSysroot       *self,
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index b18b3fd..78d60bb 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -79,7 +79,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro
 
   refspec = argv[1];
 
-  if (!ostree_sysroot_lock (sysroot, error))
+  if (!ot_admin_sysroot_lock (sysroot, error))
     goto out;
 
   if (!ostree_sysroot_load (sysroot, cancellable, error))
diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c
index a29d155..c818a00 100644
--- a/src/ostree/ot-admin-functions.c
+++ b/src/ostree/ot-admin-functions.c
@@ -96,3 +96,62 @@ ot_admin_get_indexed_deployment (OstreeSysroot  *sysroot,
   
   return g_object_ref (current_deployments->pdata[index]);
 }
+
+struct ContextState {
+  GMainContext *mainctx;
+  gboolean running;
+};
+
+static gboolean
+on_sysroot_lock_timeout (gpointer user_data)
+{
+  g_print ("Waiting for sysroot lock...\n");
+  return TRUE;
+}
+
+static void
+on_sysroot_lock_acquired (OstreeSysroot       *sysroot,
+                          GAsyncResult        *result,
+                          struct ContextState *state)
+{
+  state->running = FALSE;
+  g_main_context_wakeup (state->mainctx);
+}
+
+gboolean
+ot_admin_sysroot_lock (OstreeSysroot  *sysroot,
+                       GError        **error)
+{
+  gboolean ret = FALSE;
+  gboolean acquired;
+  struct ContextState state = {
+    .mainctx = g_main_context_new (),
+    .running = TRUE,
+  };
+
+  g_main_context_push_thread_default (state.mainctx);
+
+  if (!ostree_sysroot_try_lock (sysroot, &acquired, error))
+    goto out;
+
+  if (!acquired)
+    {
+      GSource *timeout_src = g_timeout_source_new_seconds (3);
+      g_source_set_callback (timeout_src, (GSourceFunc)on_sysroot_lock_timeout, &state, NULL);
+      g_source_attach (timeout_src, state.mainctx);
+      g_source_unref (timeout_src);
+      
+      on_sysroot_lock_timeout (&state);
+
+      ostree_sysroot_lock_async (sysroot, NULL, (GAsyncReadyCallback)on_sysroot_lock_acquired, &state);
+
+      while (state.running)
+        g_main_context_iteration (state.mainctx, TRUE);
+    }
+
+  ret = TRUE;
+ out:
+  g_main_context_pop_thread_default (state.mainctx);
+  g_main_context_unref (state.mainctx);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-functions.h b/src/ostree/ot-admin-functions.h
index 49b7039..67164ca 100644
--- a/src/ostree/ot-admin-functions.h
+++ b/src/ostree/ot-admin-functions.h
@@ -41,5 +41,9 @@ ot_admin_get_indexed_deployment (OstreeSysroot  *sysroot,
                                  int             index,
                                  GError        **error);
 
+gboolean
+ot_admin_sysroot_lock (OstreeSysroot  *sysroot,
+                       GError        **error);
+
 
 G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]