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

man/mono.1
mono/sgen/sgen-gc.h
mono/utils/Makefile.am
mono/utils/mono-log-common.c [new file with mode: 0644]
mono/utils/mono-log-posix.c [new file with mode: 0644]
mono/utils/mono-log-windows.c [new file with mode: 0644]
mono/utils/mono-logger.c
mono/utils/mono-logger.h
mono/utils/mono-threads.c
msvc/libmonoutils.vcxproj

index e2eff1620e7697a20a9d28a36db3a4e0eaf6479d..7bd449dd4559c7c9d8e1ca61432ef8a5b0340577 100644 (file)
@@ -1732,6 +1732,16 @@ messages for a certain component. You can use multiple masks by comma
 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:
index 3a86cc44f5f9bd077365a6525a26fc1f1735c373..3f61780452162b286a6056be27a731aa4e8575ff 100644 (file)
@@ -116,16 +116,40 @@ extern guint64 stat_objects_copied_major;
                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;
index b62633307b46f43e5547e6957ca6d5d6c404b0fd..02d447ad511469067266123670983bb25e694c40 100644 (file)
@@ -27,6 +27,9 @@ monoutils_sources = \
        mono-dl-darwin.c        \
        mono-dl-posix.c         \
        mono-dl.h               \
+       mono-log-windows.c      \
+       mono-log-common.c       \
+       mono-log-posix.c        \
        mono-internal-hash.c    \
        mono-internal-hash.h    \
        mono-io-portability.c   \
