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