From 76fb13178cf6be94b8e01675b37f7cb1b92f7709 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 22 Sep 2020 00:23:47 +0200
Subject: Defined lock mechanism for buffer caches.

---
 plugins/pychrysalide/glibext/buffercache.c | 134 ++++++++++++++++++++++++---
 src/analysis/binary.c                      |   4 +
 src/analysis/db/items/bookmark.c           |   4 +-
 src/analysis/db/items/comment.c            |  11 ++-
 src/analysis/db/items/switcher.c           |   4 +-
 src/analysis/disass/block.c                |   9 ++
 src/analysis/disass/disassembler.c         |   4 +
 src/analysis/disass/output.c               |   2 +-
 src/analysis/routine.c                     |   4 +
 src/arch/operands/target.c                 |   4 +
 src/glibext/buffercache-int.h              |   5 +-
 src/glibext/buffercache.c                  | 139 ++++++++++++++++++++---------
 src/glibext/buffercache.h                  |  34 ++++---
 src/glibext/bufferview.c                   | 110 ++++++++++++++---------
 src/gtkext/hexdisplay.c                    |   4 +
 src/gui/dialogs/export_disass.c            |   4 +-
 src/gui/dialogs/gotox.c                    |   4 +
 17 files changed, 360 insertions(+), 120 deletions(-)

diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c
index d3bee45..0cf3342 100644
--- a/plugins/pychrysalide/glibext/buffercache.c
+++ b/plugins/pychrysalide/glibext/buffercache.c
@@ -55,6 +55,12 @@ static int py_buffer_cache_init(PyObject *, PyObject *, PyObject *);
 /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */
 
 
+/* Met à disposition un encadrement des accès aux lignes. */
+static PyObject *py_buffer_cache_lock(PyObject *, PyObject *);
+
+/* Met à disposition un encadrement des accès aux lignes. */
+static PyObject *py_buffer_cache_unlock(PyObject *, PyObject *);
+
 /* Insère un générateur dans des lignes à une position donnée. */
 static PyObject *py_buffer_cache_insert_at(PyObject *, PyObject *);
 
@@ -243,6 +249,104 @@ static int py_buffer_cache_init(PyObject *self, PyObject *args, PyObject *kwds)
 *  Paramètres  : self = classe représentant un tampon de code.                *
 *                args = arguments fournis à l'appel.                          *
 *                                                                             *
+*  Description : Met à disposition un encadrement des accès aux lignes.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_buffer_cache_lock(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Trouvailles à retourner     */
+    int write;                              /* Type de verrou à poser      */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBufferCache *cache;                    /* Tampon natif à consulter    */
+
+#define BUFFER_CACHE_LOCK_METHOD PYTHON_METHOD_DEF                  \
+(                                                                   \
+    lock, "$self, /, write=False",                                  \
+    METH_VARARGS, py_buffer_cache,                                  \
+    "Lock for access the content of a buffer cache instance.\n"     \
+    "\n"                                                            \
+    "The *write* parameter is a boolean value which has to be set"  \
+    " if the access to perform will modify the buffer cache.\n"     \
+    "\n"                                                            \
+    "Each call of this method has to followed by a call to"         \
+    " pychrysalide.glibext.BufferCache.unlock(), with the same"     \
+    " *write* parameter."                                           \
+)
+
+    write = 0;
+
+    ret = PyArg_ParseTuple(args, "|p", &write);
+    if (!ret) return NULL;
+
+    cache = G_BUFFER_CACHE(pygobject_get(self));
+
+    g_buffer_cache_lock_unlock(cache, write, true);
+
+    result = Py_None;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant un tampon de code.                *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Met à disposition un encadrement des accès aux lignes.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_buffer_cache_unlock(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Trouvailles à retourner     */
+    int write;                              /* Type de verrou à poser      */
+    int ret;                                /* Bilan de lecture des args.  */
+    GBufferCache *cache;                    /* Tampon natif à consulter    */
+
+#define BUFFER_CACHE_UNLOCK_METHOD PYTHON_METHOD_DEF                \
+(                                                                   \
+    unlock, "$self, /, write=False",                                \
+    METH_VARARGS, py_buffer_cache,                                  \
+    "Unlock the content of a buffer cache instance.\n"              \
+    "\n"                                                            \
+    "The *write* parameter is a boolean value which has to be set"  \
+    " if the performed access has modified the buffer cache.\n"     \
+)
+
+    write = 0;
+
+    ret = PyArg_ParseTuple(args, "|p", &write);
+    if (!ret) return NULL;
+
+    cache = G_BUFFER_CACHE(pygobject_get(self));
+
+    g_buffer_cache_lock_unlock(cache, write, false);
+
+    result = Py_None;
+    Py_INCREF(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = classe représentant un tampon de code.                *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
 *  Description : Insère un générateur dans des lignes à une position donnée.  *
 *                                                                             *
 *  Retour      : -                                                            *
@@ -276,7 +380,7 @@ static PyObject *py_buffer_cache_insert_at(PyObject *self, PyObject *args)
     " extra pychrysalide.glibext.BufferLine.BufferLineFlags"        \
     " values.\n"                                                    \
     "\n"                                                            \
-    "An access lock has to be held for the cache; see the"          \
+    "An write access lock has to be held for the cache; see the"    \
     " pychrysalide.glibext.BufferCache.lock() function."            \
 )
 
@@ -326,7 +430,7 @@ static PyObject *py_buffer_cache_delete_at(PyObject *self, PyObject *args)
     METH_VARARGS, py_buffer_cache,                                      \
     "Delete the line at the *index* position from a buffer cache.\n"    \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An write access lock has to be held for the cache; see the"        \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -384,7 +488,7 @@ static PyObject *py_buffer_cache_delete_type_at(PyObject *self, PyObject *args)
     "The function returns the deleted generator as a"                       \
     " pychrysalide.glibext.LineGenerator instance, or None if none found.\n"\
     "\n"                                                                    \
-    "An access lock has to be held for the cache; see the"                  \
+    "An write access lock has to be held for the cache; see the"            \
     " pychrysalide.glibext.BufferCache.lock() function."                    \
 )
 
@@ -451,7 +555,7 @@ static PyObject *py_buffer_cache_append(PyObject *self, PyObject *args)
     " properties can be set for the line as extra"                  \
     " pychrysalide.glibext.BufferLine.BufferLineFlags values.\n"    \
     "\n"                                                            \
-    "An access lock has to be held for the cache; see the"          \
+    "An write access lock has to be held for the cache; see the"    \
     " pychrysalide.glibext.BufferCache.lock() function."            \
 )
 
