From 76fb13178cf6be94b8e01675b37f7cb1b92f7709 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard 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