+static void *
+writer_thread (void *arg)
+{
+ MonoProfiler *prof = arg;
+
+ mono_threads_attach_tools_thread ();
+
+ dump_header (prof);
+
+ while (InterlockedRead (&prof->run_writer_thread)) {
+ WriterQueueEntry *entry;
+
+ while ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
+ LogBuffer *method_buffer = NULL;
+ gboolean new_methods = FALSE;
+
+ if (entry->methods->len)
+ method_buffer = create_buffer ();
+
+ /*
+ * Encode the method events in a temporary log buffer that we
+ * flush to disk before the main buffer, ensuring that all
+ * methods have metadata emitted before they're referenced.
+ */
+ for (guint i = 0; i < entry->methods->len; i++) {
+ MethodInfo *info = g_ptr_array_index (entry->methods, i);
+
+ if (mono_conc_hashtable_lookup (prof->method_table, info->method))
+ continue;
+
+ new_methods = TRUE;
+
+ /*
+ * Other threads use this hash table to get a general
+ * idea of whether a method has already been emitted to
+ * the stream. Due to the way we add to this table, it
+ * can easily happen that multiple threads queue up the
+ * same methods, but that's OK since eventually all
+ * methods will be in this table and the thread-local
+ * method lists will just be empty for the rest of the
+ * app's lifetime.
+ */
+ mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
+
+ char *name = mono_method_full_name (info->method, 1);
+ int nlen = strlen (name) + 1;
+ uint64_t now = current_time ();
+
+ method_buffer = ensure_logbuf_inner (method_buffer, 32 + nlen);
+
+ emit_byte (method_buffer, TYPE_JIT | TYPE_METHOD);
+ emit_time (method_buffer, now);
+ emit_method_inner (method_buffer, info->method);
+ emit_ptr (method_buffer, mono_jit_info_get_code_start (info->ji));
+ emit_value (method_buffer, mono_jit_info_get_code_size (info->ji));
+
+ memcpy (method_buffer->data, name, nlen);
+ method_buffer->data += nlen;
+
+ mono_free (name);
+ free (info);
+ }
+
+ g_ptr_array_free (entry->methods, TRUE);
+
+ if (new_methods)
+ dump_buffer (prof, method_buffer);
+ else if (method_buffer)
+ free_buffer (method_buffer, method_buffer->size);
+
+ dump_buffer (prof, entry->buffer);
+
+ free (entry);
+ }
+ }
+
+ return NULL;
+}
+
+static int
+start_writer_thread (MonoProfiler* prof)
+{
+ InterlockedWrite (&prof->run_writer_thread, 1);
+
+ return !pthread_create (&prof->writer_thread, NULL, writer_thread, prof);
+}
+