@@ -504,9 +608,9 @@ static PyObject *py_buffer_cache_extend_with(PyObject *self, PyObject *args)
     " quantity, otherwise the call makes no sense. The generator"   \
     " is a pychrysalide.glibext.LineGenerator instance used to"     \
     " produce the extra new lines on demand."                       \
-    "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
-    " pychrysalide.glibext.BufferCache.lock() function."                \
+    "\n"                                                            \
+    "An write access lock has to be held for the cache; see the"    \
+    " pychrysalide.glibext.BufferCache.lock() function."            \
 )
 
     ret = PyArg_ParseTuple(args, "nO&", &count, convert_to_line_generator, &generator);
@@ -553,7 +657,7 @@ static PyObject *py_buffer_cache_truncate(PyObject *self, PyObject *args)
     "The *max* number should be lesser than the current line quantity," \
     " otherwise no effect will happen."                                 \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An write access lock has to be held for the cache; see the"        \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -603,7 +707,7 @@ static PyObject *py_buffer_cache_add_line_flag(PyObject *self, PyObject *args)
     "The *index* has to be a simple integer, and the *flag* a"      \
     " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n"     \
     "\n"                                                            \
-    "An access lock has to be held for the cache; see the"          \
+    "An write access lock has to be held for the cache; see the"    \
     " pychrysalide.glibext.BufferCache.lock() function."            \
 )
 
@@ -653,7 +757,7 @@ static PyObject *py_buffer_cache_get_line_flags(PyObject *self, PyObject *args)
     "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags"   \
     " value.\n"                                                         \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An read access lock has to be held for the cache; see the"         \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -702,7 +806,7 @@ static PyObject *py_buffer_cache_remove_line_flag(PyObject *self, PyObject *args
     "The *index* has to be a simple integer, and the *flag* a"          \
     " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n"         \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An write access lock has to be held for the cache; see the"        \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -751,7 +855,7 @@ static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *ar
     "The result is a pychrysalide.glibext.BufferLine instance or"       \
     " None.\n"                                                          \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An read access lock has to be held for the cache; see the"         \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -815,7 +919,7 @@ static PyObject *py_buffer_cache_look_for_flag(PyObject *self, PyObject *args)
     " or, if no match is found, the number of lines in the buffer"      \
     " cache.\n"                                                         \
     "\n"                                                                \
-    "An access lock has to be held for the cache; see the"              \
+    "An read access lock has to be held for the cache; see the"         \
     " pychrysalide.glibext.BufferCache.lock() function."                \
 )
 
@@ -1012,7 +1116,7 @@ static PyObject *py_buffer_cache_get_lines_count(PyObject *self, void *closure)
     lines_count, py_buffer_cache,                               \
     "Count the number of lines contained in a buffer cache.\n"  \
     "\n"                                                        \
-    "An access lock has to be held for the cache; see the"      \
+    "An read access lock has to be held for the cache; see the" \
     " pychrysalide.glibext.BufferCache.lock() function."        \
 )
 
