Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
[mono.git] / mono / sgen / sgen-protocol.c
index cb512fedf4fb503bc711709d5237d3134544dad0..2e59b6359a4b1aea6f4e650998ae1590e4318d50 100644 (file)
@@ -6,18 +6,7 @@
  * Copyright 2003-2010 Novell, Inc.
  * 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.
  */
 
 #ifdef HAVE_SGEN_GC
@@ -30,6 +19,7 @@
 #include "sgen-thread-pool.h"
 #include "sgen-client.h"
 #include "mono/utils/mono-membar.h"
+#include "mono/utils/mono-proclib.h"
 
 #include <errno.h>
 #include <string.h>
@@ -69,7 +59,7 @@ filename_for_index (int index)
 
        SGEN_ASSERT (0, file_size_limit > 0, "Indexed binary protocol filename must only be used with file size limit");
 
-       filename = sgen_alloc_internal_dynamic (strlen (filename_or_prefix) + 32, INTERNAL_MEM_BINARY_PROTOCOL, TRUE);
+       filename = (char *)sgen_alloc_internal_dynamic (strlen (filename_or_prefix) + 32, INTERNAL_MEM_BINARY_PROTOCOL, TRUE);
        sprintf (filename, "%s.%d", filename_or_prefix, index);
 
        return filename;
@@ -84,9 +74,16 @@ free_filename (char *filename)
 }
 
 static void
-binary_protocol_open_file (void)
+binary_protocol_open_file (gboolean assert_on_failure)
 {
        char *filename;
+#ifdef F_SETLK
+       struct flock lock;
+       lock.l_type = F_WRLCK;
+       lock.l_whence = SEEK_SET;
+       lock.l_start = 0;
+       lock.l_len = 0;
+#endif
 
        if (file_size_limit > 0)
                filename = filename_for_index (current_file_index);
@@ -94,11 +91,26 @@ binary_protocol_open_file (void)
                filename = filename_or_prefix;
 
        do {
-               binary_protocol_file = open (filename, O_CREAT|O_WRONLY|O_TRUNC, 0644);
-               if (binary_protocol_file == -1 && errno != EINTR)
-                       break; /* Failed */
+               binary_protocol_file = open (filename, O_CREAT | O_WRONLY, 0644);
+               if (binary_protocol_file == -1) {
+                       if (errno != EINTR)
+                               break; /* Failed */
+#ifdef F_SETLK
+               } else if (fcntl (binary_protocol_file, F_SETLK, &lock) == -1) {
+                       /* The lock for the file is already taken. Fail */
+                       close (binary_protocol_file);
+                       binary_protocol_file = -1;
+                       break;
+#endif
+               } else {
+                       /* We have acquired the lock. Truncate the file */
+                       ftruncate (binary_protocol_file, 0);
+               }
        } while (binary_protocol_file == -1);
 
+       if (binary_protocol_file == -1 && assert_on_failure)
+               g_error ("sgen binary protocol: failed to open file");
+
        if (file_size_limit > 0)
                free_filename (filename);
 }
@@ -108,12 +120,27 @@ void
 binary_protocol_init (const char *filename, long long limit)
 {
 #ifdef HAVE_UNISTD_H
-       filename_or_prefix = sgen_alloc_internal_dynamic (strlen (filename) + 1, INTERNAL_MEM_BINARY_PROTOCOL, TRUE);
-       strcpy (filename_or_prefix, filename);
-
        file_size_limit = limit;
 
-       binary_protocol_open_file ();
+       /* Original name length + . + pid length in hex + null terminator */
+       filename_or_prefix = g_strdup_printf ("%s", filename);
+       binary_protocol_open_file (FALSE);
+
+       if (binary_protocol_file == -1) {
+               /* Another process owns the file, try adding the pid suffix to the filename */
+               gint32 pid = mono_process_current_pid ();
+               g_free (filename_or_prefix);
+               filename_or_prefix = g_strdup_printf ("%s.%x", filename, pid);
+               binary_protocol_open_file (TRUE);
+       }
+
+       /* If we have a file size limit, we might need to open additional files */
+       if (file_size_limit == 0)
+               g_free (filename_or_prefix);
+
+       binary_protocol_header (PROTOCOL_HEADER_CHECK, PROTOCOL_HEADER_VERSION, SIZEOF_VOID_P, G_BYTE_ORDER == G_LITTLE_ENDIAN);
+#else
+       g_error ("sgen binary protocol: not supported");
 #endif
 }
 
@@ -224,7 +251,7 @@ binary_protocol_check_file_overflow (void)
        ++current_file_index;
        current_file_size = 0;
 
-       binary_protocol_open_file ();
+       binary_protocol_open_file (TRUE);
 }
 #endif
 
@@ -251,7 +278,7 @@ binary_protocol_flush_buffers (gboolean force)
 
        for (buf = binary_protocol_buffers; buf != NULL; buf = buf->next)
                ++num_buffers;
-       bufs = sgen_alloc_internal_dynamic (num_buffers * sizeof (BinaryProtocolBuffer*), INTERNAL_MEM_BINARY_PROTOCOL, TRUE);
+       bufs = (BinaryProtocolBuffer **)sgen_alloc_internal_dynamic (num_buffers * sizeof (BinaryProtocolBuffer*), INTERNAL_MEM_BINARY_PROTOCOL, TRUE);
        for (buf = binary_protocol_buffers, i = 0; buf != NULL; buf = buf->next, i++)
                bufs [i] = buf;
        SGEN_ASSERT (0, i == num_buffers, "Binary protocol buffer count error");
@@ -280,7 +307,7 @@ binary_protocol_get_buffer (int length)
        if (buffer && buffer->index + length <= BINARY_PROTOCOL_BUFFER_SIZE)
                return buffer;
 
-       new_buffer = sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE, "debugging memory");
+       new_buffer = (BinaryProtocolBuffer *)sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), (SgenAllocFlags)(SGEN_ALLOC_INTERNAL | SGEN_ALLOC_ACTIVATE), "debugging memory");
        new_buffer->next = buffer;
        new_buffer->index = 0;
 
@@ -386,9 +413,6 @@ protocol_entry (unsigned char type, gpointer data, int size)
                int __size = sizeof (PROTOCOL_STRUCT(method)); \
                CLIENT_PROTOCOL_NAME (method) (f1, f2, f3, f4, f5, f6);
 
-#define FLUSH() \
-               binary_protocol_flush_buffers (FALSE);
-
 #define DEFAULT_PRINT()
 #define CUSTOM_PRINT(_)
 
@@ -400,6 +424,11 @@ protocol_entry (unsigned char type, gpointer data, int size)
                protocol_entry (__type, __data, __size); \
        }
 
+#define END_PROTOCOL_ENTRY_FLUSH \
+               protocol_entry (__type, __data, __size); \
+               binary_protocol_flush_buffers (FALSE); \
+       }
+
 #ifdef SGEN_HEAVY_BINARY_PROTOCOL
 #define BEGIN_PROTOCOL_ENTRY_HEAVY0(method) \
        BEGIN_PROTOCOL_ENTRY0 (method)