Merge pull request #2734 from nealef/master
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Mon, 6 Jun 2016 16:00:47 +0000 (12:00 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Mon, 6 Jun 2016 16:00:47 +0000 (12:00 -0400)
Enhance log tracing

1  2 
man/mono.1
mono/sgen/sgen-gc.h
mono/utils/mono-threads.c

diff --combined man/mono.1
index e2eff1620e7697a20a9d28a36db3a4e0eaf6479d,a1d668dbf39c2b011832032be65ba593336d0c61..7bd449dd4559c7c9d8e1ca61432ef8a5b0340577
@@@ -7,7 -7,7 +7,7 @@@
  .\" Author:
  .\"   Miguel de Icaza (miguel@gnu.org)
  .\"
 -.TH Mono "Mono 3.0"
 +.TH Mono "Mono 4.5.2"
  .SH NAME
  mono \- Mono's ECMA-CLI native code generator (Just-in-Time and Ahead-of-Time)
  .SH SYNOPSIS
@@@ -1094,6 -1094,11 +1094,6 @@@ find spots that need to be tuned for th
  this mode can be enabled at compile time by using the --with-cooperative-gc
  flag when calling configure.
  .TP
 -\fBMONO_ENABLE_SHM\fR
 -Unix only: Enable support for cross-process handles.  Cross-process
 -handles are used to expose process handles, thread handles, named
 -mutexes, named events and named semaphores across Unix processes.
 -.TP
  \fBMONO_ENV_OPTIONS\fR
  This environment variable allows you to pass command line arguments to
  a Mono process through the environment.   This is useful for example
@@@ -1508,6 -1513,24 +1508,6 @@@ For a complete description of recommend
  deployment, see
  http://www.mono-project.com/docs/getting-started/application-deployment/
  .TP
 -\fBMONO_RTC\fR
 -Experimental RTC support in the statistical profiler: if the user has
 -the permission, more accurate statistics are gathered.  The MONO_RTC
 -value must be restricted to what the Linux rtc allows: power of two
 -from 64 to 8192 Hz. To enable higher frequencies like 4096 Hz, run as root:
 -.nf
 -
 -      echo 4096 > /proc/sys/dev/rtc/max-user-freq
 -
 -.fi
 -.Sp
 -For example:
 -.nf
 -
 -      MONO_RTC=4096 mono --profiler=default:stat program.exe
 -
 -.fi
 -.TP 
  \fBMONO_SHARED_DIR\fR
  If set its the directory where the ".wapi" handle state is stored.
  This is the directory where the Windows I/O Emulation layer stores its
@@@ -1615,10 -1638,6 +1615,10 @@@ option
  When this option is set, the runtime will invalidate the domain memory
  pool instead of destroying it.
  .TP
 +\fBdisable_omit_fp\fR
 +Disables a compiler optimization where the frame pointer is omitted
 +from the stack. This optimization can interact badly with debuggers.
 +.TP
  \fBdont-free-domains\fR
  This is an Optimization for multi-AppDomain applications (most
  commonly ASP.NET applications).  Due to internal limitations Mono,
@@@ -1732,6 -1751,16 +1732,16 @@@ messages for a certain component. You c
  separating them. For example to see config file messages and assembly loader
  messages set you mask to "asm,cfg".
  .TP
+ \fBMONO_LOG_DEST\fR
+ Controls where trace log messages are written. If not set then the messages go to stdout. 
+ If set, the string either specifies a path to a file that will have messages appended to
+ it, or the string "syslog" in which case the messages will be written to the system log.
+ Under Windows, this is simulated by writing to a file called "mono.log". 
+ \fBMONO_LOG_HEADER\fR
+ Controls whether trace log messages not directed to syslog have the id, timestamp, and
+ pid as the prefix to the log message. To enable a header this environment variable need
+ just be non-null. 
+ .TP
  \fBMONO_TRACE\fR
  Used for runtime tracing of method calls. The format of the comma separated
  trace options is:
@@@ -1786,10 -1815,6 +1796,10 @@@ Enables the maximum JIT verbosity for t
  very helpfull to diagnose a miscompilation problems of a specific
  method.
  .TP
 +\fBMONO_JIT_DUMP_METHOD\fR
 +Enables sending of the JITs intermediate representation for a specified
 +method to the IdealGraphVisualizer tool.
 +.TP
  \fBMONO_VERBOSE_HWCAP\fR
  If set, makes the JIT output information about detected CPU features
  (such as SSE, CMOV, FCMOV, etc) to stdout.
diff --combined mono/sgen/sgen-gc.h
index 3a86cc44f5f9bd077365a6525a26fc1f1735c373,9477efb8cd018eaffb838b56e07e6dc75ab0cc2b..3f61780452162b286a6056be27a731aa4e8575ff
@@@ -6,7 -6,18 +6,7 @@@
   * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
   * Copyright (C) 2012 Xamarin Inc
   *
 - * This library is free software; you can redistribute it and/or
 - * modify it under the terms of the GNU Library General Public
 - * License 2.0 as published by the Free Software Foundation;
 - *
 - * This library is distributed in the hope that it will be useful,
 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 - * Library General Public License for more details.
 - *
 - * You should have received a copy of the GNU Library General Public
 - * License 2.0 along with this library; if not, write to the Free
 - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  #ifndef __MONO_SGENGC_H__
  #define __MONO_SGENGC_H__
@@@ -116,16 -127,40 +116,40 @@@ extern guint64 stat_objects_copied_majo
                g_error (__VA_ARGS__);  \
  } } while (0)
  
