2010-07-09 Mark Probst <mark.probst@gmail.com>
authorMark Probst <mark.probst@gmail.com>
Fri, 9 Jul 2010 01:30:33 +0000 (01:30 -0000)
committerMark Probst <mark.probst@gmail.com>
Fri, 9 Jul 2010 01:30:33 +0000 (01:30 -0000)
* sgen-protocol.c, sgen-gc.c: Make binary protocol lock-freely
thread-safe.

svn path=/trunk/mono/; revision=160095

mono/metadata/ChangeLog
mono/metadata/sgen-gc.c
mono/metadata/sgen-protocol.c

index 346475b9b5c6907d2eb7369b28e057fe53b8e316..c79687bd808eff7f91f279317f3318deffbbffc8 100644 (file)
@@ -1,3 +1,8 @@
+2010-07-09  Mark Probst  <mark.probst@gmail.com>
+
+       * sgen-protocol.c, sgen-gc.c: Make binary protocol lock-freely
+       thread-safe.
+
 2010-07-08 Neale Ferguson <neale@sinenomine.net>
 
        * sgen-archdep.h: Add support for s390x
index 3c7e2a351d8af2cff048c714a0b80219b55d0a68..b0f2a3878207428ed20ae7503af545bb75ffef46 100644 (file)
@@ -3321,6 +3321,8 @@ collect_nursery (size_t requested_size)
 
        check_scan_starts ();
 
+       binary_protocol_flush_buffers ();
+
        current_collection_generation = -1;
 
        return need_major_collection ();
@@ -3554,6 +3556,8 @@ major_do_collection (const char *reason)
 
        check_scan_starts ();
 
+       binary_protocol_flush_buffers ();
+
        //consistency_check ();
 }
 
index 7515f8d0ad08e36551daced40f845196a3f0c91c..969797b425608a7121f32de2865606a549702ab3 100644 (file)
 /* If not null, dump binary protocol to this file */
 static FILE *binary_protocol_file = NULL;
 
-#define BINARY_PROTOCOL_BUFFER_SIZE    65536
+#define BINARY_PROTOCOL_BUFFER_SIZE    (65536 - 2 * 8)
 
-static unsigned char binary_protocol_buffer [BINARY_PROTOCOL_BUFFER_SIZE];
-static int binary_protocol_buffer_index = 0;
+typedef struct _BinaryProtocolBuffer BinaryProtocolBuffer;
+struct _BinaryProtocolBuffer {
+       BinaryProtocolBuffer *next;
+       int index;
+       unsigned char buffer [BINARY_PROTOCOL_BUFFER_SIZE];
+};
+
+static BinaryProtocolBuffer *binary_protocol_buffers = NULL;
+LOCK_DECLARE (binary_protocol_mutex);
 
 static void
-flush_binary_protocol_buffer (void)
+binary_protocol_flush_buffers_rec (BinaryProtocolBuffer *buffer)
 {
-       if (!binary_protocol_file)
+       if (!buffer)
                return;
-       if (binary_protocol_buffer_index == 0)
+
+       binary_protocol_flush_buffers_rec (buffer->next);
+
+       g_assert (buffer->index > 0);
+       fwrite (buffer->buffer, 1, buffer->index, binary_protocol_file);
+
+       free_os_memory (buffer, sizeof (BinaryProtocolBuffer));
+}
+
+static void
+binary_protocol_flush_buffers (void)
+{
+       if (!binary_protocol_file)
                return;
 
-       fwrite (binary_protocol_buffer, 1, binary_protocol_buffer_index, binary_protocol_file);
-       fflush (binary_protocol_file);
+       binary_protocol_flush_buffers_rec (binary_protocol_buffers);
+       binary_protocol_buffers = NULL;
+}
+
+static BinaryProtocolBuffer*
+binary_protocol_get_buffer (int length)
+{
+       BinaryProtocolBuffer *buffer, *new_buffer;
+
+ retry:
+       buffer = binary_protocol_buffers;
+       if (buffer && buffer->index + length <= BINARY_PROTOCOL_BUFFER_SIZE)
+               return buffer;
+
+       new_buffer = get_os_memory (sizeof (BinaryProtocolBuffer), TRUE);
+       new_buffer->next = buffer;
+       new_buffer->index = 0;
 
-       binary_protocol_buffer_index = 0;
+       if (InterlockedCompareExchangePointer ((void**)&binary_protocol_buffers, new_buffer, buffer) != buffer) {
+               free_os_memory (new_buffer, sizeof (BinaryProtocolBuffer));
+               goto retry;
+       }
+
+       return new_buffer;
 }
 
+
 static void
 protocol_entry (unsigned char type, gpointer data, int size)
 {
+       int index;
+       BinaryProtocolBuffer *buffer;
+
        if (!binary_protocol_file)
                return;
-       if (binary_protocol_buffer_index + 1 + size > BINARY_PROTOCOL_BUFFER_SIZE)
-               flush_binary_protocol_buffer ();
 
-       binary_protocol_buffer [binary_protocol_buffer_index++] = type;
-       memcpy (binary_protocol_buffer + binary_protocol_buffer_index, data, size);
-       binary_protocol_buffer_index += size;
+ retry:
+       buffer = binary_protocol_get_buffer (size + 1);
+ retry_same_buffer:
+       index = buffer->index;
+       if (index + 1 + size > BINARY_PROTOCOL_BUFFER_SIZE)
+               goto retry;
+
+       if (InterlockedCompareExchange (&buffer->index, index + 1 + size, index) != index)
+               goto retry_same_buffer;
+
+       buffer->buffer [index++] = type;
+       memcpy (buffer->buffer + index, data, size);
+       index += size;
 
-       g_assert (binary_protocol_buffer_index <= BINARY_PROTOCOL_BUFFER_SIZE);
+       g_assert (index <= BINARY_PROTOCOL_BUFFER_SIZE);
 }
 
 static void
 binary_protocol_collection (int generation)
 {
        SGenProtocolCollection entry = { generation };
-       flush_binary_protocol_buffer ();
+       binary_protocol_flush_buffers ();
        protocol_entry (SGEN_PROTOCOL_COLLECTION, &entry, sizeof (SGenProtocolCollection));
 }