1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1998 Xavier Leroy (Xavier.Leroy@inria.fr) */
5 /* This program is free software; you can redistribute it and/or */
6 /* modify it under the terms of the GNU Library General Public License */
7 /* as published by the Free Software Foundation; either version 2 */
8 /* of the License, or (at your option) any later version. */
10 /* This program is distributed in the hope that it will be useful, */
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
13 /* GNU Library General Public License for more details. */
25 #include "internals.h"
29 libpthread_hidden_proto(nanosleep)
31 static void __pthread_acquire(int * spinlock);
33 static __inline__ void __pthread_release(int * spinlock)
35 WRITE_MEMORY_BARRIER();
36 *spinlock = __LT_SPINLOCK_INIT;
37 __asm__ __volatile__ ("" : "=m" (*spinlock) : "m" (*spinlock));
41 /* The status field of a spinlock is a pointer whose least significant
44 Thus the field values have the following meanings:
46 status == 0: spinlock is free
47 status == 1: spinlock is taken; no thread is waiting on it
49 (status & 1) == 1: spinlock is taken and (status & ~1L) is a
50 pointer to the first waiting thread; other
51 waiting threads are linked via the p_nextlock
53 (status & 1) == 0: same as above, but spinlock is not taken.
55 The waiting list is not sorted by priority order.
56 Actually, we always insert at top of list (sole insertion mode
57 that can be performed without locking).
58 For __pthread_unlock, we perform a linear search in the list
59 to find the highest-priority, oldest waiting thread.
60 This is safe because there are no concurrent __pthread_unlock
61 operations -- only the thread that locked the mutex can unlock it. */
64 void internal_function __pthread_lock(struct _pthread_fastlock * lock,
67 #if defined HAS_COMPARE_AND_SWAP
68 long oldstatus, newstatus;
69 int successful_seizure, spurious_wakeup_count;
73 #if defined TEST_FOR_COMPARE_AND_SWAP
74 if (!__pthread_has_cas)
76 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
78 __pthread_acquire(&lock->__spinlock);
83 #if defined HAS_COMPARE_AND_SWAP
84 /* First try it without preparation. Maybe it's a completely
86 if (lock->__status == 0 && __compare_and_swap (&lock->__status, 0, 1))
89 spurious_wakeup_count = 0;
92 /* On SMP, try spinning to get the lock. */
94 if (__pthread_smp_kernel) {
95 int max_count = lock->__spinlock * 2 + 10;
97 if (max_count > MAX_ADAPTIVE_SPIN_COUNT)
98 max_count = MAX_ADAPTIVE_SPIN_COUNT;
100 for (spin_count = 0; spin_count < max_count; spin_count++) {
101 if (((oldstatus = lock->__status) & 1) == 0) {
102 if(__compare_and_swap(&lock->__status, oldstatus, oldstatus | 1))
105 lock->__spinlock += (spin_count - lock->__spinlock) / 8;
106 READ_MEMORY_BARRIER();
113 __asm__ __volatile__ ("" : "=m" (lock->__status) : "m" (lock->__status));
116 lock->__spinlock += (spin_count - lock->__spinlock) / 8;
122 /* No luck, try once more or suspend. */
125 oldstatus = lock->__status;
126 successful_seizure = 0;
128 if ((oldstatus & 1) == 0) {
129 newstatus = oldstatus | 1;
130 successful_seizure = 1;
133 self = thread_self();
134 newstatus = (long) self | 1;
138 THREAD_SETMEM(self, p_nextlock, (pthread_descr) (oldstatus));
139 /* Make sure the store in p_nextlock completes before performing
140 the compare-and-swap */
143 } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
145 /* Suspend with guard against spurious wakeup.
146 This can happen in pthread_cond_timedwait_relative, when the thread
147 wakes up due to timeout and is still on the condvar queue, and then
148 locks the queue to remove itself. At that point it may still be on the
149 queue, and may be resumed by a condition signal. */
151 if (!successful_seizure) {
154 if (self->p_nextlock != NULL) {
155 /* Count resumes that don't belong to us. */
156 spurious_wakeup_count++;
164 /* Put back any resumes we caught that don't belong to us. */
165 while (spurious_wakeup_count--)
168 READ_MEMORY_BARRIER();
172 int __pthread_unlock(struct _pthread_fastlock * lock)
174 #if defined HAS_COMPARE_AND_SWAP
176 pthread_descr thr, * ptr, * maxptr;
180 #if defined TEST_FOR_COMPARE_AND_SWAP
181 if (!__pthread_has_cas)
183 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
185 __pthread_release(&lock->__spinlock);
190 #if defined HAS_COMPARE_AND_SWAP
191 WRITE_MEMORY_BARRIER();
194 while ((oldstatus = lock->__status) == 1) {
195 if (__compare_and_swap_with_release_semantics(&lock->__status,
200 /* Find thread in waiting queue with maximal priority */
201 ptr = (pthread_descr *) &lock->__status;
202 thr = (pthread_descr) (oldstatus & ~1L);
206 /* Before we iterate over the wait queue, we need to execute
207 a read barrier, otherwise we may read stale contents of nodes that may
208 just have been inserted by other processors. One read barrier is enough to
209 ensure we have a stable list; we don't need one for each pointer chase
210 through the list, because we are the owner of the lock; other threads
211 can only add nodes at the front; if a front node is consistent,
212 the ones behind it must also be. */
214 READ_MEMORY_BARRIER();
217 if (thr->p_priority >= maxprio) {
219 maxprio = thr->p_priority;
221 ptr = &(thr->p_nextlock);
222 thr = (pthread_descr)((long)(thr->p_nextlock) & ~1L);
225 /* Remove max prio thread from waiting list. */
226 if (maxptr == (pthread_descr *) &lock->__status) {
227 /* If max prio thread is at head, remove it with compare-and-swap
228 to guard against concurrent lock operation. This removal
229 also has the side effect of marking the lock as released
230 because the new status comes from thr->p_nextlock whose
231 least significant bit is clear. */
232 thr = (pthread_descr) (oldstatus & ~1L);
233 if (! __compare_and_swap_with_release_semantics
234 (&lock->__status, oldstatus, (long)(thr->p_nextlock) & ~1L))
237 /* No risk of concurrent access, remove max prio thread normally.
238 But in this case we must also flip the least significant bit
239 of the status to mark the lock as released. */
240 thr = (pthread_descr)((long)*maxptr & ~1L);
241 *maxptr = thr->p_nextlock;
243 /* Ensure deletion from linked list completes before we
245 WRITE_MEMORY_BARRIER();
248 oldstatus = lock->__status;
249 } while (!__compare_and_swap_with_release_semantics(&lock->__status,
250 oldstatus, oldstatus & ~1L));
253 /* Wake up the selected waiting thread. Woken thread can check
254 its own p_nextlock field for NULL to detect that it has been removed. No
255 barrier is needed here, since restart() and suspend() take
256 care of memory synchronization. */
258 thr->p_nextlock = NULL;
266 * Alternate fastlocks do not queue threads directly. Instead, they queue
267 * these wait queue node structures. When a timed wait wakes up due to
268 * a timeout, it can leave its wait node in the queue (because there
269 * is no safe way to remove from the quue). Some other thread will
270 * deallocate the abandoned node.
275 struct wait_node *next; /* Next node in null terminated linked list */
276 pthread_descr thr; /* The thread waiting with this node */
277 int abandoned; /* Atomic flag */
280 static long wait_node_free_list;
281 static int wait_node_free_list_spinlock;
283 /* Allocate a new node from the head of the free list using an atomic
284 operation, or else using malloc if that list is empty. A fundamental
285 assumption here is that we can safely access wait_node_free_list->next.
286 That's because we never free nodes once we allocate them, so a pointer to a
287 node remains valid indefinitely. */
289 static struct wait_node *wait_node_alloc(void)
291 struct wait_node *new_node = 0;
293 __pthread_acquire(&wait_node_free_list_spinlock);
294 if (wait_node_free_list != 0) {
295 new_node = (struct wait_node *) wait_node_free_list;
296 wait_node_free_list = (long) new_node->next;
298 WRITE_MEMORY_BARRIER();
299 __pthread_release(&wait_node_free_list_spinlock);
302 return malloc(sizeof *wait_node_alloc());
307 /* Return a node to the head of the free list using an atomic
310 static void wait_node_free(struct wait_node *wn)
312 __pthread_acquire(&wait_node_free_list_spinlock);
313 wn->next = (struct wait_node *) wait_node_free_list;
314 wait_node_free_list = (long) wn;
315 WRITE_MEMORY_BARRIER();
316 __pthread_release(&wait_node_free_list_spinlock);
320 #if defined HAS_COMPARE_AND_SWAP
322 /* Remove a wait node from the specified queue. It is assumed
323 that the removal takes place concurrently with only atomic insertions at the
324 head of the queue. */
326 static void wait_node_dequeue(struct wait_node **pp_head,
327 struct wait_node **pp_node,
328 struct wait_node *p_node)
330 /* If the node is being deleted from the head of the
331 list, it must be deleted using atomic compare-and-swap.
332 Otherwise it can be deleted in the straightforward way. */
334 if (pp_node == pp_head) {
335 /* We don't need a read barrier between these next two loads,
336 because it is assumed that the caller has already ensured
337 the stability of *p_node with respect to p_node. */
339 long oldvalue = (long) p_node;
340 long newvalue = (long) p_node->next;
342 if (__compare_and_swap((long *) pp_node, oldvalue, newvalue))
345 /* Oops! Compare and swap failed, which means the node is
346 no longer first. We delete it using the ordinary method. But we don't
347 know the identity of the node which now holds the pointer to the node
348 being deleted, so we must search from the beginning. */
350 for (pp_node = pp_head; p_node != *pp_node; ) {
351 pp_node = &(*pp_node)->next;
352 READ_MEMORY_BARRIER(); /* Stabilize *pp_node for next iteration. */
356 *pp_node = p_node->next;
362 void __pthread_alt_lock(struct _pthread_fastlock * lock,
365 #if defined HAS_COMPARE_AND_SWAP
366 long oldstatus, newstatus;
368 struct wait_node wait_node;
370 #if defined TEST_FOR_COMPARE_AND_SWAP
371 if (!__pthread_has_cas)
373 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
375 int suspend_needed = 0;
376 __pthread_acquire(&lock->__spinlock);
378 if (lock->__status == 0)
382 self = thread_self();
384 wait_node.abandoned = 0;
385 wait_node.next = (struct wait_node *) lock->__status;
386 wait_node.thr = self;
387 lock->__status = (long) &wait_node;
391 __pthread_release(&lock->__spinlock);
399 #if defined HAS_COMPARE_AND_SWAP
401 oldstatus = lock->__status;
402 if (oldstatus == 0) {
406 self = thread_self();
407 wait_node.thr = self;
408 newstatus = (long) &wait_node;
410 wait_node.abandoned = 0;
411 wait_node.next = (struct wait_node *) oldstatus;
412 /* Make sure the store in wait_node.next completes before performing
413 the compare-and-swap */
415 } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
417 /* Suspend. Note that unlike in __pthread_lock, we don't worry
418 here about spurious wakeup. That's because this lock is not
419 used in situations where that can happen; the restart can
420 only come from the previous lock owner. */
425 READ_MEMORY_BARRIER();
429 /* Timed-out lock operation; returns 0 to indicate timeout. */
431 int __pthread_alt_timedlock(struct _pthread_fastlock * lock,
432 pthread_descr self, const struct timespec *abstime)
435 #if defined HAS_COMPARE_AND_SWAP
438 struct wait_node *p_wait_node = wait_node_alloc();
440 /* Out of memory, just give up and do ordinary lock. */
441 if (p_wait_node == 0) {
442 __pthread_alt_lock(lock, self);
446 #if defined TEST_FOR_COMPARE_AND_SWAP
447 if (!__pthread_has_cas)
449 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
451 __pthread_acquire(&lock->__spinlock);
453 if (lock->__status == 0)
457 self = thread_self();
459 p_wait_node->abandoned = 0;
460 p_wait_node->next = (struct wait_node *) lock->__status;
461 p_wait_node->thr = self;
462 lock->__status = (long) p_wait_node;
463 oldstatus = 1; /* force suspend */
466 __pthread_release(&lock->__spinlock);
471 #if defined HAS_COMPARE_AND_SWAP
473 oldstatus = lock->__status;
474 if (oldstatus == 0) {
478 self = thread_self();
479 p_wait_node->thr = self;
480 newstatus = (long) p_wait_node;
482 p_wait_node->abandoned = 0;
483 p_wait_node->next = (struct wait_node *) oldstatus;
484 /* Make sure the store in wait_node.next completes before performing
485 the compare-and-swap */
487 } while(! __compare_and_swap(&lock->__status, oldstatus, newstatus));
490 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
494 /* If we did not get the lock, do a timed suspend. If we wake up due
495 to a timeout, then there is a race; the old lock owner may try
496 to remove us from the queue. This race is resolved by us and the owner
497 doing an atomic testandset() to change the state of the wait node from 0
498 to 1. If we succeed, then it's a timeout and we abandon the node in the
499 queue. If we fail, it means the owner gave us the lock. */
501 if (oldstatus != 0) {
502 if (timedsuspend(self, abstime) == 0) {
503 if (!testandset(&p_wait_node->abandoned))
504 return 0; /* Timeout! */
506 /* Eat oustanding resume from owner, otherwise wait_node_free() below
507 will race with owner's wait_node_dequeue(). */
512 wait_node_free(p_wait_node);
514 READ_MEMORY_BARRIER();
516 return 1; /* Got the lock! */
519 void __pthread_alt_unlock(struct _pthread_fastlock *lock)
521 struct wait_node *p_node, **pp_node, *p_max_prio, **pp_max_prio;
522 struct wait_node ** const pp_head = (struct wait_node **) &lock->__status;
525 WRITE_MEMORY_BARRIER();
527 #if defined TEST_FOR_COMPARE_AND_SWAP
528 if (!__pthread_has_cas)
530 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
532 __pthread_acquire(&lock->__spinlock);
538 /* If no threads are waiting for this lock, try to just
539 atomically release it. */
540 #if defined TEST_FOR_COMPARE_AND_SWAP
541 if (!__pthread_has_cas)
543 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
545 if (lock->__status == 0 || lock->__status == 1) {
552 #if defined TEST_FOR_COMPARE_AND_SWAP
556 #if defined HAS_COMPARE_AND_SWAP
558 long oldstatus = lock->__status;
559 if (oldstatus == 0 || oldstatus == 1) {
560 if (__compare_and_swap_with_release_semantics (&lock->__status, oldstatus, 0))
568 /* Process the entire queue of wait nodes. Remove all abandoned
569 wait nodes and put them into the global free queue, and
570 remember the one unabandoned node which refers to the thread
571 having the highest priority. */
573 pp_max_prio = pp_node = pp_head;
574 p_max_prio = p_node = *pp_head;
577 READ_MEMORY_BARRIER(); /* Prevent access to stale data through p_node */
579 while (p_node != (struct wait_node *) 1) {
582 if (p_node->abandoned) {
583 /* Remove abandoned node. */
584 #if defined TEST_FOR_COMPARE_AND_SWAP
585 if (!__pthread_has_cas)
587 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
588 *pp_node = p_node->next;
590 #if defined TEST_FOR_COMPARE_AND_SWAP
593 #if defined HAS_COMPARE_AND_SWAP
594 wait_node_dequeue(pp_head, pp_node, p_node);
596 wait_node_free(p_node);
597 /* Note that the next assignment may take us to the beginning
598 of the queue, to newly inserted nodes, if pp_node == pp_head.
599 In that case we need a memory barrier to stabilize the first of
602 if (pp_node == pp_head)
603 READ_MEMORY_BARRIER(); /* No stale reads through p_node */
605 } else if ((prio = p_node->thr->p_priority) >= maxprio) {
606 /* Otherwise remember it if its thread has a higher or equal priority
607 compared to that of any node seen thus far. */
609 pp_max_prio = pp_node;
613 /* This canno6 jump backward in the list, so no further read
614 barrier is needed. */
615 pp_node = &p_node->next;
619 /* If all threads abandoned, go back to top */
620 if (maxprio == INT_MIN)
623 /* Now we want to to remove the max priority thread's wait node from
624 the list. Before we can do this, we must atomically try to change the
625 node's abandon state from zero to nonzero. If we succeed, that means we
626 have the node that we will wake up. If we failed, then it means the
627 thread timed out and abandoned the node in which case we repeat the
628 whole unlock operation. */
630 if (!testandset(&p_max_prio->abandoned)) {
631 #if defined TEST_FOR_COMPARE_AND_SWAP
632 if (!__pthread_has_cas)
634 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
635 *pp_max_prio = p_max_prio->next;
637 #if defined TEST_FOR_COMPARE_AND_SWAP
640 #if defined HAS_COMPARE_AND_SWAP
641 wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);
643 restart(p_max_prio->thr);
648 #if defined TEST_FOR_COMPARE_AND_SWAP
649 if (!__pthread_has_cas)
651 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
653 __pthread_release(&lock->__spinlock);
659 /* Compare-and-swap emulation with a spinlock */
661 #ifdef TEST_FOR_COMPARE_AND_SWAP
662 int __pthread_has_cas = 0;
665 #if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
667 int __pthread_compare_and_swap(long * ptr, long oldval, long newval,
672 __pthread_acquire(spinlock);
674 if (*ptr == oldval) {
675 *ptr = newval; res = 1;
680 __pthread_release(spinlock);
687 /* The retry strategy is as follows:
688 - We test and set the spinlock MAX_SPIN_COUNT times, calling
689 sched_yield() each time. This gives ample opportunity for other
690 threads with priority >= our priority to make progress and
691 release the spinlock.
692 - If a thread with priority < our priority owns the spinlock,
693 calling sched_yield() repeatedly is useless, since we're preventing
694 the owning thread from making progress and releasing the spinlock.
695 So, after MAX_SPIN_LOCK attemps, we suspend the calling thread
696 using nanosleep(). This again should give time to the owning thread
697 for releasing the spinlock.
698 Notice that the nanosleep() interval must not be too small,
699 since the kernel does busy-waiting for short intervals in a realtime
700 process (!). The smallest duration that guarantees thread
701 suspension is currently 2ms.
702 - When nanosleep() returns, we try again, doing MAX_SPIN_COUNT
703 sched_yield(), then sleeping again if needed. */
705 static void __pthread_acquire(int * spinlock)
710 READ_MEMORY_BARRIER();
712 while (testandset(spinlock)) {
713 if (cnt < MAX_SPIN_COUNT) {
718 tm.tv_nsec = SPIN_SLEEP_DURATION;
719 nanosleep(&tm, NULL);