+ #ifndef HOST_WIN32
+ # define LOG_TIMESTAMP  \
+       do {    \
+               time_t t;                                                                       \
+               struct tm tod;                                                                  \
+               time(&t);                                                                       \
+               localtime_r(&t, &tod);                                                          \
+               strftime(logTime, sizeof(logTime), "%Y-%m-%d %H:%M:%S", &tod);                  \
+       } while (0)
+ #else
+ # define LOG_TIMESTAMP  \
+       do {    \
+               time_t t;                                                                       \
+               struct tm *tod;                                                                 \
+               time(&t);                                                                       \
+               tod = localtime(&t);                                                            \
+               strftime(logTime, sizeof(logTime), "%F %T", tod);                               \
+       } while (0)
+ #endif
  
  #define SGEN_LOG(level, format, ...) do {      \
        if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) {        \
-               mono_gc_printf (gc_debug_file, format "\n", ##__VA_ARGS__);     \
+               char logTime[80];                                                               \
+               LOG_TIMESTAMP;                                                                  \
+               mono_gc_printf (gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__);      \
  } } while (0)
  
  #define SGEN_COND_LOG(level, cond, format, ...) do {  \
-       if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) {        \
-               if (cond)       \
-                       mono_gc_printf (gc_debug_file, format "\n", ##__VA_ARGS__);     \
+       if (G_UNLIKELY ((level) <= SGEN_MAX_DEBUG_LEVEL && (level) <= gc_debug_level)) {                \
+               if (cond) {                                                                             \
+                       char logTime[80];                                                               \
+                       LOG_TIMESTAMP;                                                                  \
+                       mono_gc_printf (gc_debug_file, "%s " format "\n", logTime, ##__VA_ARGS__);      \
+               }                                                                                       \
  } } while (0)
  
  extern int gc_debug_level;
@@@ -315,7 -350,6 +339,7 @@@ enum 
        INTERNAL_MEM_CARDTABLE_MOD_UNION,
        INTERNAL_MEM_BINARY_PROTOCOL,
        INTERNAL_MEM_TEMPORARY,
 +      INTERNAL_MEM_LOG_ENTRY,
        INTERNAL_MEM_FIRST_CLIENT
  };
  
@@@ -397,14 -431,12 +421,14 @@@ gboolean sgen_is_worker_thread (MonoNat
  typedef void (*CopyOrMarkObjectFunc) (GCObject**, SgenGrayQueue*);
  typedef void (*ScanObjectFunc) (GCObject *obj, SgenDescriptor desc, SgenGrayQueue*);
  typedef void (*ScanVTypeFunc) (GCObject *full_object, char *start, SgenDescriptor desc, SgenGrayQueue* BINARY_PROTOCOL_ARG (size_t size));
 +typedef void (*ScanPtrFieldFunc) (GCObject *obj, GCObject **ptr, SgenGrayQueue* queue);
  typedef gboolean (*DrainGrayStackFunc) (SgenGrayQueue *queue);
  
  typedef struct {
        CopyOrMarkObjectFunc copy_or_mark_object;
        ScanObjectFunc scan_object;
        ScanVTypeFunc scan_vtype;
 +      ScanPtrFieldFunc scan_ptr_field;
        /* Drain stack optimized for the above functions */
        DrainGrayStackFunc drain_gray_stack;
        /*FIXME add allocation function? */
@@@ -432,9 -464,9 +456,9 @@@ void* sgen_alloc_internal_dynamic (size
  void sgen_free_internal_dynamic (void *addr, size_t size, int type);
  
  void sgen_pin_stats_enable (void);
 -void sgen_pin_stats_register_object (GCObject *obj, size_t size);
 +void sgen_pin_stats_register_object (GCObject *obj, int generation);
  void sgen_pin_stats_register_global_remset (GCObject *obj);
 -void sgen_pin_stats_print_class_stats (void);
 +void sgen_pin_stats_report (void);
  
  void sgen_sort_addresses (void **array, size_t size);
  void sgen_add_to_global_remset (gpointer ptr, GCObject *obj);
@@@ -549,8 -581,7 +573,8 @@@ void sgen_split_nursery_init (SgenMinor
  /* Updating references */
  
  #ifdef SGEN_CHECK_UPDATE_REFERENCE
 -gboolean sgen_thread_pool_is_thread_pool_thread (MonoNativeThreadId some_thread) MONO_INTERNAL;
 +gboolean sgen_thread_pool_is_thread_pool_thread (MonoNativeThreadId some_thread);
 +
  static inline void
  sgen_update_reference (GCObject **p, GCObject *o, gboolean allow_null)
  {
  
  typedef void (*sgen_cardtable_block_callback) (mword start, mword size);
  void sgen_major_collector_iterate_live_block_ranges (sgen_cardtable_block_callback callback);
 +void sgen_major_collector_iterate_block_ranges (sgen_cardtable_block_callback callback);
  
  typedef enum {
        ITERATE_OBJECTS_SWEEP = 1,
@@@ -589,12 -619,6 +613,12 @@@ typedef struc
        size_t num_unique_scanned_objects;
  } ScannedObjectCounts;
  
 +typedef enum {
 +      CARDTABLE_SCAN_GLOBAL = 0,
 +      CARDTABLE_SCAN_MOD_UNION = 1,
 +      CARDTABLE_SCAN_MOD_UNION_PRECLEAN = CARDTABLE_SCAN_MOD_UNION | 2,
 +} CardTableScanType;
 +
  typedef struct _SgenMajorCollector SgenMajorCollector;
  struct _SgenMajorCollector {
        size_t section_size;
        void (*free_non_pinned_object) (GCObject *obj, size_t size);
        void (*pin_objects) (SgenGrayQueue *queue);
        void (*pin_major_object) (GCObject *obj, SgenGrayQueue *queue);
 -      void (*scan_card_table) (gboolean mod_union, ScanCopyContext ctx);
 +      void (*scan_card_table) (CardTableScanType scan_type, ScanCopyContext ctx);
        void (*iterate_live_block_ranges) (sgen_cardtable_block_callback callback);
 +      void (*iterate_block_ranges) (sgen_cardtable_block_callback callback);
        void (*update_cardtable_mod_union) (void);
        void (*init_to_space) (void);
        void (*sweep) (void);
@@@ -814,8 -837,17 +838,8 @@@ size_t sgen_gc_get_total_heap_allocatio
  
  /* STW */
  
 -typedef struct {
 -      int generation;
 -      const char *reason;
 -      gboolean is_overflow;
 -      gint64 total_time;
 -      gint64 stw_time;
 -      gint64 bridge_time;
 -} GGTimingInfo;
 -
  void sgen_stop_world (int generation);
 -void sgen_restart_world (int generation, GGTimingInfo *timing);
 +void sgen_restart_world (int generation);
  gboolean sgen_is_world_stopped (void);
  
  gboolean sgen_set_allow_synchronous_major (gboolean flag);
@@@ -835,7 -867,6 +859,7 @@@ struct _LOSObject 
  
  extern LOSObject *los_object_list;
  extern mword los_memory_usage;
 +extern mword los_memory_usage_total;
  
  void sgen_los_free_object (LOSObject *obj);
  void* sgen_los_alloc_large_inner (GCVTable vtable, size_t size);
@@@ -843,7 -874,7 +867,7 @@@ void sgen_los_sweep (void)
  gboolean sgen_ptr_is_in_los (char *ptr, char **start);
  void sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data);
  void sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback);
 -void sgen_los_scan_card_table (gboolean mod_union, ScanCopyContext ctx);
 +void sgen_los_scan_card_table (CardTableScanType scan_type, ScanCopyContext ctx);
  void sgen_los_update_cardtable_mod_union (void);
  void sgen_los_count_cards (long long *num_total_cards, long long *num_marked_cards);
  gboolean sgen_los_is_valid_object (char *object);
@@@ -947,8 -978,6 +971,8 @@@ extern int default_nursery_size
  extern guint32 tlab_size;
  extern NurseryClearPolicy nursery_clear_policy;
  extern gboolean sgen_try_free_some_memory;
 +extern mword total_promoted_size;
 +extern mword total_allocated_major;
  
  extern MonoCoopMutex gc_mutex;
  
index a92d250b290448698ece831e6809b4c99a8f3cdd,3d479a07fe12a502ff5563410fd79ea5e83a1f31..03c0aca8ddf3f749a801d1319ba4fa76585691b5
@@@ -6,7 -6,6 +6,7 @@@
   *
   * Copyright 2011 Novell, Inc (http://www.novell.com)
   * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
 + * Licensed under the MIT license. See LICENSE file in the project root for full license information.
   */
  
  #include <config.h>
@@@ -28,7 -27,6 +28,7 @@@
  #include <mono/utils/mono-lazy-init.h>
  #include <mono/utils/mono-coop-mutex.h>
  #include <mono/utils/mono-coop-semaphore.h>
 +#include <mono/utils/mono-threads-coop.h>
  
  #include <errno.h>
  
@@@ -47,15 -45,8 +47,15 @@@ harder for an operation that is hardly 
  The GC has to acquire this lock before starting a STW to make sure
  a runtime suspend won't make it wronly see a thread in a safepoint
  when it is in fact not.
 +
 +This has to be a naked locking primitive, and not a coop aware one, as
 +it needs to be usable when destroying thread_info_key, the TLS key for
 +the current MonoThreadInfo. In this case, mono_thread_info_current_unchecked,
 +(which is used inside MONO_ENTER_GC_SAFE), would return NULL, leading
 +to an assertion error. We then simply switch state manually in
 +mono_thread_info_suspend_lock_with_info.
  */
 -static MonoCoopSem global_suspend_semaphore;
 +static MonoSemType global_suspend_semaphore;
  
  static size_t thread_info_size;
  static MonoThreadInfoCallbacks threads_callbacks;
@@@ -80,6 -71,9 +80,9 @@@ static gboolean unified_suspend_enabled
  /*abort at 1 sec*/
  #define SLEEP_DURATION_BEFORE_ABORT 200
  
+ static long sleepWarnDuration = SLEEP_DURATION_BEFORE_WARNING,
+           sleepAbortDuration = SLEEP_DURATION_BEFORE_ABORT;
  static int suspend_posts, resume_posts, abort_posts, waits_done, pending_ops;
  
  void
@@@ -196,6 -190,7 +199,6 @@@ mono_threads_end_global_suspend (void
  static void
  dump_threads (void)
  {
 -      MonoThreadInfo *info;
        MonoThreadInfo *cur = mono_thread_info_current ();
  
        MOSTLY_ASYNC_SAFE_PRINTF ("STATE CUE CARD: (? means a positive number, usually 1 or 2, * means any number)\n");
  #else
                MOSTLY_ASYNC_SAFE_PRINTF ("--thread %p id %p [%p] state %x  %s\n", info, (void *) mono_thread_info_get_tid (info), (void*)(size_t)info->native_handle, info->thread_state, info == cur ? "GC INITIATOR" : "" );
  #endif
 -
 -      } END_FOREACH_THREAD_SAFE
 +      } FOREACH_THREAD_SAFE_END
  }
  
  gboolean
@@@ -235,14 -231,14 +238,14 @@@ mono_threads_wait_pending_operations (v
                for (i = 0; i < pending_suspends; ++i) {
                        THREADS_SUSPEND_DEBUG ("[INITIATOR-WAIT-WAITING]\n");
                        InterlockedIncrement (&waits_done);
-                       if (!mono_os_sem_timedwait (&suspend_semaphore, SLEEP_DURATION_BEFORE_ABORT, MONO_SEM_FLAGS_NONE))
+                       if (!mono_os_sem_timedwait (&suspend_semaphore, sleepAbortDuration, MONO_SEM_FLAGS_NONE))
                                continue;
                        mono_stopwatch_stop (&suspension_time);
  
                        dump_threads ();
  
                        MOSTLY_ASYNC_SAFE_PRINTF ("WAITING for %d threads, got %d suspended\n", (int)pending_suspends, i);
-                       g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), SLEEP_DURATION_BEFORE_ABORT);
+                       g_error ("suspend_thread suspend took %d ms, which is more than the allowed %d ms", (int)mono_stopwatch_elapsed_ms (&suspension_time), sleepAbortDuration);
                }
                mono_stopwatch_stop (&suspension_time);
                THREADS_SUSPEND_DEBUG ("Suspending %d threads took %d ms.\n", (int)pending_suspends, (int)mono_stopwatch_elapsed_ms (&suspension_time));
@@@ -278,7 -274,7 +281,7 @@@ mono_thread_info_lookup (MonoNativeThre
  {
                MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
  
 -      if (!mono_lls_find (&thread_list, hp, (uintptr_t)id)) {
 +      if (!mono_lls_find (&thread_list, hp, (uintptr_t)id, HAZARD_FREE_ASYNC_CTX)) {
                mono_hazard_pointer_clear_all (hp, -1);
                return NULL;
        } 
@@@ -292,7 -288,7 +295,7 @@@ mono_thread_info_insert (MonoThreadInf
  {
        MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
  
 -      if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info)) {
 +      if (!mono_lls_insert (&thread_list, hp, (MonoLinkedListSetNode*)info, HAZARD_FREE_SAFE_CTX)) {
                mono_hazard_pointer_clear_all (hp, -1);
                return FALSE;
        } 
@@@ -308,7 -304,7 +311,7 @@@ mono_thread_info_remove (MonoThreadInf
        gboolean res;
  
        THREADS_DEBUG ("removing info %p\n", info);
 -      res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info);
 +      res = mono_lls_remove (&thread_list, hp, (MonoLinkedListSetNode*)info, HAZARD_FREE_SAFE_CTX);
        mono_hazard_pointer_clear_all (hp, -1);
        return res;
  }
@@@ -386,25 -382,13 +389,25 @@@ register_thread (MonoThreadInfo *info, 
        return info;
  }
  
 +static void
 +mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info);
 +
  static void
  unregister_thread (void *arg)
  {
 -      MonoThreadInfo *info = (MonoThreadInfo *) arg;
 -      int small_id = info->small_id;
 +      gpointer gc_unsafe_stackdata;
 +      MonoThreadInfo *info;
 +      int small_id;
 +
 +      info = (MonoThreadInfo *) arg;
        g_assert (info);
  
 +      small_id = info->small_id;
 +
 +      /* We only enter the GC unsafe region, as when exiting this function, the thread
 +       * will be detached, and the current MonoThreadInfo* will be destroyed. */
 +      mono_threads_enter_gc_unsafe_region_unbalanced_with_info (info, &gc_unsafe_stackdata);
 +
        THREADS_DEBUG ("unregistering info %p\n", info);
  
        mono_native_tls_set_value (thread_exited_key, GUINT_TO_POINTER (1));
        if (threads_callbacks.thread_detach)
                threads_callbacks.thread_detach (info);
  
 -      mono_thread_info_suspend_lock ();
 +      mono_thread_info_suspend_lock_with_info (info);
  
        /*
        Now perform the callback that must be done under locks.
        g_byte_array_free (info->stackdata, /*free_segment=*/TRUE);
  
        /*now it's safe to free the thread info.*/
 -      mono_thread_hazardous_free_or_queue (info, free_thread_info, TRUE, FALSE);
 +      mono_thread_hazardous_try_free (info, free_thread_info);
 +      /* Pump the HP queue */
 +      mono_thread_hazardous_try_free_some ();
 +
        mono_thread_small_id_free (small_id);
  }
  
@@@ -639,6 -620,7 +642,7 @@@ mono_threads_init (MonoThreadInfoCallba
        gboolean res;
        threads_callbacks = *callbacks;
        thread_info_size = info_size;
+       char *sleepLimit;
  #ifdef HOST_WIN32
        res = mono_native_tls_alloc (&thread_info_key, NULL);
        res = mono_native_tls_alloc (&thread_exited_key, NULL);
        g_assert (res);
  
        unified_suspend_enabled = g_getenv ("MONO_ENABLE_UNIFIED_SUSPEND") != NULL || mono_threads_is_coop_enabled ();
+       
+       if ((sleepLimit = g_getenv ("MONO_SLEEP_ABORT_LIMIT")) != NULL) {
+               long threshold = strtol(sleepLimit, NULL, 10);
+               if ((errno == 0) && (threshold >= 40))  {
+                       sleepAbortDuration = threshold;
+                       sleepWarnDuration = threshold / 20;
+               } else
+                       g_warning("MONO_SLEEP_ABORT_LIMIT must be a number >= 40");
+       }
  
 -      mono_coop_sem_init (&global_suspend_semaphore, 1);
 +      mono_os_sem_init (&global_suspend_semaphore, 1);
        mono_os_sem_init (&suspend_semaphore, 0);
  
 -      mono_lls_init (&thread_list, NULL);
 +      mono_lls_init (&thread_list, NULL, HAZARD_FREE_NO_LOCK);
        mono_thread_smr_init ();
        mono_threads_init_platform ();
        mono_threads_init_coop ();
@@@ -816,6 -807,12 +829,6 @@@ mono_thread_info_begin_resume (MonoThre
        return mono_thread_info_core_resume (info);
  }
  
 -gboolean
 -mono_thread_info_check_suspend_result (MonoThreadInfo *info)
 -{
 -      return check_async_suspend (info);
 -}
 -
  /*
  FIXME fix cardtable WB to be out of line and check with the runtime if the target is not the
  WB trampoline. Another option is to encode wb ranges in MonoJitInfo, but that is somewhat hard.
@@@ -902,8 -899,6 +915,8 @@@ suspend_sync (MonoNativeThreadId tid, g
        mono_threads_wait_pending_operations ();
  
        if (!check_async_suspend (info)) {
 +              mono_thread_info_core_resume (info);
 +              mono_threads_wait_pending_operations ();
                mono_hazard_pointer_clear (hp, 1);
                return NULL;
        }
@@@ -1005,30 -1000,17 +1018,30 @@@ The suspend lock is held during any sus
  A GC that has safepoints must take this lock as part of its
  STW to make sure no unsafe pending suspend is in progress.   
  */
 +
 +static void
 +mono_thread_info_suspend_lock_with_info (MonoThreadInfo *info)
 +{
 +      g_assert (info);
 +
 +      MONO_ENTER_GC_SAFE_WITH_INFO(info);
 +
 +      int res = mono_os_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
 +      g_assert (res != -1);
 +
 +      MONO_EXIT_GC_SAFE_WITH_INFO;
 +}
 +
  void
  mono_thread_info_suspend_lock (void)
  {
 -      int res = mono_coop_sem_wait (&global_suspend_semaphore, MONO_SEM_FLAGS_NONE);
 -      g_assert (res != -1);
 +      mono_thread_info_suspend_lock_with_info (mono_thread_info_current_unchecked ());
  }
  
  void
  mono_thread_info_suspend_unlock (void)
  {
 -      mono_coop_sem_post (&global_suspend_semaphore);
 +      mono_os_sem_post (&global_suspend_semaphore);
  }
  
  /*
@@@ -1164,35 -1146,35 +1177,35 @@@ sleep_interrupt (gpointer data
  static inline guint32
  sleep_interruptable (guint32 ms, gboolean *alerted)
  {
 -      guint32 start, now, end;
 +      gint64 now, end;
  
        g_assert (INFINITE == G_MAXUINT32);
  
        g_assert (alerted);
        *alerted = FALSE;
  
 -      start = mono_msec_ticks ();
 -
 -      if (start < G_MAXUINT32 - ms) {
 -              end = start + ms;
 -      } else {
 -              /* start + ms would overflow guint32 */
 -              end = G_MAXUINT32;
 -      }
 +      if (ms != INFINITE)
 +              end = mono_100ns_ticks () + (ms * 1000 * 10);
  
        mono_lazy_initialize (&sleep_init, sleep_initialize);
  
        mono_coop_mutex_lock (&sleep_mutex);
  
 -      for (now = mono_msec_ticks (); ms == INFINITE || now - start < ms; now = mono_msec_ticks ()) {
 +      for (;;) {
 +              if (ms != INFINITE) {
 +                      now = mono_100ns_ticks ();
 +                      if (now > end)
 +                              break;
 +              }
 +
                mono_thread_info_install_interrupt (sleep_interrupt, NULL, alerted);
                if (*alerted) {
                        mono_coop_mutex_unlock (&sleep_mutex);
                        return WAIT_IO_COMPLETION;
                }
  
 -              if (ms < INFINITE)
 -                      mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, end - now);
 +              if (ms != INFINITE)
 +                      mono_coop_cond_timedwait (&sleep_cond, &sleep_mutex, (end - now) / 10 / 1000);
                else
                        mono_coop_cond_wait (&sleep_cond, &sleep_mutex);
  
@@@ -1226,7 -1208,7 +1239,7 @@@ mono_thread_info_sleep (guint32 ms, gbo
        if (alerted)
                return sleep_interruptable (ms, alerted);
  
 -      MONO_PREPARE_BLOCKING;
 +      MONO_ENTER_GC_SAFE;
  
        if (ms == INFINITE) {
                do {
  #endif /* __linux__ */
        }
  
 -      MONO_FINISH_BLOCKING;
 +      MONO_EXIT_GC_SAFE;
  
        return 0;
  }
  gint
  mono_thread_info_usleep (guint64 us)
  {
 -      MONO_PREPARE_BLOCKING;
 +      MONO_ENTER_GC_SAFE;
        g_usleep (us);
 -      MONO_FINISH_BLOCKING;
 +      MONO_EXIT_GC_SAFE;
        return 0;
  }
  
@@@ -1343,6 -1325,12 +1356,6 @@@ mono_threads_open_thread_handle (HANDL
        return mono_threads_core_open_thread_handle (handle, tid);
  }
  
 -void
 -mono_thread_info_set_name (MonoNativeThreadId tid, const char *name)
 -{
 -      mono_threads_core_set_name (tid, name);
 -}
 -
  #define INTERRUPT_STATE ((MonoThreadInfoInterruptToken*) (size_t) -1)
  
  struct _MonoThreadInfoInterruptToken {
@@@ -1543,8 -1531,26 +1556,8 @@@ mono_thread_info_describe_interrupt_tok
                g_string_append_printf (text, "waiting");
  }
  
 -/* info must be self or be held in a hazard pointer. */
  gboolean
 -mono_threads_add_async_job (MonoThreadInfo *info, MonoAsyncJob job)
 +mono_thread_info_is_current (MonoThreadInfo *info)
  {
 -      MonoAsyncJob old_job;
 -      do {
 -              old_job = (MonoAsyncJob) info->service_requests;
 -              if (old_job & job)
 -                      return FALSE;
 -      } while (InterlockedCompareExchange (&info->service_requests, old_job | job, old_job) != old_job);
 -      return TRUE;
 -}
 -
 -MonoAsyncJob
 -mono_threads_consume_async_jobs (void)
 -{
 -      MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key);
 -
 -      if (!info)
 -              return (MonoAsyncJob) 0;
 -
 -      return (MonoAsyncJob) InterlockedExchange (&info->service_requests, 0);
 +      return mono_thread_info_get_tid (info) == mono_native_thread_id_get ();
  }