Skip to content

Commit

Permalink
Exclude the current thread when stopping the world if Instruments is …
Browse files Browse the repository at this point in the history
…attached

When Instruments is attached to profile memory usage, it injects liboainject.dylib into the target process. This replaces the default mmap/munmap with version that lock for statistics collection. This will result in deadlock within Mono when the GC stops the world to collect and attemps to mmap. There is an internal __OAExcludeMachThreadID method which adds/removes the passed in thread from the internal exclusion list and prevents Instruments from collecting statistics for that thread. We add the current thread to the exclusion list after we stop the world, then remove the current thread from the exclusion list when we resume.
  • Loading branch information
martinpotter committed Sep 11, 2018
1 parent bf9064c commit 3743e86
Showing 1 changed file with 103 additions and 0 deletions.
103 changes: 103 additions & 0 deletions mono/metadata/sgen-stw.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,94 @@
#include "utils/mono-threads.h"
#include "utils/mono-threads-debug.h"

#if defined (PLATFORM_MACOSX)

#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <pthread.h>

#if defined(__x86_64__)

#define MACH_HEADER_TYPE struct mach_header_64
#define NLIST_TYPE struct nlist_64
#define OFFSET_TYPE uint64_t

#elif (defined(i386) || defined(__i386__))

#define MACH_HEADER_TYPE struct mach_header
#define NLIST_TYPE struct nlist
#define OFFSET_TYPE uint32_t

#endif

const char *OAExcludeMachThreadID_function_name = "___OAExcludeMachThreadID";
static void (*OAExcludeMachThreadID) (pthread_t, int) = NULL;

static OFFSET_TYPE
offset_for_symbol (struct symtab_command *symtab, uint8_t *data, const char *symbol_name)
{
NLIST_TYPE *nlist = (NLIST_TYPE *)(data + symtab->symoff);
char *strtab = (char *) (data + symtab->stroff);

for (int i = 0; i < symtab->nsyms; ++i, nlist++) {
const char *name = nlist->n_un.n_strx ? strtab + nlist->n_un.n_strx : NULL;
if (name != NULL && strcmp(symbol_name, name) == 0) {
OFFSET_TYPE offset = nlist->n_value;
return offset;
}
}

return 0;
}

static void
mono_sgen_dylib_loaded (const struct mach_header *header, intptr_t slide)
{
Dl_info image_info;
int result = dladdr(header, &image_info);
if (result == 0)
return;

const char *image_name = image_info.dli_fname;
if (strstr(image_name, "liboainject.dylib") == NULL)
return;

struct load_command *cmd = (struct load_command*)((char *) header + sizeof(MACH_HEADER_TYPE));

for (int commandIndex = 0; commandIndex < header->ncmds; commandIndex++) {
if (cmd->cmd == LC_SYMTAB) {
OFFSET_TYPE offset = offset_for_symbol((struct symtab_command *) cmd, (uint8_t *) header, OAExcludeMachThreadID_function_name);
if (offset != 0) {
OAExcludeMachThreadID = (void (*)(pthread_t, int)) (slide + offset);
}

return;
}

cmd = (struct load_command *) ((char *) cmd + cmd->cmdsize);
}
}

static void
mono_sgen_dylib_unloaded (const struct mach_header *header, intptr_t slide)
{
Dl_info image_info;
int result = dladdr(header, &image_info);
if (result == 0)
return;

const char *image_name = image_info.dli_fname;
if (strstr(image_name, "liboainject.dylib") == NULL)
return;

OAExcludeMachThreadID = NULL;
}

#endif


#define TV_DECLARE SGEN_TV_DECLARE
#define TV_GETTIME SGEN_TV_GETTIME
#define TV_ELAPSED SGEN_TV_ELAPSED
Expand Down Expand Up @@ -133,12 +221,22 @@ sgen_client_stop_world (int generation)
sgen_memgov_collection_start (generation);
if (sgen_need_bridge_processing ())
sgen_bridge_reset_data ();

#if defined (PLATFORM_MACOSX)
if (OAExcludeMachThreadID != NULL)
OAExcludeMachThreadID(pthread_self(), 1);
#endif
}

/* LOCKING: assumes the GC lock is held */
void
sgen_client_restart_world (int generation, gint64 *stw_time)
{
#if defined (PLATFORM_MACOSX)
if (OAExcludeMachThreadID != NULL)
OAExcludeMachThreadID(pthread_self(), 0);
#endif

TV_DECLARE (end_sw);
TV_DECLARE (start_handshake);
unsigned long usec;
Expand Down Expand Up @@ -191,6 +289,11 @@ mono_sgen_init_stw (void)
{
mono_counters_register ("World stop", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &time_stop_world);
mono_counters_register ("World restart", MONO_COUNTER_GC | MONO_COUNTER_ULONG | MONO_COUNTER_TIME, &time_restart_world);

#if defined (PLATFORM_MACOSX)
_dyld_register_func_for_add_image (&mono_sgen_dylib_loaded);
_dyld_register_func_for_remove_image (&mono_sgen_dylib_unloaded);
#endif
}

/* Unified suspend code */
Expand Down

0 comments on commit 3743e86

Please sign in to comment.