diff --git a/mono/utils/mono-log-common.c b/mono/utils/mono-log-common.c
new file mode 100644 (file)
index 0000000..6565d4f
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * mono-log-common.c: Platform-independent interface to the logger
+ *
+ * This module contains the POSIX syslog logger interface
+ *
+ * Author:
+ *    Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+#include <errno.h>
+#include <time.h>
+#ifndef HOST_WIN32
+#include <sys/time.h>
+#else
+#include <process.h>
+#endif
+#include "mono-logger.h"
+
+static FILE *logFile = NULL;
+static void *logUserData = NULL;
+
+/**
+ * mapSyslogLevel:
+ *     
+ *     @level - GLogLevelFlags value
+ *     @returns The equivalent character identifier
+ */
+static inline char 
+mapLogFileLevel(GLogLevelFlags level) 
+{
+       if (level & G_LOG_LEVEL_ERROR)
+               return ('E');
+       if (level & G_LOG_LEVEL_CRITICAL)
+               return ('C');
+       if (level & G_LOG_LEVEL_WARNING)
+               return ('W');
+       if (level & G_LOG_LEVEL_MESSAGE)
+               return ('N');
+       if (level & G_LOG_LEVEL_INFO)
+               return ('I');
+       if (level & G_LOG_LEVEL_DEBUG)
+               return ('D');
+       return ('I');
+}
+
+/**
+ * mono_log_open_logfile
+ *     
+ *     Open the logfile. If the path is not specified default to stdout. If the
+ *     open fails issue a warning and use stdout as the log file destination.
+ *
+ *     @path - Path for log file
+ *     @userData - Not used
+ */
+void
+mono_log_open_logfile(const char *path, void *userData)
+{
+       if (path == NULL) {
+               logFile = stdout;
+       } else {
+#ifndef HOST_WIN32
+               logFile = fopen(path, "w");
+#else
+               gunichar2 *wPath = g_utf8_to_utf16(path, -1, 0, 0, 0);
+               if (wPath != NULL) {
+                       logFile = _wfopen((wchar_t *) wPath, L"w");
+                       g_free (wPath);
+               }
+#endif
+               if (logFile == NULL) {
+                       g_warning("opening of log file %s failed with %s - defaulting to stdout", 
+                                 path, strerror(errno));
+                       logFile = stdout;
+               }
+       }
+       logUserData = userData;
+}
+
+/**
+ * mono_log_write_logfile
+ *     
+ *     Write data to the log file.
+ *
+ *     @domain - Identifier string
+ *     @level - Logging level flags
+ *     @format - Printf format string
+ *     @vargs - Variable argument list
+ */
+void
+mono_log_write_logfile(const char *domain, GLogLevelFlags level, mono_bool hdr, const char *format, va_list args)
+{
+       time_t t;
+       char logTime[80],       
+            logMessage[512];
+       pid_t pid;
+       int iLog = 0;
+       size_t nLog;
+
+       if (logFile == NULL)
+               logFile = stdout;
+
+       if (hdr) {
+#ifndef HOST_WIN32
+               struct tm tod;
+               time(&t);
+               localtime_r(&t, &tod);
+               pid = getpid();
+               strftime(logTime, sizeof(logTime), "%Y-%m-%d %H:%M:%S", &tod);
+#else
+               struct tm *tod;
+               time(&t);
+               tod = localtime(&t);
+               pid = _getpid();
+               strftime(logTime, sizeof(logTime), "%F %T", tod);
+#endif
+               iLog = snprintf(logMessage, sizeof(logMessage), "%s level[%c] mono[%d]: ",
+                               logTime,mapLogFileLevel(level),pid);
+       }
+       nLog = sizeof(logMessage) - iLog - 2;
+       iLog = vsnprintf(logMessage+iLog, nLog, format, args);
+       logMessage[iLog++] = '\n';
+       logMessage[iLog++] = '\0';
+       fputs(logMessage, logFile);
+       fflush(logFile);
+
+       if (level == G_LOG_FLAG_FATAL)
+               abort();
+}
+
+/**
+ * mono_log_close_logfile
+ *
+ *     Close the log file
+ */
+void
+mono_log_close_logfile()
+{
+       if (logFile) {
+               if (logFile != stdout)
+                       fclose(logFile);
+               logFile = NULL;
+       }
+}
diff --git a/mono/utils/mono-log-posix.c b/mono/utils/mono-log-posix.c
new file mode 100644 (file)
index 0000000..1ce111c
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * mono-log-posix.c: POSIX interface to the logger
+ *
+ * This module contains the POSIX syslog logger routines
+ *
+ * Author:
+ *    Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(_POSIX_VERSION) 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include "mono-logger.h"
+
+static void *logUserData = NULL;
+
+/**
+ * mapSyslogLevel:
+ *     
+ *     @level - GLogLevelFlags value
+ *     @returns The equivalent syslog priority value
+ */
+static __inline__ int
+mapSyslogLevel(GLogLevelFlags level) 
+{
+       if (level & G_LOG_LEVEL_ERROR)
+               return (LOG_ERR);
+       if (level & G_LOG_LEVEL_CRITICAL)
+               return (LOG_CRIT);
+       if (level & G_LOG_LEVEL_WARNING)
+               return (LOG_WARNING);
+       if (level & G_LOG_LEVEL_MESSAGE)
+               return (LOG_NOTICE);
+       if (level & G_LOG_LEVEL_INFO)
+               return (LOG_INFO);
+       if (level & G_LOG_LEVEL_DEBUG)
+               return (LOG_DEBUG);
+       return (LOG_INFO);
+}
+
+/**
+ * mono_log_open_logfile
+ *     
+ *     Open the syslog interface specifying that we want our PID recorded 
+ *     and that we're using the LOG_USER facility.
+ *
+ *     @ident - Identifier: ignored
+ *     @userData - Not used
+ */
+void
+mono_log_open_syslog(const char *ident, void *userData)
+{
+       openlog("mono", LOG_PID, LOG_USER);
+       logUserData = userData;
+}
+
+/**
+ * mono_log_write_logfile
+ *     
+ *     Write data to the log file.
+ *
+ *     @domain - Identifier string
+ *     @level - Logging level flags
+ *     @format - Printf format string
+ *     @vargs - Variable argument list
+ */
+void
+mono_log_write_syslog(const char *domain, GLogLevelFlags level, mono_bool hdr, const char *format, va_list args)
+{
+       vsyslog(mapSyslogLevel(level), format, args);
+
+       if (level == G_LOG_FLAG_FATAL)
+               abort();
+}
+
+/**
+ * mono_log_close_logfile
+ *
+ *     Close the log file
+ */
+void
+mono_log_close_syslog()
+{
+       closelog();
+}
+#endif
diff --git a/mono/utils/mono-log-windows.c b/mono/utils/mono-log-windows.c
new file mode 100644 (file)
index 0000000..c6ebc9e
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * mono-log-windows.c: Simplistic simulation of a syslog logger for Windows
+ *
+ * This module contains the Windows syslog logger interface
+ *
+ * Author:
+ *    Neale Ferguson <neale@sinenomine.net>
+ *
+ */
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HOST_WIN32
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <glib.h>
+#include <errno.h>
+#include <time.h>
+#include <process.h>
+#include "mono-logger.h"
+
+static FILE *logFile = NULL;
+static void *logUserData = NULL;
+static wchar_t *logFileName = L".//mono.log";
+
+/**
+ * mapSyslogLevel:
+ *     
+ *     @level - GLogLevelFlags value
+ *     @returns The equivalent character identifier
+ */
+static inline char 
+mapLogFileLevel(GLogLevelFlags level) 
+{
+       if (level & G_LOG_LEVEL_ERROR)
+               return ('E');
+       if (level & G_LOG_LEVEL_CRITICAL)
+               return ('C');
+       if (level & G_LOG_LEVEL_WARNING)
+               return ('W');
+       if (level & G_LOG_LEVEL_MESSAGE)
+               return ('N');
+       if (level & G_LOG_LEVEL_INFO)
+               return ('I');
+       if (level & G_LOG_LEVEL_DEBUG)
+               return ('D');
+       return ('I');
+}
+
+/**
+ * mono_log_open_syslog
+ *     
+ *     Open the syslog file. If the open fails issue a warning and 
+ *     use stdout as the log file destination.
+ *
+ *     @ident - Identifier: ignored
+ *     @userData - Not used
+ */
+void
+mono_log_open_syslog(const char *ident, void *userData)
+{
+       logFile = _wfopen(logFileName, L"w");
+       if (logFile == NULL) {
+               g_warning("opening of log file %s failed with %s",
+                         strerror(errno));
+               logFile = stdout;
+       }
+       logUserData = userData;
+}
+
+/**
+ * mono_log_write_syslog
+ *     
+ *     Write data to the syslog file.
+ *
+ *     @domain - Identifier string
+ *     @level - Logging level flags
+ *     @format - Printf format string
+ *     @vargs - Variable argument list
+ */
+void
+mono_log_write_syslog(const char *domain, GLogLevelFlags level, mono_bool hdr, const char *format, va_list args)
+{
+       time_t t;
+       struct tm *tod;
+       char logTime[80],
+             logMessage[512];
+       pid_t pid;
+       int iLog = 0;
+       size_t nLog;
+
+       if (logFile == NULL)
+               mono_log_open_syslog(NULL, NULL);
+
+       time(&t);
+       tod = localtime(&t);
+       pid = _getpid();
+       strftime(logTime, sizeof(logTime), "%Y-%m-%d %H:%M:%S", tod);
+       iLog = snprintf(logMessage, sizeof(logMessage), "%s level[%c] mono[%d]: ",
+                       logTime,mapLogFileLevel(level),pid);
+       nLog = sizeof(logMessage) - iLog - 2;
+       iLog = vsnprintf(logMessage+iLog, nLog, format, args);
+       logMessage[iLog++] = '\n';
+       logMessage[iLog++] = 0;
+       fputs(logMessage, logFile);
+       fflush(logFile);
+
+       if (level == G_LOG_FLAG_FATAL)
+               abort();
+}
+
+/**
+ * mono_log_close_syslog
+ *
+ *     Close the syslog file
+ */
+void
+mono_log_close_syslog()
+{
+       if (logFile) {
+               fclose(logFile);
+               logFile = NULL;
+       }
+}
+#endif
index 7d0c9ce12a4f811d33e6d5a3bca405b2f564da03..734a2fdbf33ab2bcd28173cde90e3271139c4fdc 100644 (file)
@@ -11,13 +11,21 @@ typedef struct {
        MonoTraceMask   mask;
 } MonoLogLevelEntry;
 
