[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