[utils] Fix retiring of live block for the lock free allocator
[mono.git] / mono / utils / lock-free-alloc.c
index 308ab12dda8037eed792642c24d7b6fafccb56a2..d103ef6aa333eeb96a920d8e62ef0af79db5ecb2 100644 (file)
@@ -3,24 +3,7 @@
  *
  * (C) Copyright 2011 Novell, Inc
  *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- * 
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 /*
@@ -250,7 +233,7 @@ desc_retire (Descriptor *desc)
        g_assert (desc->in_use);
        desc->in_use = FALSE;
        free_sb (desc->sb, desc->block_size);
-       mono_thread_hazardous_free_or_queue (desc, desc_enqueue_avail, FALSE, TRUE);
+       mono_thread_hazardous_try_free (desc, desc_enqueue_avail);
 }
 #else
 MonoLockFreeQueue available_descs;
@@ -294,7 +277,7 @@ desc_put_partial (gpointer _desc)
 
        g_assert (desc->anchor.data.state != STATE_FULL);
 
-       mono_lock_free_queue_node_free (&desc->node);
+       mono_lock_free_queue_node_unpoison (&desc->node);
        mono_lock_free_queue_enqueue (&desc->heap->sc->partial, &desc->node);
 }
 
@@ -302,7 +285,7 @@ static void
 list_put_partial (Descriptor *desc)
 {
        g_assert (desc->anchor.data.state != STATE_FULL);
-       mono_thread_hazardous_free_or_queue (desc, desc_put_partial, FALSE, TRUE);
+       mono_thread_hazardous_try_free (desc, desc_put_partial);
 }
 
 static void
@@ -321,7 +304,7 @@ list_remove_empty_desc (MonoLockFreeAllocSizeClass *sc)
                        desc_retire (desc);
                } else {
                        g_assert (desc->heap->sc == sc);
-                       mono_thread_hazardous_free_or_queue (desc, desc_put_partial, FALSE, TRUE);
+                       mono_thread_hazardous_try_free (desc, desc_put_partial);
                        if (++num_non_empty >= 2)
                                return;
                }
@@ -494,8 +477,18 @@ mono_lock_free_free (gpointer ptr, size_t block_size)
                g_assert (old_anchor.data.state != STATE_EMPTY);
 
                if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, NULL, desc) == desc) {
-                       /* We own it, so we free it. */
-                       desc_retire (desc);
+                       /*
+                        * We own desc, check if it's still empty, in which case we retire it.
+                        * If it's partial we need to put it back either on the active slot or
+                        * on the partial list.
+                        */
+                       if (desc->anchor.data.state == STATE_EMPTY) {
+                               desc_retire (desc);
+                       } else if (desc->anchor.data.state == STATE_PARTIAL) {
+                               if (InterlockedCompareExchangePointer ((gpointer * volatile)&heap->active, desc, NULL) != NULL)
+                                       heap_put_partial (desc);
+
+                       }
                } else {
                        /*
                         * Somebody else must free it, so we do some