-GLogLevelFlags mono_internal_current_level             = INT_MAX;
-MonoTraceMask  mono_internal_current_mask              = MONO_TRACE_ALL;
+GLogLevelFlags mono_internal_current_level     = INT_MAX;
+MonoTraceMask  mono_internal_current_mask      = MONO_TRACE_ALL;
+gboolean mono_trace_log_header                 = FALSE;
 
 static GQueue          *level_stack            = NULL;
 static const char      *mono_log_domain        = "Mono";
 static MonoPrintCallback print_callback, printerr_callback;
 
+static MonoLogCallback logCallback = {
+       .opener = NULL,
+       .writer = NULL,
+       .closer = NULL,
+       .header = FALSE
+};
+
 /**
  * mono_trace_init:
  *
@@ -32,6 +40,8 @@ mono_trace_init (void)
 
                mono_trace_set_mask_string(g_getenv("MONO_LOG_MASK"));
                mono_trace_set_level_string(g_getenv("MONO_LOG_LEVEL"));
+               mono_trace_set_logheader_string(g_getenv("MONO_LOG_HEADER"));
+               mono_trace_set_logdest_string(g_getenv("MONO_LOG_DEST"));
        }
 }
 
@@ -71,7 +81,13 @@ mono_tracev_inner (GLogLevelFlags level, MonoTraceMask mask, const char *format,
                        return;
        }
 
-       g_logv (mono_log_domain, level, format, args);
+       if (logCallback.opener == NULL) {
+               logCallback.opener = mono_log_open_logfile;
+               logCallback.writer = mono_log_write_logfile;
+               logCallback.closer = mono_log_close_logfile;
+               logCallback.opener(NULL, NULL);
+       }
+       logCallback.writer(mono_log_domain, level, logCallback.header, format, args);
 }
 
 /**
@@ -107,7 +123,55 @@ mono_trace_set_mask (MonoTraceMask mask)
        if(level_stack == NULL)
                mono_trace_init();
 
-       mono_internal_current_mask      = mask;
+       mono_internal_current_mask = mask;
+}
+
+/**
+ * mono_trace_set_logdest:
+ *
+ *     @dest: Destination for logging
+ *
+ * Sets the current logging destination. This can be a file or, if supported,
+ * syslog.
+ */
+void 
+mono_trace_set_logdest_string (const char *dest)
+{
+       MonoLogCallback logger;
+
+       if(level_stack == NULL)
+               mono_trace_init();
+
+       if ((dest == NULL) || (strcmp("syslog", dest) != 0)) {
+               logger.opener = mono_log_open_logfile;
+               logger.writer = mono_log_write_logfile;
+               logger.closer = mono_log_close_logfile;
+               mono_trace_set_log_handler(&logger, dest, NULL);
+       } else {
+               logger.opener = mono_log_open_syslog;
+               logger.writer = mono_log_write_syslog;
+               logger.closer = mono_log_close_syslog;
+               mono_trace_set_log_handler(&logger, mono_log_domain, NULL);
+       }
+}
+
+/**
+ * mono_trace_set_logheader:
+ *
+ *     @head: Whether we want pid/date/time header on log messages
+ *
+ * Sets the current logging header option.
+ */
+void 
+mono_trace_set_logheader_string(const char *head)
+{
+       MonoLogCallback logger;
+
+       if (head == NULL) {
+               mono_trace_log_header = FALSE;
+       } else {
+               mono_trace_log_header = TRUE;
+       }
 }
 
 /**
@@ -236,28 +300,6 @@ mono_trace_is_traced (GLogLevelFlags level, MonoTraceMask mask)
        return (level <= mono_internal_current_level && mask & mono_internal_current_mask);
 }
 
-static MonoLogCallback log_callback;
-
-static const char*
-log_level_get_name (GLogLevelFlags log_level)
-{
-       switch (log_level & G_LOG_LEVEL_MASK) {
-       case G_LOG_LEVEL_ERROR: return "error";
-       case G_LOG_LEVEL_CRITICAL: return "critical";
-       case G_LOG_LEVEL_WARNING: return "warning";
-       case G_LOG_LEVEL_MESSAGE: return "message";
-       case G_LOG_LEVEL_INFO: return "info";
-       case G_LOG_LEVEL_DEBUG: return "debug";
-       default: return "unknown";
-       }
-}
-
-static void
-log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
-{
-       log_callback (log_domain, log_level_get_name (log_level), message, log_level & G_LOG_LEVEL_ERROR, user_data);
-}
-
 /**
  * mono_trace_set_log_handler:
  *
@@ -269,11 +311,14 @@ log_adapter (const gchar *log_domain, GLogLevelFlags log_level, const gchar *mes
  * execution will not resume after a fatal error.
  */
 void
