[gnome-builder] vcs: commit to various thread-safety requirements
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] vcs: commit to various thread-safety requirements
- Date: Sat, 14 Oct 2017 00:03:13 +0000 (UTC)
commit f70d52361d8dac6b6335e76039c618b4d1466722
Author: Christian Hergert <chergert redhat com>
Date: Fri Oct 13 16:35:16 2017 -0700
vcs: commit to various thread-safety requirements
We want to ensure that we have some thread-safety guarantees in
IdeVcs so that background workers can still check for ignored
status of files without round-tripping to the main thread.
src/libide/vcs/ide-vcs.c | 77 ++++++++++++++++++++++++++++++++++-----------
1 files changed, 58 insertions(+), 19 deletions(-)
---
diff --git a/src/libide/vcs/ide-vcs.c b/src/libide/vcs/ide-vcs.c
index fff1d5c..3636a6e 100644
--- a/src/libide/vcs/ide-vcs.c
+++ b/src/libide/vcs/ide-vcs.c
@@ -34,13 +34,16 @@ enum {
static guint signals [N_SIGNALS];
static GPtrArray *ignored;
+G_LOCK_DEFINE_STATIC (ignored);
+
void
ide_vcs_register_ignored (const gchar *pattern)
{
+ G_LOCK (ignored);
if (ignored == NULL)
ignored = g_ptr_array_new ();
-
g_ptr_array_add (ignored, g_pattern_spec_new (pattern));
+ G_UNLOCK (ignored);
}
static void
@@ -85,17 +88,20 @@ ide_vcs_default_init (IdeVcsInterface *iface)
/**
* ide_vcs_is_ignored:
* @self: An #IdeVcs
- * @file: A #GFile
+ * @file: (nullable): A #GFile
* @error: A location for a #GError, or %NULL
*
* This function will check if @file is considered an "ignored file" by
* the underlying Version Control System.
*
- * This function is not thread-safe, it must only be called from the
- * main thread.
+ * For convenience, this function will return %TRUE if @file is %NULL.
*
* Returns: %TRUE if the path should be ignored.
*
+ * Thread safety: This function is safe to call from a thread as
+ * #IdeVcs implementations are required to ensure this function
+ * is thread-safe.
+ *
* Since: 3.18
*/
gboolean
@@ -103,10 +109,15 @@ ide_vcs_is_ignored (IdeVcs *self,
GFile *file,
GError **error)
{
+ gboolean ret = FALSE;
+
g_return_val_if_fail (IDE_IS_VCS (self), FALSE);
- /* FIXME: Find threaded callers of this function, or
- * make this function require thread-safety.
- */
+ g_return_val_if_fail (!file || G_IS_FILE (file), FALSE);
+
+ if (file == NULL)
+ return TRUE;
+
+ G_LOCK (ignored);
if G_LIKELY (ignored != NULL)
{
@@ -119,20 +130,25 @@ ide_vcs_is_ignored (IdeVcs *self,
GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
if (g_pattern_match (pattern_spec, len, name, reversed))
- return TRUE;
+ {
+ ret = TRUE;
+ break;
+ }
}
}
- if (IDE_VCS_GET_IFACE (self)->is_ignored)
- return IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
+ G_UNLOCK (ignored);
+
+ if (!ret && IDE_VCS_GET_IFACE (self)->is_ignored)
+ ret = IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
- return FALSE;
+ return ret;
}
/**
* ide_vcs_path_is_ignored:
* @self: An #IdeVcs
- * @path: The path to check
+ * @path: (nullable): The path to check
* @error: A location for a #GError, or %NULL
*
* This function acts like ide_vcs_is_ignored() except that it
@@ -141,11 +157,14 @@ ide_vcs_is_ignored (IdeVcs *self,
* It will check if the path is absolute or relative to the project
* directory and adjust as necessary.
*
- * This function is not thread-safe, it must only be called from the
- * main thread.
+ * For convenience, this function will return %TRUE if @path is %NULL.
*
* Returns: %TRUE if the path should be ignored.
*
+ * Thread safety: This function is safe to call from a thread as
+ * #IdeVcs implementations are required to ensure this function
+ * is thread-safe.
+ *
* Since: 3.28
*/
gboolean
@@ -153,8 +172,14 @@ ide_vcs_path_is_ignored (IdeVcs *self,
const gchar *path,
GError **error)
{
+ gboolean ret = FALSE;
+
g_return_val_if_fail (IDE_IS_VCS (self), FALSE);
- g_return_val_if_fail (path != NULL, FALSE);
+
+ if (path == NULL)
+ return TRUE;
+
+ G_LOCK (ignored);
if G_LIKELY (ignored != NULL)
{
@@ -167,11 +192,16 @@ ide_vcs_path_is_ignored (IdeVcs *self,
GPatternSpec *pattern_spec = g_ptr_array_index (ignored, i);
if (g_pattern_match (pattern_spec, len, name, reversed))
- return TRUE;
+ {
+ ret = TRUE;
+ break;
+ }
}
}
- if (IDE_VCS_GET_IFACE (self)->is_ignored)
+ G_UNLOCK (ignored);
+
+ if (!ret && IDE_VCS_GET_IFACE (self)->is_ignored)
{
g_autoptr(GFile) file = NULL;
@@ -180,10 +210,10 @@ ide_vcs_path_is_ignored (IdeVcs *self,
else
file = g_file_get_child (ide_vcs_get_working_directory (self), path);
- return IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
+ ret = IDE_VCS_GET_IFACE (self)->is_ignored (self, file, error);
}
- return FALSE;
+ return ret;
}
gint
@@ -206,7 +236,16 @@ ide_vcs_get_priority (IdeVcs *self)
* Retrieves the working directory for the context. This is the root of where
* the project files exist.
*
+ * This function is safe to call from threads holding a reference to @self.
+ *
* Returns: (transfer none): A #GFile.
+ *
+ * Since: 3.18
+ *
+ * Thread safety: this function is safe to call from threads. The working
+ * directory should only be set at creating and therefore safe to call
+ * at any time from any thread that holds a reference to @self. Those
+ * implementing #IdeVcs are required to ensure this invariant holds true.
*/
GFile *
ide_vcs_get_working_directory (IdeVcs *self)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]