diff --git a/src/libsysprof/sysprof-address-layout.c b/src/libsysprof/sysprof-address-layout.c index ff92fe26..9cc3c564 100644 --- a/src/libsysprof/sysprof-address-layout.c +++ b/src/libsysprof/sysprof-address-layout.c @@ -28,6 +28,7 @@ struct _SysprofAddressLayout { GObject parent_instance; + GRWLock rwlock; GPtrArray *mmaps; guint mmaps_dirty : 1; }; @@ -73,6 +74,7 @@ sysprof_address_layout_finalize (GObject *object) SysprofAddressLayout *self = (SysprofAddressLayout *)object; g_clear_pointer (&self->mmaps, g_ptr_array_unref); + g_rw_lock_clear (&self->rwlock); G_OBJECT_CLASS (sysprof_address_layout_parent_class)->finalize (object); } @@ -88,6 +90,7 @@ sysprof_address_layout_class_init (SysprofAddressLayoutClass *klass) static void sysprof_address_layout_init (SysprofAddressLayout *self) { + g_rw_lock_init (&self->rwlock); self->mmaps = g_ptr_array_new_with_free_func (g_object_unref); } @@ -104,9 +107,13 @@ sysprof_address_layout_take (SysprofAddressLayout *self, g_return_if_fail (SYSPROF_IS_ADDRESS_LAYOUT (self)); g_return_if_fail (SYSPROF_IS_DOCUMENT_MMAP (map)); + g_rw_lock_writer_lock (&self->rwlock); + g_ptr_array_add (self->mmaps, map); self->mmaps_dirty = TRUE; + + g_rw_lock_writer_unlock (&self->rwlock); } static int @@ -195,26 +202,42 @@ sysprof_address_layout_lookup (SysprofAddressLayout *self, g_return_val_if_fail (SYSPROF_IS_ADDRESS_LAYOUT (self), NULL); - if (self->mmaps_dirty) + g_rw_lock_reader_lock (&self->rwlock); + + while (self->mmaps_dirty) { g_autoptr(EggBitset) dups = NULL; EggBitsetIter iter; - guint old_len = self->mmaps->len; guint i; - self->mmaps_dirty = FALSE; + g_rw_lock_reader_unlock (&self->rwlock); + g_rw_lock_writer_lock (&self->rwlock); - g_ptr_array_sort (self->mmaps, compare_mmaps); - dups = find_duplicates (self->mmaps); - - if (egg_bitset_iter_init_last (&iter, dups, &i)) + if (self->mmaps_dirty) { - do - g_ptr_array_remove_index (self->mmaps, i); - while (egg_bitset_iter_previous (&iter, &i)); + self->mmaps_dirty = FALSE; + + g_ptr_array_sort (self->mmaps, compare_mmaps); + dups = find_duplicates (self->mmaps); + + if (egg_bitset_iter_init_last (&iter, dups, &i)) + { + do + g_ptr_array_remove_index (self->mmaps, i); + while (egg_bitset_iter_previous (&iter, &i)); + } + + /* We can't be monitored when we're in this path as the + * application cannot have gotten access yet. Ignore + * any sort of items changes. + * + * g_list_model_items_changed (G_LIST_MODEL (self), + * 0, old_len, self->mmaps->len); + */ } - g_list_model_items_changed (G_LIST_MODEL (self), 0, old_len, self->mmaps->len); + g_rw_lock_writer_unlock (&self->rwlock); + g_rw_lock_reader_lock (&self->rwlock); } ret = bsearch (&address, @@ -223,5 +246,7 @@ sysprof_address_layout_lookup (SysprofAddressLayout *self, sizeof (gpointer), find_by_address); + g_rw_lock_reader_unlock (&self->rwlock); + return ret ? *ret : NULL; } diff --git a/src/libsysprof/sysprof-document-symbols.c b/src/libsysprof/sysprof-document-symbols.c index 2f8d1849..166e12a5 100644 --- a/src/libsysprof/sysprof-document-symbols.c +++ b/src/libsysprof/sysprof-document-symbols.c @@ -22,6 +22,8 @@ #include +#include + #include "sysprof-address-layout-private.h" #include "sysprof-document-private.h" #include "sysprof-document-symbols-private.h" @@ -70,6 +72,9 @@ typedef struct _Symbolize ProgressFunc progress_func; gpointer progress_data; GDestroyNotify progress_data_destroy; + guint n_partitions; + guint partition_seq; + guint progress; } Symbolize; static void @@ -140,41 +145,108 @@ add_traceable (SysprofDocumentSymbols *self, } } -static void -sysprof_document_symbols_worker (GTask *task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) +static DexFuture * +symbolize_fiber (gpointer user_data) { - static const struct { - const char *name; - guint value; - } context_switches[] = { - { "- - Hypervisor - -", SYSPROF_ADDRESS_CONTEXT_HYPERVISOR }, - { "- - Kernel - -", SYSPROF_ADDRESS_CONTEXT_KERNEL }, - { "- - User - -", SYSPROF_ADDRESS_CONTEXT_USER }, - { "- - Guest - -", SYSPROF_ADDRESS_CONTEXT_GUEST }, - { "- - Guest Kernel - -", SYSPROF_ADDRESS_CONTEXT_GUEST_KERNEL }, - { "- - Guest User - -", SYSPROF_ADDRESS_CONTEXT_GUEST_USER }, - }; - g_autoptr(GRefString) context_switch = g_ref_string_new_intern ("Context Switch"); - Symbolize *state = task_data; - EggBitsetIter iter; - EggBitset *bitset; - GListModel *model; - guint count = 0; - guint i; + Symbolize *state = user_data; + g_autoptr(GListModel) model = NULL; + guint partition; + guint count; + guint n_items; + guint max; - g_assert (source_object == NULL); - g_assert (G_IS_TASK (task)); - g_assert (!cancellable || G_IS_CANCELLABLE (cancellable)); g_assert (state != NULL); g_assert (SYSPROF_IS_DOCUMENT (state->document)); g_assert (SYSPROF_IS_SYMBOLIZER (state->symbolizer)); g_assert (SYSPROF_IS_DOCUMENT_SYMBOLS (state->symbols)); + g_assert (state->n_partitions > 1); - bitset = _sysprof_document_traceables (state->document); - model = G_LIST_MODEL (state->document); + if (SYSPROF_IS_NO_SYMBOLIZER (state->symbolizer)) + return dex_future_new_for_boolean (TRUE); + + model = sysprof_document_list_traceables (state->document); + n_items = g_list_model_get_n_items (model); + partition = g_atomic_int_add (&state->partition_seq, 1); + count = n_items / (state->n_partitions - 1); + max = MIN (n_items, (partition + 1) * count); + + for (guint i = count * partition; i < max; i++) + { + g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i); + int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); + SysprofProcessInfo *process_info = g_hash_table_lookup (state->pid_to_process_info, GINT_TO_POINTER (pid)); + + add_traceable (state->symbols, + state->strings, + process_info, + traceable, + state->symbolizer); + + if (g_atomic_int_add (&state->progress, 1) % 100 == 0) + { + if (state->progress_func) + state->progress_func (state->progress / (double)n_items, _("Symbolizing stack traces"), state->progress_data); + } + } + + return dex_future_new_for_boolean (TRUE); +} + +static DexFuture * +handle_symbolize_result (DexFuture *completed, + gpointer user_data) +{ + Symbolize *state = user_data; + + if (dex_future_get_status (completed) == DEX_FUTURE_STATUS_REJECTED) + return NULL; + + return dex_future_new_take_object (g_object_ref (state->symbols)); +} + +static const struct { + const char *name; + guint value; +} context_switches[] = { + { "- - Hypervisor - -", SYSPROF_ADDRESS_CONTEXT_HYPERVISOR }, + { "- - Kernel - -", SYSPROF_ADDRESS_CONTEXT_KERNEL }, + { "- - User - -", SYSPROF_ADDRESS_CONTEXT_USER }, + { "- - Guest - -", SYSPROF_ADDRESS_CONTEXT_GUEST }, + { "- - Guest Kernel - -", SYSPROF_ADDRESS_CONTEXT_GUEST_KERNEL }, + { "- - Guest User - -", SYSPROF_ADDRESS_CONTEXT_GUEST_USER }, +}; + +void +_sysprof_document_symbols_new (SysprofDocument *document, + SysprofStrings *strings, + SysprofSymbolizer *symbolizer, + GHashTable *pid_to_process_info, + ProgressFunc progress_func, + gpointer progress_data, + GDestroyNotify progress_data_destroy, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GRefString) context_switch = g_ref_string_new_intern ("Context Switch"); + g_autoptr(DexAsyncResult) result = NULL; + g_autoptr(GPtrArray) futures = NULL; + DexFuture *future; + Symbolize *state; + + g_return_if_fail (SYSPROF_IS_DOCUMENT (document)); + g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer)); + + state = g_new0 (Symbolize, 1); + state->document = g_object_ref (document); + state->symbolizer = g_object_ref (symbolizer); + state->symbols = g_object_new (SYSPROF_TYPE_DOCUMENT_SYMBOLS, NULL); + state->strings = sysprof_strings_ref (strings); + state->pid_to_process_info = g_hash_table_ref (pid_to_process_info); + state->progress_func = progress_func; + state->progress_data = progress_data; + state->progress_data_destroy = progress_data_destroy; + state->n_partitions = MAX (1, g_get_num_processors () / 2) + 1; /* Create static symbols for context switch use */ for (guint cs = 0; cs < G_N_ELEMENTS (context_switches); cs++) @@ -193,80 +265,36 @@ sysprof_document_symbols_worker (GTask *task, state->symbols->context_switches[context_switches[cs].value] = g_steal_pointer (&symbol); } - /* Walk through the available traceables which need symbols extracted */ - if (!SYSPROF_IS_NO_SYMBOLIZER (state->symbolizer) && - egg_bitset_iter_init_first (&iter, bitset, &i)) + futures = g_ptr_array_new_with_free_func (dex_unref); + + for (guint i = 0; i < state->n_partitions; i++) { - guint n_items = egg_bitset_get_size (bitset); + DexScheduler *scheduler = dex_thread_pool_scheduler_get_default (); - do - { - g_autoptr(SysprofDocumentTraceable) traceable = g_list_model_get_item (model, i); - int pid = sysprof_document_frame_get_pid (SYSPROF_DOCUMENT_FRAME (traceable)); - SysprofProcessInfo *process_info = g_hash_table_lookup (state->pid_to_process_info, GINT_TO_POINTER (pid)); - - add_traceable (state->symbols, - state->strings, - process_info, - traceable, - state->symbolizer); - - count++; - - if (state->progress_func != NULL && count % 100 == 0) - state->progress_func (count / (double)n_items, _("Symbolizing stack traces"), state->progress_data); - } - while (egg_bitset_iter_next (&iter, &i)); + g_ptr_array_add (futures, + dex_scheduler_spawn (scheduler, 0, + symbolize_fiber, + state, + NULL)); } - g_task_return_pointer (task, - g_object_ref (state->symbols), - g_object_unref); -} + future = dex_future_allv ((DexFuture **)futures->pdata, futures->len); + future = dex_future_finally (future, + handle_symbolize_result, + state, + (GDestroyNotify)symbolize_free); -void -_sysprof_document_symbols_new (SysprofDocument *document, - SysprofStrings *strings, - SysprofSymbolizer *symbolizer, - GHashTable *pid_to_process_info, - ProgressFunc progress_func, - gpointer progress_data, - GDestroyNotify progress_data_destroy, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_autoptr(GTask) task = NULL; - Symbolize *state; - - g_return_if_fail (SYSPROF_IS_DOCUMENT (document)); - g_return_if_fail (SYSPROF_IS_SYMBOLIZER (symbolizer)); - - state = g_new0 (Symbolize, 1); - state->document = g_object_ref (document); - state->symbolizer = g_object_ref (symbolizer); - state->symbols = g_object_new (SYSPROF_TYPE_DOCUMENT_SYMBOLS, NULL); - state->strings = sysprof_strings_ref (strings); - state->pid_to_process_info = g_hash_table_ref (pid_to_process_info); - state->progress_func = progress_func; - state->progress_data = progress_data; - state->progress_data_destroy = progress_data_destroy; - - task = g_task_new (NULL, cancellable, callback, user_data); - g_task_set_source_tag (task, _sysprof_document_symbols_new); - g_task_set_task_data (task, state, (GDestroyNotify)symbolize_free); - g_task_run_in_thread (task, sysprof_document_symbols_worker); + result = dex_async_result_new (NULL, cancellable, callback, user_data); + dex_async_result_await (result, future); } SysprofDocumentSymbols * _sysprof_document_symbols_new_finish (GAsyncResult *result, GError **error) { - g_return_val_if_fail (G_IS_TASK (result), NULL); - g_return_val_if_fail (g_task_is_valid (result, NULL), NULL); - g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == _sysprof_document_symbols_new, NULL); + g_return_val_if_fail (DEX_IS_ASYNC_RESULT (result), NULL); - return g_task_propagate_pointer (G_TASK (result), error); + return dex_async_result_propagate_pointer (DEX_ASYNC_RESULT (result), error); } /** diff --git a/src/libsysprof/sysprof-elf-loader-private.h b/src/libsysprof/sysprof-elf-loader-private.h index 363ca751..9e44f0d6 100644 --- a/src/libsysprof/sysprof-elf-loader-private.h +++ b/src/libsysprof/sysprof-elf-loader-private.h @@ -33,10 +33,10 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (SysprofElfLoader, sysprof_elf_loader, SYSPROF, ELF_LOADER, GObject) SysprofElfLoader *sysprof_elf_loader_new (void); -const char * const *sysprof_elf_loader_get_debug_dirs (SysprofElfLoader *self); +char **sysprof_elf_loader_dup_debug_dirs (SysprofElfLoader *self); void sysprof_elf_loader_set_debug_dirs (SysprofElfLoader *self, const char * const *debug_dirs); -const char * const *sysprof_elf_loader_get_external_debug_dirs (SysprofElfLoader *self); +char **sysprof_elf_loader_dup_external_debug_dirs (SysprofElfLoader *self); void sysprof_elf_loader_set_external_debug_dirs (SysprofElfLoader *self, const char * const *debug_dirs); SysprofElf *sysprof_elf_loader_load (SysprofElfLoader *self, diff --git a/src/libsysprof/sysprof-elf-loader.c b/src/libsysprof/sysprof-elf-loader.c index 31f02545..b56eb11c 100644 --- a/src/libsysprof/sysprof-elf-loader.c +++ b/src/libsysprof/sysprof-elf-loader.c @@ -32,6 +32,7 @@ struct _SysprofElfLoader { GObject parent_instance; + GRecMutex mutex; GHashTable *cache; char **debug_dirs; char **external_debug_dirs; @@ -71,6 +72,7 @@ sysprof_elf_loader_finalize (GObject *object) g_clear_pointer (&self->debug_dirs, g_strfreev); g_clear_pointer (&self->external_debug_dirs, g_strfreev); g_clear_pointer (&self->cache, g_hash_table_unref); + g_rec_mutex_clear (&self->mutex); G_OBJECT_CLASS (sysprof_elf_loader_parent_class)->finalize (object); } @@ -86,11 +88,11 @@ sysprof_elf_loader_get_property (GObject *object, switch (prop_id) { case PROP_DEBUG_DIRS: - g_value_set_boxed (value, sysprof_elf_loader_get_debug_dirs (self)); + g_value_take_boxed (value, sysprof_elf_loader_dup_debug_dirs (self)); break; case PROP_EXTERNAL_DEBUG_DIRS: - g_value_set_boxed (value, sysprof_elf_loader_get_external_debug_dirs (self)); + g_value_take_boxed (value, sysprof_elf_loader_dup_external_debug_dirs (self)); break; default: @@ -149,12 +151,13 @@ sysprof_elf_loader_class_init (SysprofElfLoaderClass *klass) static void sysprof_elf_loader_init (SysprofElfLoader *self) { + g_rec_mutex_init (&self->mutex); self->debug_dirs = g_strdupv ((char **)DEFAULT_DEBUG_DIRS); self->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _g_object_xunref); } /** - * sysprof_elf_loader_get_debug_dirs: + * sysprof_elf_loader_dup_debug_dirs: * @self: a #SysprofElfLoader * * Gets the #SysprofElfLoader:debug-dirs property. @@ -164,12 +167,18 @@ sysprof_elf_loader_init (SysprofElfLoader *self) * * Returns: (nullable): an array of debug directories, or %NULL */ -const char * const * -sysprof_elf_loader_get_debug_dirs (SysprofElfLoader *self) +char ** +sysprof_elf_loader_dup_debug_dirs (SysprofElfLoader *self) { + char **ret; + g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL); - return (const char * const *)self->debug_dirs; + g_rec_mutex_lock (&self->mutex); + ret = g_strdupv (self->debug_dirs); + g_rec_mutex_unlock (&self->mutex); + + return ret; } /** @@ -197,12 +206,14 @@ sysprof_elf_loader_set_debug_dirs (SysprofElfLoader *self, g_return_if_fail (SYSPROF_IS_ELF_LOADER (self)); g_return_if_fail (self->debug_dirs != NULL); + g_rec_mutex_lock (&self->mutex); if (sysprof_set_strv (&self->debug_dirs, debug_dirs)) g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG_DIRS]); + g_rec_mutex_unlock (&self->mutex); } /** - * sysprof_elf_loader_get_external_debug_dirs: + * sysprof_elf_loader_dup_external_debug_dirs: * @self: a #SysprofElfLoader * * Gets the #SysprofElfLoader:external-debug-dirs property. @@ -210,14 +221,20 @@ sysprof_elf_loader_set_debug_dirs (SysprofElfLoader *self, * See sysprof_elf_loader_set_external_debug_dirs() for how this * property is used to locate ELF files. * - * Returns: (nullable): an array of external debug directories, or %NULL + * Returns: (transfer full) (nullable): an array of external debug directories, or %NULL */ -const char * const * -sysprof_elf_loader_get_external_debug_dirs (SysprofElfLoader *self) +char ** +sysprof_elf_loader_dup_external_debug_dirs (SysprofElfLoader *self) { + char **ret; + g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL); - return (const char * const *)self->external_debug_dirs; + g_rec_mutex_lock (&self->mutex); + ret = g_strdupv (self->external_debug_dirs); + g_rec_mutex_lock (&self->mutex); + + return ret; } /** @@ -243,8 +260,10 @@ sysprof_elf_loader_set_external_debug_dirs (SysprofElfLoader *self, { g_return_if_fail (SYSPROF_IS_ELF_LOADER (self)); + g_rec_mutex_lock (&self->mutex); if (sysprof_set_strv (&self->external_debug_dirs, external_debug_dirs)) g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EXTERNAL_DEBUG_DIRS]); + g_rec_mutex_unlock (&self->mutex); } static char * @@ -414,6 +433,8 @@ sysprof_elf_loader_load (SysprofElfLoader *self, g_return_val_if_fail (SYSPROF_IS_ELF_LOADER (self), NULL); g_return_val_if_fail (!mount_namespace || SYSPROF_IS_MOUNT_NAMESPACE (mount_namespace), NULL); + g_rec_mutex_lock (&self->mutex); + /* We must translate the file into a number of paths that may possibly * locate the file in the case that there are overlays in the mount * namespace. Each of the paths could be in a lower overlay layer. @@ -453,7 +474,10 @@ sysprof_elf_loader_load (SysprofElfLoader *self, if (cached_elf != NULL) { if (sysprof_elf_matches (cached_elf, file_inode, build_id)) - return g_object_ref (cached_elf); + { + g_rec_mutex_unlock (&self->mutex); + return g_object_ref (cached_elf); + } } continue; @@ -486,10 +510,15 @@ sysprof_elf_loader_load (SysprofElfLoader *self, } if (elf != NULL) - return g_steal_pointer (&elf); + { + g_rec_mutex_unlock (&self->mutex); + return g_steal_pointer (&elf); + } } failure: + g_rec_mutex_unlock (&self->mutex); + g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, diff --git a/src/libsysprof/sysprof-elf-symbolizer.c b/src/libsysprof/sysprof-elf-symbolizer.c index d522cf38..a79832bc 100644 --- a/src/libsysprof/sysprof-elf-symbolizer.c +++ b/src/libsysprof/sysprof-elf-symbolizer.c @@ -199,11 +199,11 @@ sysprof_elf_symbolizer_get_property (GObject *object, switch (prop_id) { case PROP_DEBUG_DIRS: - g_value_set_boxed (value, sysprof_elf_symbolizer_get_debug_dirs (self)); + g_value_take_boxed (value, sysprof_elf_symbolizer_dup_debug_dirs (self)); break; case PROP_EXTERNAL_DEBUG_DIRS: - g_value_set_boxed (value, sysprof_elf_symbolizer_get_external_debug_dirs (self)); + g_value_take_boxed (value, sysprof_elf_symbolizer_dup_external_debug_dirs (self)); break; default: @@ -277,12 +277,12 @@ sysprof_elf_symbolizer_new (void) return g_object_new (SYSPROF_TYPE_ELF_SYMBOLIZER, NULL); } -const char * const * -sysprof_elf_symbolizer_get_debug_dirs (SysprofElfSymbolizer *self) +char ** +sysprof_elf_symbolizer_dup_debug_dirs (SysprofElfSymbolizer *self) { g_return_val_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self), NULL); - return sysprof_elf_loader_get_debug_dirs (self->loader); + return sysprof_elf_loader_dup_debug_dirs (self->loader); } void @@ -294,12 +294,12 @@ sysprof_elf_symbolizer_set_debug_dirs (SysprofElfSymbolizer *self, sysprof_elf_loader_set_debug_dirs (self->loader, debug_dirs); } -const char * const * -sysprof_elf_symbolizer_get_external_debug_dirs (SysprofElfSymbolizer *self) +char ** +sysprof_elf_symbolizer_dup_external_debug_dirs (SysprofElfSymbolizer *self) { g_return_val_if_fail (SYSPROF_IS_ELF_SYMBOLIZER (self), NULL); - return sysprof_elf_loader_get_external_debug_dirs (self->loader); + return sysprof_elf_loader_dup_external_debug_dirs (self->loader); } void diff --git a/src/libsysprof/sysprof-elf-symbolizer.h b/src/libsysprof/sysprof-elf-symbolizer.h index 7ea96e55..bbe5d7f5 100644 --- a/src/libsysprof/sysprof-elf-symbolizer.h +++ b/src/libsysprof/sysprof-elf-symbolizer.h @@ -37,12 +37,12 @@ GType sysprof_elf_symbolizer_get_type (void) G_GNUC SYSPROF_AVAILABLE_IN_ALL SysprofSymbolizer *sysprof_elf_symbolizer_new (void); SYSPROF_AVAILABLE_IN_ALL -const char * const *sysprof_elf_symbolizer_get_debug_dirs (SysprofElfSymbolizer *self); +char **sysprof_elf_symbolizer_dup_debug_dirs (SysprofElfSymbolizer *self); SYSPROF_AVAILABLE_IN_ALL void sysprof_elf_symbolizer_set_debug_dirs (SysprofElfSymbolizer *self, const char * const *debug_dirs); SYSPROF_AVAILABLE_IN_ALL -const char * const *sysprof_elf_symbolizer_get_external_debug_dirs (SysprofElfSymbolizer *self); +char **sysprof_elf_symbolizer_dup_external_debug_dirs (SysprofElfSymbolizer *self); SYSPROF_AVAILABLE_IN_ALL void sysprof_elf_symbolizer_set_external_debug_dirs (SysprofElfSymbolizer *self, const char * const *external_debug_dirs); diff --git a/src/libsysprof/sysprof-strings.c b/src/libsysprof/sysprof-strings.c index 421da461..3c9e635d 100644 --- a/src/libsysprof/sysprof-strings.c +++ b/src/libsysprof/sysprof-strings.c @@ -24,7 +24,7 @@ struct _SysprofStrings { - GMutex mutex; + GRWLock rwlock; GHashTable *hashtable; }; @@ -34,7 +34,7 @@ sysprof_strings_new (void) SysprofStrings *self; self = g_atomic_rc_box_new0 (SysprofStrings); - g_mutex_init (&self->mutex); + g_rw_lock_init (&self->rwlock); self->hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_ref_string_release, @@ -54,7 +54,7 @@ sysprof_strings_finalize (gpointer data) { SysprofStrings *self = data; - g_mutex_clear (&self->mutex); + g_rw_lock_clear (&self->rwlock); g_clear_pointer (&self->hashtable, g_hash_table_unref); } @@ -73,14 +73,24 @@ sysprof_strings_get (SysprofStrings *self, if (string == NULL) return NULL; - g_mutex_lock (&self->mutex); + g_rw_lock_reader_lock (&self->rwlock); if (!(ret = g_hash_table_lookup (self->hashtable, string))) { - ret = g_ref_string_new (string); - g_hash_table_insert (self->hashtable, ret, ret); - } - g_ref_string_acquire (ret); - g_mutex_unlock (&self->mutex); + g_rw_lock_reader_unlock (&self->rwlock); + g_rw_lock_writer_lock (&self->rwlock); - return ret; + /* Check again, now with write lock */ + if (!(ret = g_hash_table_lookup (self->hashtable, string))) + { + ret = g_ref_string_new (string); + g_hash_table_insert (self->hashtable, ret, ret); + } + + g_rw_lock_writer_unlock (&self->rwlock); + + return g_ref_string_acquire (ret); + } + g_rw_lock_reader_unlock (&self->rwlock); + + return g_ref_string_acquire (ret); }