Fix code for TEST_FOR_COMPARE_AND_SWAP being defined.
authordrepper <drepper>
Wed, 12 Jul 2000 19:56:18 +0000 (19:56 +0000)
committerdrepper <drepper>
Wed, 12 Jul 2000 19:56:18 +0000 (19:56 +0000)
Add tests also to new alternative spinlock implementation.

linuxthreads/spinlock.c
linuxthreads/spinlock.h

index a63c653..38d6b8e 100644 (file)
 #include "spinlock.h"
 #include "restart.h"
 
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+static void __pthread_acquire(int * spinlock);
+#endif
+
+
 /* The status field of a spinlock is a pointer whose least significant
    bit is a locked flag.
 
@@ -59,10 +64,10 @@ void internal_function __pthread_lock(struct _pthread_fastlock * lock,
 #if defined TEST_FOR_COMPARE_AND_SWAP
   if (!__pthread_has_cas)
 #endif
-#if !defined HAS_COMPARE_AND_SWAP
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
   {
     __pthread_acquire(&lock->__spinlock);
-    return 0;
+    return;
   }
 #endif
 
@@ -147,7 +152,7 @@ int __pthread_unlock(struct _pthread_fastlock * lock)
 #if defined TEST_FOR_COMPARE_AND_SWAP
   if (!__pthread_has_cas)
 #endif
-#if !defined HAS_COMPARE_AND_SWAP
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
   {
     WRITE_MEMORY_BARRIER();
     lock->__spinlock = 0;
@@ -237,7 +242,9 @@ struct wait_node {
 };
 
 static long wait_node_free_list;
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_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
@@ -247,8 +254,33 @@ static int wait_node_free_list_spinlock;
 
 static struct wait_node *wait_node_alloc(void)
 {
+#if defined HAS_COMPARE_AND_SWAP
   long oldvalue, newvalue;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    struct wait_node *new_node = 0;
 
+    __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;
+    }
+    WRITE_MEMORY_BARRIER();
+    wait_node_free_list_spinlock = 0;
+
+    if (new_node == 0)
+      return malloc(sizeof *wait_node_alloc());
+
+    return new_node;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
   do {
     oldvalue = wait_node_free_list;
 
@@ -257,10 +289,10 @@ static struct wait_node *wait_node_alloc(void)
 
     newvalue = (long) ((struct wait_node *) oldvalue)->next;
     WRITE_MEMORY_BARRIER();
-  } while (! compare_and_swap(&wait_node_free_list, oldvalue, newvalue,
-                              &wait_node_free_list_spinlock));
+  } while (! __compare_and_swap(&wait_node_free_list, oldvalue, newvalue));
 
   return (struct wait_node *) oldvalue;
+#endif
 }
 
 /* Return a node to the head of the free list using an atomic
@@ -268,37 +300,53 @@ static struct wait_node *wait_node_alloc(void)
 
 static void wait_node_free(struct wait_node *wn)
 {
+#if defined HAS_COMPARE_AND_SWAP
   long oldvalue, newvalue;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __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();
+    wait_node_free_list_spinlock = 0;
+    return;
+  }
+#endif
 
+#if defined HAS_COMPARE_AND_SWAP
   do {
     oldvalue = wait_node_free_list;
     wn->next = (struct wait_node *) oldvalue;
     newvalue = (long) wn;
     WRITE_MEMORY_BARRIER();
-  } while (! compare_and_swap(&wait_node_free_list, oldvalue, newvalue,
-                              &wait_node_free_list_spinlock));
+  } while (! __compare_and_swap(&wait_node_free_list, oldvalue, newvalue));
+#endif
 }
 
+#if defined HAS_COMPARE_AND_SWAP
+
 /* Remove a wait node from the specified queue.  It is assumed
    that the removal takes place concurrently with only atomic insertions at the
    head of the queue. */
 
 static void wait_node_dequeue(struct wait_node **pp_head,
                              struct wait_node **pp_node,
-                             struct wait_node *p_node,
-                             int *spinlock)
+                             struct wait_node *p_node)
 {
-  long oldvalue, newvalue;
-
   /* If the node is being deleted from the head of the
      list, it must be deleted using atomic compare-and-swap.
      Otherwise it can be deleted in the straightforward way. */
 
   if (pp_node == pp_head) {
-    oldvalue = (long) p_node;
-    newvalue = (long) p_node->next;
-
-    if (compare_and_swap((long *) pp_node, oldvalue, newvalue, spinlock))
+    long oldvalue = (long) p_node;
+    long newvalue = (long) p_node->next;
+       
+    if (__compare_and_swap((long *) pp_node, oldvalue, newvalue))
       return;
 
     /* Oops! Compare and swap failed, which means the node is
@@ -314,12 +362,46 @@ static void wait_node_dequeue(struct wait_node **pp_head,
   return;
 }
 
+#endif
+
 void __pthread_alt_lock(struct _pthread_fastlock * lock,
                        pthread_descr self)
 {
-  struct wait_node wait_node;
+#if defined HAS_COMPARE_AND_SWAP
   long oldstatus, newstatus;
+#endif
+  struct wait_node wait_node;
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    int suspend_needed = 0;
+    __pthread_acquire(&lock->__spinlock);
+
+    if (lock->__status == 0)
+      lock->__status = 1;
+    else {
+      if (self == NULL)
+       self = thread_self();
+
+      wait_node.abandoned = 0;
+      wait_node.next = (struct wait_node *) lock->__status;
+      wait_node.thr = self = thread_self();
+      suspend_needed = 1;
+    }
 
+    WRITE_MEMORY_BARRIER();
+    lock->__spinlock = 0;
+
+    if (suspend_needed)
+      suspend (self);
+    return;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
   do {
     oldstatus = lock->__status;
     if (oldstatus == 0) {
@@ -344,6 +426,7 @@ void __pthread_alt_lock(struct _pthread_fastlock * lock,
 
   if (oldstatus != 0)
     suspend(self);
+#endif
 }
 
 /* Timed-out lock operation; returns 0 to indicate timeout. */
@@ -351,8 +434,11 @@ void __pthread_alt_lock(struct _pthread_fastlock * lock,
 int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
                            pthread_descr self, const struct timespec *abstime)
 {
+  long oldstatus;
+#if defined HAS_COMPARE_AND_SWAP
+  long newstatus;
+#endif
   struct wait_node *p_wait_node = wait_node_alloc();
-  long oldstatus, newstatus;
 
   /* Out of memory, just give up and do ordinary lock. */
   if (p_wait_node == 0) {
@@ -360,6 +446,32 @@ int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
     return 1;
   }
 
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+
+    if (lock->__status == 0)
+      lock->__status = 1;
+    else {
+      if (self == NULL)
+       self = thread_self();
+
+      p_wait_node->abandoned = 0;
+      p_wait_node->next = (struct wait_node *) lock->__status;
+      p_wait_node->thr = self = thread_self();
+    }
+
+    WRITE_MEMORY_BARRIER();
+    lock->__spinlock = 0;
+    oldstatus = 1; /* force suspend */
+    goto suspend;
+  }
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
   do {
     oldstatus = lock->__status;
     if (oldstatus == 0) {
@@ -376,6 +488,11 @@ int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
     MEMORY_BARRIER();
   } while(! compare_and_swap(&lock->__status, oldstatus, newstatus,
                              &lock->__spinlock));
+#endif
+
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  suspend:
+#endif
 
   /* If we did not get the lock, do a timed suspend. If we wake up due
      to a timeout, then there is a race; the old lock owner may try
@@ -402,24 +519,50 @@ int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
 
 void __pthread_alt_unlock(struct _pthread_fastlock *lock)
 {
-  long oldstatus;
   struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio;
   struct wait_node ** const pp_head = (struct wait_node **) &lock->__status;
   int maxprio;
 
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    __pthread_acquire(&lock->__spinlock);
+  }
+#endif
+
   while (1) {
 
   /* If no threads are waiting for this lock, try to just
      atomically release it. */
+#if defined TEST_FOR_COMPARE_AND_SWAP
+    if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+    {
+      if (lock->__status == 0 || lock->__status == 1) {
+       lock->__status = 0;
+       break;
+      }
+    }
+#endif
 
-    oldstatus = lock->__status;
-    if (oldstatus == 0 || oldstatus == 1) {
-      if (compare_and_swap_with_release_semantics (&lock->__status, oldstatus,
-                                                  0, &lock->__spinlock))
-       return;
-      else
-       continue;
+#if defined TEST_FOR_COMPARE_AND_SWAP
+    else
+#endif
+
+#if defined HAS_COMPARE_AND_SWAP
+    {
+      long oldstatus = lock->__status;
+      if (oldstatus == 0 || oldstatus == 1) {
+       if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0))
+         break;
+       else
+         continue;
+      }
     }
+#endif
 
     /* Process the entire queue of wait nodes. Remove all abandoned
        wait nodes and put them into the global free queue, and
@@ -435,7 +578,18 @@ void __pthread_alt_unlock(struct _pthread_fastlock *lock)
 
       if (p_node->abandoned) {
        /* Remove abandoned node. */
-       wait_node_dequeue(pp_head, pp_node, p_node, &lock->__spinlock);
+#if defined TEST_FOR_COMPARE_AND_SWAP
+       if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+         *pp_node = p_node->next;
+#endif
+#if defined TEST_FOR_COMPARE_AND_SWAP
+       else
+#endif
+#if defined HAS_COMPARE_AND_SWAP
+         wait_node_dequeue(pp_head, pp_node, p_node);
+#endif
        wait_node_free(p_node);
        READ_MEMORY_BARRIER();
        p_node = *pp_node;
@@ -469,12 +623,33 @@ void __pthread_alt_unlock(struct _pthread_fastlock *lock)
        whole unlock operation. */
 
     if (!testandset(&p_max_prio->abandoned)) {
-      wait_node_dequeue(pp_head, pp_max_prio, p_max_prio, &lock->__spinlock);
+#if defined TEST_FOR_COMPARE_AND_SWAP
+      if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+       *pp_max_prio = p_max_prio->next;
+#endif
+#if defined TEST_FOR_COMPARE_AND_SWAP
+      else
+#endif
+#if defined HAS_COMPARE_AND_SWAP
+       wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);
+#endif
       WRITE_MEMORY_BARRIER();
       restart(p_max_prio->thr);
-      return;
+      break;
     }
   }
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    WRITE_MEMORY_BARRIER();
+    lock->__spinlock = 0;
+  }
+#endif
 }
 
 
