mirror of
https://github.com/varun-r-mallya/sysprof.git
synced 2025-12-31 20:36:25 +00:00
libsysprof: parallelize capture symbolizing
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include <libdex.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user