[Git][ghc/ghc][wip/T18210] eventlog: Fix racy flushing

Ben Gamari gitlab at gitlab.haskell.org
Mon May 25 00:06:45 UTC 2020



Ben Gamari pushed to branch wip/T18210 at Glasgow Haskell Compiler / GHC


Commits:
29acf083 by Ben Gamari at 2020-05-24T20:06:38-04:00
eventlog: Fix racy flushing

Previously no attempt was made to avoid multiple threads writing their
capability-local eventlog buffers to the eventlog writer simultaneously.
This could result in multiple eventlog streams being interleaved. Fix
this by documenting that the EventLogWriter's write() and flush()
functions may be called reentrantly and fix the default writer to
protect its FILE* by a mutex.

Fixes #18210.

- - - - -


3 changed files:

- docs/users_guide/runtime_control.rst
- includes/rts/EventLogWriter.h
- rts/eventlog/EventLogWriter.c


Changes:

=====================================
docs/users_guide/runtime_control.rst
=====================================
@@ -196,11 +196,17 @@ Furthermore GHC lets you specify the way event log data (see :rts-flag:`-l
         Hands buffered event log data to your event log writer. Return true on success.
         Required for a custom :c:type:`EventLogWriter`.
 
+        Note that this function may be called by multiple threads
+        simultaneously.
+
     .. c:member:: void flushEventLog(void)
 
         Flush buffers (if any) of your custom :c:type:`EventLogWriter`. This can
         be ``NULL``.
 
+        Note that this function may be called by multiple threads
+        simultaneously.
+
     .. c:member:: void stopEventLogWriter(void)
 
         Called when event logging is about to stop. This can be ``NULL``.


=====================================
includes/rts/EventLogWriter.h
=====================================
@@ -24,9 +24,13 @@ typedef struct {
     void (* initEventLogWriter) (void);
 
     // Write a series of events returning true on success.
+    // Note that this may be called by multiple threads simultaneously.
+    // The writer is responsible for concurrency control.
     bool (* writeEventLog) (void *eventlog, size_t eventlog_size);
 
     // Flush possibly existing buffers (may be NULL)
+    // Note that this may be called by multiple threads simultaneously.
+    // The writer is responsible for concurrency control.
     void (* flushEventLog) (void);
 
     // Close an initialized EventLogOutput (may be NULL)


=====================================
rts/eventlog/EventLogWriter.c
=====================================
@@ -28,11 +28,22 @@ static pid_t event_log_pid = -1;
 // File for logging events
 static FILE *event_log_file = NULL;
 
+// Protects event log file
+static Mutex event_log_mutex;
+
 static void initEventLogFileWriter(void);
 static bool writeEventLogFile(void *eventlog, size_t eventlog_size);
 static void flushEventLogFile(void);
 static void stopEventLogFileWriter(void);
 
+#if defined(THREADED_RTS)
+static void acquire_event_log_mutex(void) { ACQUIRE_MUTEX(&event_log_mutex); }
+static void release_event_log_mutex(void) { RELEASE_MUTEX(&event_log_mutex); }
+#else
+static void acquire_event_log_mutex(void) {}
+static void release_event_log_mutex(void) {}
+#endif
+
 static char *outputFileName(void)
 {
 
@@ -89,6 +100,9 @@ initEventLogFileWriter(void)
     }
 
     stgFree(event_log_filename);
+#if defined(THREADED_RTS)
+    initMutex(&event_log_mutex);
+#endif
 }
 
 static bool
@@ -97,15 +111,17 @@ writeEventLogFile(void *eventlog, size_t eventlog_size)
     unsigned char *begin = eventlog;
     size_t remain = eventlog_size;
 
+    acquire_event_log_mutex();
     while (remain > 0) {
         size_t written = fwrite(begin, 1, remain, event_log_file);
         if (written == 0) {
+            release_event_log_mutex();
             return false;
         }
         remain -= written;
         begin += written;
     }
-
+    release_event_log_mutex();
     return true;
 }
 
@@ -124,6 +140,9 @@ stopEventLogFileWriter(void)
         fclose(event_log_file);
         event_log_file = NULL;
     }
+#if defined(THREADED_RTS)
+    closeMutex(&event_log_mutex);
+#endif
 }
 
 const EventLogWriter FileEventLogWriter = {



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/29acf0835a102cdad2ecb08ba7d6a37b70eb99cc

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/29acf0835a102cdad2ecb08ba7d6a37b70eb99cc
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20200524/c77d1716/attachment-0001.html>


More information about the ghc-commits mailing list