@@ -486,8 +661,6 @@ int __pthread_has_cas = 0;
 
 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
 
-static void __pthread_acquire(int * spinlock);
-
 int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
                                int * spinlock)
 {
index 6609ef7..435271d 100644 (file)
@@ -105,7 +105,7 @@ static inline int __pthread_trylock (struct _pthread_fastlock * lock)
 #if defined TEST_FOR_COMPARE_AND_SWAP
   if (!__pthread_has_cas)
 #endif
-#if !defined HAS_COMPARE_AND_SWAP
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
   {
     return (testandset(&lock->__spinlock) ? EBUSY : 0);
   }
@@ -140,13 +140,26 @@ static inline void __pthread_alt_init_lock(struct _pthread_fastlock * lock)
 
 static inline int __pthread_alt_trylock (struct _pthread_fastlock * lock)
 {
+#if defined HAS_COMPARE_AND_SWAP
   long oldstatus;
+#endif
+
+#if defined TEST_FOR_COMPARE_AND_SWAP
+  if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+  {
+    return (testandset(&lock->__spinlock) ? EBUSY : 0);
+  }
+#endif
 
+#if defined HAS_COMPARE_AND_SWAP
   do {
     oldstatus = lock->__status;
     if (oldstatus != 0) return EBUSY;
   } while(! compare_and_swap(&lock->__status, 0, 1, &lock->__spinlock));
   return 0;
+#endif
 }
 
 /* Initializers for both lock variants */