[PATCH] [libpthread] possible optimization of wait_node_alloc() and wait_node_free()

Dmitry Adamushko dmitry.adamushko at gmail.com
Mon Feb 26 16:09:23 UTC 2007


Hi,

as a possible optimization:

(1) spinlock-mb-rm.patch

__pthread_release() does WRITE_MEMORY_BARRIER() explicitly at the
beginning so the ones in wait_node_alloc() and wait_node_free() (right
before calling __pthread_release()) are redundant.

(2) spinlock-wn-atomic.patch

wait_node_alloc() and wait_node_free() can be optimised a bit in case
of HAS_COMPARE_AND_SWAP.

Although, this is a rather worst-case scenario optimization. At the
average case, contention for "wait_node_free_list_spinlock" is /very
likely/ to be low and - now that I'm thinking again - on most archs
testandset() is likely to be
simpler than compare_and_swap() (?). So, well, maybe it's not worth
considering.

--
Best regards,
Dmitry Adamushko


--- libpthread/linuxthreads/spinlock.c  2007-01-26 00:54:19.000000000 +0100
+++ libpthread/linuxthreads/spinlock-mb-rm.c    2007-02-26
13:41:32.378300000 +0100
@@ -293,7 +293,6 @@ static struct wait_node *wait_node_alloc
      new_node = (struct wait_node *) wait_node_free_list;
      wait_node_free_list = (long) new_node->next;
    }
-    WRITE_MEMORY_BARRIER();
    __pthread_release(&wait_node_free_list_spinlock);

    if (new_node == 0)
@@ -310,7 +309,6 @@ static void wait_node_free(struct wait_n
    __pthread_acquire(&wait_node_free_list_spinlock);
    wn->next = (struct wait_node *) wait_node_free_list;
    wait_node_free_list = (long) wn;
-    WRITE_MEMORY_BARRIER();
    __pthread_release(&wait_node_free_list_spinlock);
    return;
 }

--- libpthread/linuxthreads/spinlock.c  2007-02-26 14:16:23.716470000 +0100
+++ libpthread/linuxthreads/spinlock-wn.c       2007-02-26
14:29:48.407751000 +0100
@@ -276,7 +276,9 @@ struct wait_node {
 };

 static long wait_node_free_list;
+#if !defined HAS_COMPARE_AND_SWAP
 static int wait_node_free_list_spinlock;
+#endif

 /* Allocate a new node from the head of the free list using an atomic
   operation, or else using malloc if that list is empty.  A fundamental
@@ -288,12 +290,21 @@ static struct wait_node *wait_node_alloc
 {
    struct wait_node *new_node = 0;

+#if defined HAS_COMPARE_AND_SWAP
+    do {
+       new_node = (struct wait_node *) wait_node_free_list;
+       if (!new_node)
+           break;
+    } while (!__compare_and_swap(&wait_node_free_list,
+                   (long) new_node, (long) new_node->next));
+#else
    __pthread_acquire(&wait_node_free_list_spinlock);
    if (wait_node_free_list != 0) {
      new_node = (struct wait_node *) wait_node_free_list;
      wait_node_free_list = (long) new_node->next;
    }
    __pthread_release(&wait_node_free_list_spinlock);
+#endif

    if (new_node == 0)
      return malloc(sizeof *wait_node_alloc());
@@ -306,10 +317,17 @@ static struct wait_node *wait_node_alloc

 static void wait_node_free(struct wait_node *wn)
 {
+#if defined HAS_COMPARE_AND_SWAP
+    do {
+       wn->next = (struct wait_node *) wait_node_free_list;
+    } while (!__compare_and_swap_with_release_semantics(&wait_node_free_list,
+                   (long) wn->next, (long) wn));
+#else
    __pthread_acquire(&wait_node_free_list_spinlock);
    wn->next = (struct wait_node *) wait_node_free_list;
    wait_node_free_list = (long) wn;
    __pthread_release(&wait_node_free_list_spinlock);
+#endif
    return;
 }



More information about the uClibc mailing list