-mono_trace_set_log_handler (MonoLogCallback callback, void *user_data)
+mono_trace_set_log_handler (MonoLogCallback *callback, const char *dest, void *user_data)
 {
        g_assert (callback);
-       log_callback = callback;
-       g_log_set_default_handler (log_adapter, user_data);
+       logCallback.opener = callback->opener;
+       logCallback.writer = callback->writer;
+       logCallback.closer = callback->closer;
+       logCallback.header = mono_trace_log_header;
+       logCallback.opener(dest, user_data);
 }
 
 static void
index 36f7714f2ed2dd946058e3c28a0b52c21e90e8f9..3bb54a6886ed83219359716cd78936ac9b5a99aa 100644 (file)
@@ -10,11 +10,27 @@ mono_trace_set_level_string (const char *value);
 MONO_API void 
 mono_trace_set_mask_string (const char *value);
 
-typedef void (*MonoLogCallback) (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);
+MONO_API void 
+mono_trace_set_logdest_string (const char *value);
+
+MONO_API void 
+mono_trace_set_logheader_string (const char *value);
+
 typedef void (*MonoPrintCallback) (const char *string, mono_bool is_stdout);
 
+typedef void (*MonoLoggerOpen) (const char *, void *);
+typedef void (*MonoLoggerWrite) (const char *, GLogLevelFlags, mono_bool, const char *, va_list);
+typedef void (*MonoLoggerClose) (void);
+
+typedef struct _MonoLogCallback_ {
+       MonoLoggerOpen  opener;         /* Routine to open logging */
+       MonoLoggerWrite writer;         /* Routine to write log data */
+       MonoLoggerClose closer;         /* Routine to close logging */
+       mono_bool       header;         /* Whether we want pid/time/date in log message */
+} MonoLogCallback;
+
 MONO_API void
