Home | History | Annotate | Line # | Download | only in libpthread
pthread_lock.c revision 1.1.2.1
      1 /* Copyright */
      2 
      3 #include <assert.h>
      4 #include <errno.h>
      5 #include <signal.h>
      6 #include <stdlib.h>
      7 #include <ucontext.h>
      8 #include <sys/queue.h>
      9 
     10 #include "pthread.h"
     11 #include "pthread_int.h"
     12 
     13 /* How many times to try before checking whether we've been continued. */
     14 #define NSPINS 20	/* XXX arbitrary */
     15 
     16 static int nspins = NSPINS;
     17 
     18 void
     19 pthread_spinlock(pthread_t thread, pt_spin_t *lock)
     20 {
     21 	int count, ret;
     22 
     23 	count = nspins;
     24 	++thread->pt_spinlocks;
     25 
     26 	do {
     27 		while (((ret = __cpu_simple_lock_try(lock)) == 0) && --count)
     28 			;
     29 
     30 		if (ret == 1)
     31 			break;
     32 
     33 		--thread->pt_spinlocks;
     34 
     35 		/* We may be preempted while spinning. If so, we will
     36 		 * be restarted here if thread->pt_spinlocks is
     37 		 * nonzero, which can happen if:
     38 		 * a) we just got the lock
     39 		 * b) we haven't yet decremented the lock count.
     40 		 * If we're at this point, (b) applies. Therefore,
     41 		 * check if we're being continued, and if so, bail.
     42 		 * (in case (a), we should let the code finish and
     43 		 * we will bail out in pthread_spinunlock()).
     44 		 */
     45 		if (thread->pt_next != NULL) {
     46 			PTHREADD_ADD(PTHREADD_SPINPREEMPT);
     47 			pthread__switch(thread, thread->pt_next, 0);
     48 		}
     49 		/* try again */
     50 		count = nspins;
     51 		++thread->pt_spinlocks;
     52 	} while (/*CONSTCOND*/1);
     53 
     54 	PTHREADD_ADD(PTHREADD_SPINLOCKS);
     55 	/* Got it! We're out of here. */
     56 }
     57 
     58 
     59 int
     60 pthread_spintrylock(pthread_t thread, pt_spin_t *lock)
     61 {
     62 	int ret;
     63 
     64 	++thread->pt_spinlocks;
     65 
     66 	ret = __cpu_simple_lock_try(lock);
     67 
     68 	if (ret == 0) {
     69 		--thread->pt_spinlocks;
     70 		/* See above. */
     71 		if (thread->pt_next != NULL) {
     72 			PTHREADD_ADD(PTHREADD_SPINPREEMPT);
     73 			pthread__switch(thread, thread->pt_next, 0);
     74 		}
     75 	}
     76 
     77 	return ret;
     78 }
     79 
     80 
     81 void
     82 pthread_spinunlock(pthread_t thread, pt_spin_t *lock)
     83 {
     84 	__cpu_simple_unlock(lock);
     85 	--thread->pt_spinlocks;
     86 
     87 	PTHREADD_ADD(PTHREADD_SPINUNLOCKS);
     88 
     89 	/* If we were preempted while holding a spinlock, the
     90 	 * scheduler will notice this and continue us. To be good
     91 	 * citzens, we must now get out of here if that was our
     92 	 * last spinlock.
     93 	 * XXX when will we ever have more than one?
     94 	 */
     95 
     96 	if ((thread->pt_spinlocks == 0) && (thread->pt_next != NULL)) {
     97 		PTHREADD_ADD(PTHREADD_SPINPREEMPT);
     98 		pthread__switch(thread, thread->pt_next, 0);
     99 	}
    100 }
    101 
    102