@@ -1042,6 +1146,8 @@ static PyObject *py_buffer_cache_get_lines_count(PyObject *self, void *closure)
 PyTypeObject *get_python_buffer_cache_type(void)
 {
     static PyMethodDef py_buffer_cache_methods[] = {
+        BUFFER_CACHE_LOCK_METHOD,
+        BUFFER_CACHE_UNLOCK_METHOD,
         BUFFER_CACHE_INSERT_AT_METHOD,
         BUFFER_CACHE_DELETE_AT_METHOD,
         BUFFER_CACHE_DELETE_TYPE_AT_METHOD,
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 2eafda9..95d2133 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -1733,6 +1733,8 @@ static void on_binary_processor_changed(GArchProcessor *proc, GArchInstruction *
 
     if (binary->disass_cache != NULL)
     {
+        g_buffer_cache_wlock(binary->disass_cache);
+
         range = g_arch_instruction_get_range(instr);
 
         if (added)
@@ -1799,6 +1801,8 @@ static void on_binary_processor_changed(GArchProcessor *proc, GArchInstruction *
 
         }
 
+        g_buffer_cache_wunlock(binary->disass_cache);
+
     }
 
 }
diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c
index a3da5b3..0a64c89 100644
--- a/src/analysis/db/items/bookmark.c
+++ b/src/analysis/db/items/bookmark.c
@@ -537,7 +537,7 @@ static bool g_db_bookmark_run(GDbBookmark *bookmark, GLoadedBinary *binary, bool
     cache = g_loaded_binary_get_disassembly_cache(binary);
     if (cache == NULL) goto exit;
 
-    g_buffer_cache_lock(cache);
+    g_buffer_cache_wlock(cache);
 
     /* Recherche de la ligne concernée */
 
@@ -565,7 +565,7 @@ static bool g_db_bookmark_run(GDbBookmark *bookmark, GLoadedBinary *binary, bool
 
     /* Sortie */
 
-    g_buffer_cache_unlock(cache);
+    g_buffer_cache_wunlock(cache);
 
     g_object_unref(G_OBJECT(cache));
 
diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c
index 136b62b..bdff3a6 100644
--- a/src/analysis/db/items/comment.c
+++ b/src/analysis/db/items/comment.c
@@ -731,11 +731,12 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap
     const mrange_t *range;                  /* Emplacement d'instruction   */
     size_t linked;                          /* Indice lié à traiter        */
 
-    result = true;
+    result = false;
 
     cache = g_loaded_binary_get_disassembly_cache(binary);
+    if (cache == NULL) goto exit;
 
-    g_buffer_cache_lock(cache);
+    g_buffer_cache_wlock(cache)
 
     switch (comment->type)
     {
@@ -813,10 +814,14 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap
 
     }
 
-    g_buffer_cache_unlock(cache);
+    g_buffer_cache_wunlock(cache);
 
     g_object_unref(G_OBJECT(cache));
 
+    result = true;
+
+ exit:
+
     return result;
 
 }
diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c
index 3ae9358..090b8ce 100644
--- a/src/analysis/db/items/switcher.c
+++ b/src/analysis/db/items/switcher.c
@@ -611,7 +611,7 @@ static bool g_db_switcher_run(GDbSwitcher *switcher, GLoadedBinary *binary, ImmO
     cursor = g_binary_cursor_new();
     g_binary_cursor_update(G_BINARY_CURSOR(cursor), &switcher->addr);
 
-    g_buffer_cache_lock(cache);
+    g_buffer_cache_wlock(cache);
 
     index = g_buffer_cache_find_index_by_cursor(cache, cursor, true);
 
@@ -630,7 +630,7 @@ static bool g_db_switcher_run(GDbSwitcher *switcher, GLoadedBinary *binary, ImmO
 
  exit_gui:
 
-    g_buffer_cache_unlock(cache);
+    g_buffer_cache_wunlock(cache);
 
     g_object_unref(G_OBJECT(cache));
 
diff --git a/src/analysis/disass/block.c b/src/analysis/disass/block.c
index a141d68..ea1441f 100644
--- a/src/analysis/disass/block.c
+++ b/src/analysis/disass/block.c
@@ -574,12 +574,17 @@ static char *g_basic_block_build_tooltip(const GBasicBlock *block)
         if (label != NULL)
         {
             cache = g_buffer_cache_new(NULL, DLC_COUNT, DLC_ASSEMBLY_LABEL);
+
+            g_buffer_cache_wlock(cache);
+
             g_buffer_cache_append(cache, G_LINE_GENERATOR(symbol), BLF_NONE);
 
             line = g_buffer_cache_find_line_by_index(cache, 0);
             name = g_buffer_line_get_text(line, DLC_ASSEMBLY_LABEL, DLC_COUNT, true);
             g_object_unref(G_OBJECT(line));
 
+            g_buffer_cache_wunlock(cache);
+
             g_object_unref(G_OBJECT(cache));
 
             /* Suppression de la fin de l'étiquette... */
@@ -640,6 +645,8 @@ static char *g_basic_block_build_tooltip(const GBasicBlock *block)
     proc = g_loaded_binary_get_processor(block->binary);
     cache = g_loaded_binary_get_disassembly_cache(block->binary);
 
+    g_buffer_cache_rlock(cache);
+
     iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(&range));
     if (iter == NULL) goto no_iter;
 
@@ -789,6 +796,8 @@ static char *g_basic_block_build_tooltip(const GBasicBlock *block)
 
  no_iter:
 
+    g_buffer_cache_runlock(cache);
+
     g_object_unref(G_OBJECT(cache));
     g_object_unref(G_OBJECT(proc));
 
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 0b81180..4056c59 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -413,6 +413,8 @@ void output_disassembly(GLoadedBinary *binary, GProcContext *context, GtkStatusS
     g_width_tracker_set_column_min_width(tracker, DLC_ASSEMBLY_LABEL, offset);
     g_object_unref(G_OBJECT(tracker));
 
+    g_buffer_cache_wlock(*cache);
+
     /**
      * Impression du prologue.
      */
@@ -468,6 +470,8 @@ void output_disassembly(GLoadedBinary *binary, GProcContext *context, GtkStatusS
      * Nettoyage avant sortie.
      */
 
+    g_buffer_cache_wunlock(*cache);
+
     g_object_unref(G_OBJECT(lang));
     g_object_unref(G_OBJECT(content));
     g_object_unref(G_OBJECT(format));
diff --git a/src/analysis/disass/output.c b/src/analysis/disass/output.c
index f2e423c..ffff64a 100644
--- a/src/analysis/disass/output.c
+++ b/src/analysis/disass/output.c
@@ -324,7 +324,7 @@ void print_disassembled_instructions(GBufferCache *cache, GCodingLanguage *lang,
             if (compared >= 0)
             {
                 if (compared == 0)
-                    g_db_item_apply(G_DB_ITEM(comment), binary);
+                    /* FIXME *** g_db_item_apply(G_DB_ITEM(comment), binary) */;
 
                 else
                     log_variadic_message(LMT_BAD_BINARY,
diff --git a/src/analysis/routine.c b/src/analysis/routine.c
index aca47ee..422e7de 100644
--- a/src/analysis/routine.c
+++ b/src/analysis/routine.c
@@ -1105,6 +1105,8 @@ char *g_binary_routine_build_tooltip(const GBinRoutine *routine, const GLoadedBi
     proc = g_loaded_binary_get_processor(binary);
     cache = g_loaded_binary_get_disassembly_cache(binary);
 
+    g_buffer_cache_rlock(cache);
+
     /* Parcours des instructions */
 
     srange = g_binary_symbol_get_range(G_BIN_SYMBOL(routine));
@@ -1315,6 +1317,8 @@ char *g_binary_routine_build_tooltip(const GBinRoutine *routine, const GLoadedBi
 
  gbrbt_no_iter:
 
+    g_buffer_cache_runlock(cache);
+
     g_object_unref(G_OBJECT(cache));
     g_object_unref(G_OBJECT(proc));
 
diff --git a/src/arch/operands/target.c b/src/arch/operands/target.c
index 78a2fc1..2c75f1c 100644
--- a/src/arch/operands/target.c
+++ b/src/arch/operands/target.c
@@ -406,6 +406,8 @@ static char *g_target_operand_build_tooltip(const GTargetOperand *operand, const
 
                 cache = g_loaded_binary_get_disassembly_cache(binary);
 
+                g_buffer_cache_rlock(cache);
+
                 cursor = g_binary_cursor_new();
                 g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(srange));
 
@@ -423,6 +425,8 @@ static char *g_target_operand_build_tooltip(const GTargetOperand *operand, const
                     g_object_unref(G_OBJECT(line));
                 }
 
+                g_buffer_cache_runlock(cache);
+
                 g_object_unref(G_OBJECT(cache));
 
                 break;
diff --git a/src/glibext/buffercache-int.h b/src/glibext/buffercache-int.h
index 2ffa8ec..36e4369 100644
--- a/src/glibext/buffercache-int.h
+++ b/src/glibext/buffercache-int.h
@@ -68,11 +68,12 @@ struct _GBufferCache
 
     GBinContent *content;                   /* Contenu binaire global      */
 
+    GWidthTracker *tracker;                 /* Suivi des largeurs          */
+
     cache_info *lines;                      /* Liste des lignes intégrées  */
     size_t count;                           /* Quantité en cache           */
     size_t used;                            /* Quantité utilisée           */
-
-    GWidthTracker *tracker;                 /* Suivi des largeurs          */
+    GRWLock access;                         /* Verrou de protection        */
 
 };
 
diff --git a/src/glibext/buffercache.c b/src/glibext/buffercache.c
index 2913409..ebe8a7f 100644
--- a/src/glibext/buffercache.c
+++ b/src/glibext/buffercache.c
@@ -547,6 +547,7 @@ static void g_buffer_cache_init(GBufferCache *cache)
     cache->lines = NULL;
     cache->count = 0;
     cache->used = 0;
+    g_rw_lock_init(&cache->access);
 
     cache->tracker = NULL;
 
@@ -624,6 +625,8 @@ static void g_buffer_cache_finalize(GBufferCache *cache)
     if (cache->lines != NULL)
         free(cache->lines);
 
+    g_rw_lock_clear(&cache->access);
+
     G_OBJECT_CLASS(g_buffer_cache_parent_class)->finalize(G_OBJECT(cache));
 
 }
@@ -666,21 +669,24 @@ GBufferCache *g_buffer_cache_new(GBinContent *content, size_t col_count, size_t
 *                                                                             *
 *  Paramètres  : cache = tampon de lignes à consulter.                        *
 *                                                                             *
-*  Description : Fournit la hauteur d'impression d'une ligne visualisée.      *
+*  Description : Indique l'éventuel contenu binaire associé au cache.         *
 *                                                                             *
-*  Retour      : Hauteur de ligne en pixels.                                  *
+*  Retour      : Eventuel contenu renseigné ou NULL.                          *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-gint g_buffer_cache_get_line_height(const GBufferCache *cache)
+GBinContent *g_buffer_cache_get_content(const GBufferCache *cache)
 {
-    GBufferCacheClass *class;               /* Classe des tampons          */
+    GBinContent *result;                    /* Contenu à retourner         */
 
-    class = G_BUFFER_CACHE_GET_CLASS(cache);
+    result = cache->content;
 
-    return class->line_height;
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
+
+    return result;
 
 }
 
@@ -689,24 +695,21 @@ gint g_buffer_cache_get_line_height(const GBufferCache *cache)
 *                                                                             *
 *  Paramètres  : cache = tampon de lignes à consulter.                        *
 *                                                                             *
-*  Description : Indique l'éventuel contenu binaire associé au cache.         *
+*  Description : Fournit la hauteur d'impression d'une ligne visualisée.      *
 *                                                                             *
-*  Retour      : Eventuel contenu renseigné ou NULL.                          *
+*  Retour      : Hauteur de ligne en pixels.                                  *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBinContent *g_buffer_cache_get_content(const GBufferCache *cache)
+gint g_buffer_cache_get_line_height(const GBufferCache *cache)
 {
-    GBinContent *result;                    /* Contenu à retourner         */
-
-    result = cache->content;
+    GBufferCacheClass *class;               /* Classe des tampons          */
 
-    if (result != NULL)
-        g_object_ref(G_OBJECT(result));
+    class = G_BUFFER_CACHE_GET_CLASS(cache);
 
-    return result;
+    return class->line_height;
 
 }
 
@@ -759,44 +762,78 @@ gint g_buffer_cache_get_text_position(const GBufferCache *cache)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : cache = instance GLib à consulter.                           *
+*  Paramètres  : cache = composant GLib à consulter.                          *
 *                                                                             *
-*  Description : Compte le nombre de lignes rassemblées dans un tampon.       *
+*  Description : Fournit un lien vers la structure de suivi de largeurs.      *
 *                                                                             *
-*  Retour      : Nombre de lignes constituant le tampon.                      *
+*  Retour      : Gestionnaire de largeurs de lignes.                          *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-size_t g_buffer_cache_count_lines(const GBufferCache *cache)
+GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
 {
-    // TODO check lock
+    GWidthTracker *result;                  /* Instance à retourner    *   */
 
-    return cache->used;
+    result = cache->tracker;
+
+    g_object_ref(G_OBJECT(result));
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : cache = composant GLib à consulter.                          *
+*  Paramètres  : cache = cache de lignes à mettre à jour.                     *
+*                write = précise le type d'accès prévu (lecture/écriture).    *
+*                lock  = indique le sens du verrouillage à mener.             *
 *                                                                             *
-*  Description : Fournit un lien vers la structure de suivi de largeurs.      *
+*  Description : Met à disposition un encadrement des accès aux lignes.       *
 *                                                                             *
-*  Retour      : Gestionnaire de largeurs de lignes.                          *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
+void g_buffer_cache_lock_unlock(GBufferCache *cache, bool write, bool lock)
 {
-    GWidthTracker *result;                  /* Instance à retourner    *   */
+    if (write)
+    {
+        if (lock) g_rw_lock_writer_lock(&cache->access);
+        else g_rw_lock_writer_unlock(&cache->access);
+    }
+    else
+    {
+        if (lock) g_rw_lock_reader_lock(&cache->access);
+        else g_rw_lock_reader_unlock(&cache->access);
+    }
 
-    result = cache->tracker;
+}
 
-    g_object_ref(G_OBJECT(result));
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : cache = instance GLib à consulter.                           *
+*                                                                             *
+*  Description : Compte le nombre de lignes rassemblées dans un tampon.       *
+*                                                                             *
+*  Retour      : Nombre de lignes constituant le tampon.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_buffer_cache_count_lines(GBufferCache *cache)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
+    result = cache->used;
 
     return result;
 
@@ -878,6 +915,8 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator
     size_t needed;                          /* Emplacements nécessaires    */
     size_t i;                               /* Boucle de parcours          */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     assert(index < cache->used);
 
     assert(!(before && after));
@@ -1000,6 +1039,8 @@ void g_buffer_cache_delete_at(GBufferCache *cache, size_t index)
 {
     cache_info *info;                       /* Accès direct à une ligne    */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     assert(index < cache->used);
 
     info = &cache->lines[index];
@@ -1044,6 +1085,8 @@ GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *cache, size_t index,
     size_t count;                           /* Emplacements occupés        */
     size_t delete;                          /* Indice de suppression       */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     assert(index < cache->used);
 
     assert(!(before && after));
@@ -1165,6 +1208,8 @@ void g_buffer_cache_append(GBufferCache *cache, GLineGenerator *generator, Buffe
     size_t i;                               /* Boucle de parcours          */
     cache_info *info;                       /* Accès direct à une ligne    */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     count = g_line_generator_count_lines(generator);
 
     assert(count > 0);
@@ -1226,6 +1271,8 @@ void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerato
     cache_info *info;                       /* Accès direct à une ligne    */
     size_t added;                           /* Nombre d'ajouts effectués   */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     assert(count >= cache->used);
 
     if (count > cache->count)
@@ -1286,6 +1333,8 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max)
     size_t j;                               /* Boucle de parcours #2       */
     size_t removed;                         /* Nombre de retraits effectués*/
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     for (i = max; i < cache->used; i++)
     {
         info = &cache->lines[i];
@@ -1336,8 +1385,10 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max)
 *                                                                             *
 ******************************************************************************/
 
-void g_buffer_cache_get_line_cursor(const GBufferCache *cache, size_t index, gint x, GLineCursor **cursor)
+void g_buffer_cache_get_line_cursor(GBufferCache *cache, size_t index, gint x, GLineCursor **cursor)
 {
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     assert(index < cache->used);
 
     get_cache_info_cursor(&cache->lines[index], index, x, cursor);
@@ -1363,7 +1414,7 @@ void g_buffer_cache_add_line_flag(GBufferCache *cache, size_t index, BufferLineF
 {
     cache_info *info;                       /* Accès direct à une ligne    */
 
-    // TODO : check lock
+    assert(!g_rw_lock_writer_trylock(&cache->access));
 
     assert(index < cache->used);
 
@@ -1396,14 +1447,14 @@ void g_buffer_cache_add_line_flag(GBufferCache *cache, size_t index, BufferLineF
 *                                                                             *
 ******************************************************************************/
 
-BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *cache, size_t index)
+BufferLineFlags g_buffer_cache_get_line_flags(GBufferCache *cache, size_t index)
 {
     BufferLineFlags result;                 /* Somme à renvoyer            */
     cache_info *info;                       /* Accès direct à une ligne    */
     const generator_link *generator;        /* Générateur retenu           */
     size_t i;                               /* Boucle de parcours          */
 
-    // TODO : check lock
+    assert(!g_rw_lock_writer_trylock(&cache->access));
 
     assert(index < cache->used);
 
@@ -1447,7 +1498,7 @@ void g_buffer_cache_remove_line_flag(GBufferCache *cache, size_t index, BufferLi
 {
     cache_info *info;                       /* Accès direct à une ligne    */
 
-    // TODO : check lock
+    assert(!g_rw_lock_writer_trylock(&cache->access));
 
     assert(index < cache->used);
 
@@ -1484,7 +1535,7 @@ void g_buffer_cache_refresh_line(GBufferCache *cache, size_t index)
 {
     cache_info *info;                       /* Accès direct à une ligne    */
 
-    // TODO : check lock
+    assert(!g_rw_lock_writer_trylock(&cache->access));
 
     assert(index < cache->used);
 
@@ -1510,10 +1561,12 @@ void g_buffer_cache_refresh_line(GBufferCache *cache, size_t index)
 *                                                                             *
 ******************************************************************************/
 
-GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *cache, size_t index)
+GBufferLine *g_buffer_cache_find_line_by_index(GBufferCache *cache, size_t index)
 {
     GBufferLine *result;                    /* Ligne trouvée à retourner   */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     if (index < cache->used)
         result = get_cache_info_line(&cache->lines[index], cache->tracker, index, cache->content);
     else
@@ -1634,11 +1687,13 @@ void g_buffer_cache_draw(const GBufferCache *cache, cairo_t *cr, size_t first, s
 *                                                                             *
 ******************************************************************************/
 
-size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first, size_t start, size_t end)
+size_t _g_buffer_cache_find_index_by_cursor(GBufferCache *cache, const GLineCursor *cursor, bool first, size_t start, size_t end)
 {
     size_t result;                          /* Indice à retourner          */
     cache_info *found;                      /* Eventuel élément trouvé     */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     int find_containing_generator(const GLineCursor *c, const cache_info *i)
     {
         const generator_link *generator;    /* Générateur retenu           */
@@ -1707,10 +1762,12 @@ size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLi
 *                                                                             *
 ******************************************************************************/
 
-size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLineCursor *cursor, bool first)
+size_t g_buffer_cache_find_index_by_cursor(GBufferCache *cache, const GLineCursor *cursor, bool first)
 {
     size_t result;                          /* Indice à retourner          */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     if (cache->used == 0)
         result = 0;
     else
@@ -1735,7 +1792,7 @@ size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *cache, const GLin
 *                                                                             *
 ******************************************************************************/
 
-size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, BufferLineFlags flag)
+size_t g_buffer_cache_look_for_flag(GBufferCache *cache, size_t start, BufferLineFlags flag)
 {
     size_t result;                          /* Indice de ligne à retourner */
     GLineCursor *init;                      /* Localisation de départ      */
@@ -1743,7 +1800,7 @@ size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, Buf
     GLineCursor *next;                      /* Localisation suivante       */
     int ret;                                /* Bilan de comparaison        */
 
-    // TODO : check lock
+    assert(!g_rw_lock_writer_trylock(&cache->access));
 
     assert(start < cache->used);
 
@@ -1795,7 +1852,7 @@ size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, Buf
 *                                                                             *
 ******************************************************************************/
 
-bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *cache, const GLineCursor *cursor, size_t first, size_t last, bool code, gint *x, gint *y)
+bool g_buffer_cache_get_cursor_coordinates(GBufferCache *cache, const GLineCursor *cursor, size_t first, size_t last, bool code, gint *x, gint *y)
 {
     bool result;                            /* Bilan à retourner           */
     size_t index;                           /* Indice de correspondance    */
@@ -1803,6 +1860,8 @@ bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *cache, const GLin
     const cache_info *info;                 /* Infos sur une ligne donnée  */
     const generator_link *generator;        /* Générateur retenu           */
 
+    assert(!g_rw_lock_writer_trylock(&cache->access));
+
     index = _g_buffer_cache_find_index_by_cursor(cache, cursor, true, first, last);
 
     result = (index < cache->used);
diff --git a/src/glibext/buffercache.h b/src/glibext/buffercache.h
index f0f54b0..e657fff 100644
--- a/src/glibext/buffercache.h
+++ b/src/glibext/buffercache.h
@@ -72,12 +72,23 @@ gint g_buffer_cache_get_left_margin(const GBufferCache *);
 /* Fournit la position de départ pour l'impression de texte. */
 gint g_buffer_cache_get_text_position(const GBufferCache *);
 
-/* Compte le nombre de lignes rassemblées dans un tampon. */
-size_t g_buffer_cache_count_lines(const GBufferCache *);
-
 /* Fournit un lien vers la structure de suivi de largeurs. */
 GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *);
 
+/*  Met à disposition un encadrement des accès aux lignes. */
+void g_buffer_cache_lock_unlock(GBufferCache *, bool, bool);
+
+
+#define g_buffer_cache_wlock(cache) g_buffer_cache_lock_unlock(cache, true, true);
+#define g_buffer_cache_wunlock(cache) g_buffer_cache_lock_unlock(cache, true, false);
+
+#define g_buffer_cache_rlock(cache) g_buffer_cache_lock_unlock(cache, false, true);
+#define g_buffer_cache_runlock(cache) g_buffer_cache_lock_unlock(cache, false, false);
+
+
+/* Compte le nombre de lignes rassemblées dans un tampon. */
+size_t g_buffer_cache_count_lines(GBufferCache *);
+
 /* Insère un générateur dans des lignes à une position donnée. */
 void g_buffer_cache_insert_at(GBufferCache *, size_t, GLineGenerator *, BufferLineFlags, bool, bool);
 
@@ -97,13 +108,13 @@ void g_buffer_cache_extend_with(GBufferCache *, size_t, GLineGenerator *);
 void g_buffer_cache_truncate(GBufferCache *, size_t);
 
 /* Retrouve l'emplacement correspondant à une position de ligne. */
-void g_buffer_cache_get_line_cursor(const GBufferCache *, size_t, gint, GLineCursor **);
+void g_buffer_cache_get_line_cursor(GBufferCache *, size_t, gint, GLineCursor **);
 
 /* Ajoute une propriété particulière à une ligne. */
 void g_buffer_cache_add_line_flag(GBufferCache *, size_t, BufferLineFlags);
 
 /* Détermine l'ensemble des propriétés attachées à une ligne. */
-BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *, size_t);
+BufferLineFlags g_buffer_cache_get_line_flags(GBufferCache *, size_t);
 
 /* Retire une propriété particulière attachée à une ligne. */
 void g_buffer_cache_remove_line_flag(GBufferCache *, size_t, BufferLineFlags);
@@ -111,11 +122,8 @@ void g_buffer_cache_remove_line_flag(GBufferCache *, size_t, BufferLineFlags);
 /* Force la mise à jour du contenu d'une ligne donnée. */
 void g_buffer_cache_refresh_line(GBufferCache *, size_t);
 
-#define g_buffer_cache_lock(c)
-#define g_buffer_cache_unlock(c)
-
 /* Retrouve une ligne au sein d'un tampon avec un indice. */
-GBufferLine *g_buffer_cache_find_line_by_index(const GBufferCache *, size_t);
+GBufferLine *g_buffer_cache_find_line_by_index(GBufferCache *, size_t);
 
 /* Fait remonter les largeurs requises par une ligne donnée. */
 void g_buffer_cache_collect_widths(GBufferCache *, size_t, size_t, size_t, gint *, gint *);
@@ -124,16 +132,16 @@ void g_buffer_cache_collect_widths(GBufferCache *, size_t, size_t, size_t, gint
 void g_buffer_cache_draw(const GBufferCache *, cairo_t *, size_t, size_t, const cairo_rectangle_int_t *, const GDisplayOptions *, const gint *, const segcnt_list *);
 
 /* Indique l'indice correspondant à une adresse donnée. */
-size_t _g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool, size_t, size_t);
+size_t _g_buffer_cache_find_index_by_cursor(GBufferCache *, const GLineCursor *, bool, size_t, size_t);
 
 /* Indique l'indice correspondant à une adresse donnée. */
-size_t g_buffer_cache_find_index_by_cursor(const GBufferCache *, const GLineCursor *, bool);
+size_t g_buffer_cache_find_index_by_cursor(GBufferCache *, const GLineCursor *, bool);
 
 /* Avance autant que possible vers une ligne idéale. */
-size_t g_buffer_cache_look_for_flag(const GBufferCache *, size_t, BufferLineFlags);
+size_t g_buffer_cache_look_for_flag(GBufferCache *, size_t, BufferLineFlags);
 
 /* Indique la position d'affichage d'une adresse donnée. */
-bool g_buffer_cache_get_cursor_coordinates(const GBufferCache *, const GLineCursor *, size_t, size_t, bool, gint *, gint *);
+bool g_buffer_cache_get_cursor_coordinates(GBufferCache *, const GLineCursor *, size_t, size_t, bool, gint *, gint *);
 
 
 
diff --git a/src/glibext/bufferview.c b/src/glibext/bufferview.c
index 7ac6718..72740b1 100644
--- a/src/glibext/bufferview.c
+++ b/src/glibext/bufferview.c
@@ -81,13 +81,13 @@ static void on_buffer_cache_line_updated(const GBufferCache *, size_t, GBufferVi
 /* Calcule la position idéale de curseur pour un point donné. */
 static bool _g_buffer_view_compute_caret_full(GBufferView *, gint, GBufferLine *, size_t, const GDisplayOptions *, cairo_rectangle_int_t *, GLineCursor **);
 
+/* Fournit la ligne présente à une ordonnée donnée. */
+static GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *);
+
 /* Déplace le curseur au sein d'une vue de tampon. */
 static bool _g_buffer_view_move_caret(GBufferView *, const GBufferLine *, size_t, cairo_rectangle_int_t *, bool, GdkScrollDirection, const GDisplayOptions *);
 
 
-/* Fournit la ligne présente à une ordonnée donnée. */
-static GBufferLine *g_buffer_view_find_line_at(GBufferView *, gint, size_t *);
-
 
 
 
@@ -449,6 +449,8 @@ void g_buffer_view_restrict(GBufferView *view, GLineCursor *start, GLineCursor *
         if (view->tracker != NULL)
             g_object_unref(G_OBJECT(view->tracker));
 
+        g_buffer_cache_rlock(view->cache);
+
         if (view->unrestricted)
         {
             view->first = 0;
@@ -475,6 +477,8 @@ void g_buffer_view_restrict(GBufferView *view, GLineCursor *start, GLineCursor *
 
         }
 
+        g_buffer_cache_runlock(view->cache);
+
     }
 
 }
@@ -643,6 +647,8 @@ bool g_buffer_view_compute_caret_full(GBufferView *view, gint x, gint y, const G
 
     result = false;
 
+    g_buffer_cache_rlock(view->cache);
+
     /* Détermination de la ligne courante */
 
     lheight = g_buffer_cache_get_line_height(view->cache);
@@ -665,6 +671,8 @@ bool g_buffer_view_compute_caret_full(GBufferView *view, gint x, gint y, const G
 
  gbvccf_done:
 
+    g_buffer_cache_runlock(view->cache);
+
     return result;
 
 }
@@ -814,6 +822,48 @@ static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : view = visualisation à consulter.                            *
+*                y    = ordonnée comprise dans la ligne recherchée.           *
+*                idx  = indice de la ligne trouvée ou NULL. [OUT]             *
+*                                                                             *
+*  Description : Fournit la ligne présente à une ordonnée donnée.             *
+*                                                                             *
+*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx)
+{
+    GBufferLine *result;                    /* Ligne trouvée à retourner   */
+    gint lheight;                           /* Hauteur d'une ligne         */
+    size_t index;                           /* Indice attendu              */
+
+    /**
+     * Le verrou sur le tampon est déjà posé.
+     */
+
+    lheight = g_buffer_cache_get_line_height(view->cache);
+    index = y / lheight;
+
+    index += view->first;
+
+    if (index <= view->last)
+        result = g_buffer_cache_find_line_by_index(view->cache, index);
+    else
+        result = NULL;
+
+    if (result != NULL && idx != NULL)
+        *idx = index;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : view    = vue de tampon à mettre à jour.                     *
 *                ctrl    = indique la demande d'un parcours rapide.           *
 *                dir     = direction du parcours.                             *
@@ -842,6 +892,8 @@ bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection d
 
     result = false;
 
+    g_buffer_cache_rlock(view->cache);
+
     line = g_buffer_view_find_line_at(view, caret->y, &index);
     if (line == NULL) goto gbvmc_done;
 
@@ -945,6 +997,8 @@ bool g_buffer_view_move_caret(GBufferView *view, bool ctrl, GdkScrollDirection d
 
  gbvmc_done:
 
+    g_buffer_cache_runlock(view->cache);
+
     return result;
 
 }
@@ -981,6 +1035,8 @@ GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const GDi
 
     result = NULL;
 
+    g_buffer_cache_rlock(view->cache);
+
     /* Zone d'intervention bornée ! */
 
     text_pos = g_buffer_cache_get_text_position(view->cache);
@@ -1013,6 +1069,8 @@ GObject *g_buffer_view_find_creator(GBufferView *view, gint x, gint y, const GDi
 
  gbvfc_done:
 
+    g_buffer_cache_runlock(view->cache);
+
     return result;
 
 }
@@ -1080,6 +1138,8 @@ bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const G
 
     /* Zone d'intervention bornée ! */
 
+    g_buffer_cache_rlock(view->cache);
+
     text_pos = g_buffer_cache_get_text_position(view->cache);
 
     if (x < text_pos)
@@ -1121,6 +1181,8 @@ bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const G
 
  gbvhs_done:
 
+    g_buffer_cache_runlock(view->cache);
+
     return result;
 
 }
@@ -1209,44 +1271,6 @@ void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint virt_y, const
 
 
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : view = visualisation à consulter.                            *
-*                y    = ordonnée comprise dans la ligne recherchée.           *
-*                idx  = indice de la ligne trouvée ou NULL. [OUT]             *
-*                                                                             *
-*  Description : Fournit la ligne présente à une ordonnée donnée.             *
-*                                                                             *
-*  Retour      : Ligne retrouvée ou NULL si aucune.                           *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx)
-{
-    GBufferLine *result;                    /* Ligne trouvée à retourner   */
-    gint lheight;                           /* Hauteur d'une ligne         */
-    size_t index;                           /* Indice attendu              */
-
-    lheight = g_buffer_cache_get_line_height(view->cache);
-    index = y / lheight;
-
-    index += view->first;
-
-    if (index <= view->last)
-        result = g_buffer_cache_find_line_by_index(view->cache, index);
-    else
-        result = NULL;
-
-    if (result != NULL && idx != NULL)
-        *idx = index;
-
-    return result;
-
-}
-
-
 
 
 
@@ -1280,8 +1304,12 @@ bool g_buffer_view_get_cursor_coordinates(GBufferView *view, const GLineCursor *
 {
     bool result;                            /* Bilan à retourner           */
 
+    g_buffer_cache_rlock(view->cache);
+
     result = g_buffer_cache_get_cursor_coordinates(view->cache, cursor, view->first, view->last, code, x, y);
 
+    g_buffer_cache_runlock(view->cache);
+
     return result;
 
 }
diff --git a/src/gtkext/hexdisplay.c b/src/gtkext/hexdisplay.c
index ea662ae..49da03a 100644
--- a/src/gtkext/hexdisplay.c
+++ b/src/gtkext/hexdisplay.c
@@ -324,6 +324,8 @@ static void gtk_hex_display_populate_cache(GtkHexDisplay *display)
 
     /* Adaptation du tampon interne */
 
+    g_buffer_cache_wlock(display->cache);
+
     count = g_buffer_cache_count_lines(display->cache);
 
     if (needed < count)
@@ -332,6 +334,8 @@ static void gtk_hex_display_populate_cache(GtkHexDisplay *display)
     else if (needed > count)
         g_buffer_cache_extend_with(display->cache, needed, G_LINE_GENERATOR(display->generator));
 
+    g_buffer_cache_wunlock(display->cache);
+
     if (needed != count)
         gtk_widget_queue_resize(GTK_WIDGET(display));
 
diff --git a/src/gui/dialogs/export_disass.c b/src/gui/dialogs/export_disass.c
index 84ccc0a..12fc51f 100644
--- a/src/gui/dialogs/export_disass.c
+++ b/src/gui/dialogs/export_disass.c
@@ -389,7 +389,7 @@ static void start_binary_export(GBufferCache *cache, buffer_export_context *temp
 
     queue = get_work_queue();
 
-    g_buffer_cache_lock(cache);
+    g_buffer_cache_rlock(cache);
     count = g_buffer_cache_count_lines(cache);
 
     info->msg = gtk_status_stack_add_activity(get_global_status(), _("Exporting binary content..."), count);
@@ -463,7 +463,7 @@ static void on_binary_export_completed(GSeqWork *work, export_info_t *info)
 
     log_simple_message(LMT_INFO, "Binary content exported!");
 
-    g_buffer_cache_unlock(info->cache);
+    g_buffer_cache_runlock(info->cache);
     g_object_unref(G_OBJECT(info->cache));
 
     g_object_unref(G_OBJECT(info->options));
diff --git a/src/gui/dialogs/gotox.c b/src/gui/dialogs/gotox.c
index ec665c1..2179960 100644
--- a/src/gui/dialogs/gotox.c
+++ b/src/gui/dialogs/gotox.c
@@ -393,6 +393,8 @@ static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary,
 
     cache = g_loaded_binary_get_disassembly_cache(binary);
 
+    g_buffer_cache_rlock(cache);
+
     cursor = g_binary_cursor_new();
     g_binary_cursor_update(G_BINARY_CURSOR(cursor), addr);
 
@@ -404,6 +406,8 @@ static void add_new_location_to_list(GtkTreeStore *store, GLoadedBinary *binary,
 
     line = g_buffer_cache_find_line_by_index(cache, index);
 
+    g_buffer_cache_runlock(cache);
+
     g_object_unref(G_OBJECT(cache));
 
     /* Adresse en mémoire virtuelle */
-- 
cgit v0.11.2-87-g4458