-mono_trace_set_log_handler (MonoLogCallback callback, void *user_data);
+mono_trace_set_log_handler (MonoLogCallback *callback, const char *dest, void *user_data);
 
 MONO_API void
 mono_trace_set_print_handler (MonoPrintCallback callback);
@@ -22,6 +38,23 @@ mono_trace_set_print_handler (MonoPrintCallback callback);
 MONO_API void
 mono_trace_set_printerr_handler (MonoPrintCallback callback);
 
+MONO_API void
+mono_log_open_syslog(const char *, void *);
+
+MONO_API void
+mono_log_write_syslog(const char *, GLogLevelFlags, mono_bool, const char *, va_list);
+
+MONO_API void
+mono_log_close_syslog(void);
+
+MONO_API void
+mono_log_open_logfile(const char *, void *);
+
+MONO_API void
+mono_log_write_logfile(const char *, GLogLevelFlags, mono_bool, const char *, va_list);
+
+MONO_API void
+mono_log_close_logfile(void);
 
 MONO_END_DECLS
 
index a92d250b290448698ece831e6809b4c99a8f3cdd..03c0aca8ddf3f749a801d1319ba4fa76585691b5 100644 (file)
@@ -80,6 +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
@@ -235,14 +238,14 @@ mono_threads_wait_pending_operations (void)
                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));
@@ -639,6 +642,7 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
        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);
@@ -655,6 +659,15 @@ mono_threads_init (MonoThreadInfoCallbacks *callbacks, size_t info_size)
        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_os_sem_init (&global_suspend_semaphore, 1);
        mono_os_sem_init (&suspend_semaphore, 0);
index 5daad9472621c95d4b94c98809d6f0ab2a74ff50..7ef841f56d0aa72f6a19b58c3876b826db775ea6 100644 (file)
@@ -42,6 +42,8 @@
     <ClCompile Include="..\mono\utils\mono-io-portability.c" />\r
     <ClCompile Include="..\mono\utils\mono-linked-list-set.c" />\r
     <ClCompile Include="..\mono\utils\mono-logger.c" />\r
+    <ClCompile Include="..\mono\utils\mono-log-windows.c" />\r
+    <ClCompile Include="..\mono\utils\mono-log-common.c" />\r
     <ClCompile Include="..\mono\utils\mono-math.c" />\r
     <ClCompile Include="..\mono\utils\mono-md5.c" />\r
     <ClCompile Include="..\mono\utils\mono-mmap.c" />\r