pthread_mutex.c revision 1.1.2.2 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
14 int
15 pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
16 {
17
18 assert(mutex != NULL);
19
20 /* XXX No mutex attr support yet. */
21 if (attr != NULL)
22 return EINVAL;
23
24 /* Allocate. */
25
26 mutex->ptm_magic = PT_MUTEX_MAGIC;
27 mutex->ptm_owner = NULL;
28 pthread_lockinit(&mutex->ptm_lock);
29 pthread_lockinit(&mutex->ptm_interlock);
30 PTQ_INIT(&mutex->ptm_blocked);
31
32 return 0;
33 }
34
35
36 int
37 pthread_mutex_destroy(pthread_mutex_t *mutex)
38 {
39
40 assert(mutex != NULL);
41 assert(mutex->ptm_lock == __SIMPLELOCK_UNLOCKED);
42
43 mutex->ptm_magic = PT_MUTEX_DEAD;
44
45 return 0;
46 }
47
48
49 /*
50 * Note regarding memory visibility: Pthreads has rules about memory
51 * visibility and mutexes. Very roughly: Memory a thread can see when
52 * it unlocks a mutex can be seen by another thread that locks the
53 * same mutex.
54 *
55 * A memory barrier after a lock and before an unlock will provide
56 * this behavior. This code relies on __cpu_simple_lock_try() to issue
57 * a barrier after obtaining a lock, and on __cpu_simple_unlock() to
58 * issue a barrier before releasing a lock.
59 */
60
61 int
62 pthread_mutex_lock(pthread_mutex_t *mutex)
63 {
64 pthread_t self;
65 #ifdef ERRORCHECK
66 if ((mutex == NULL) || (mutex->ptm_magic != PT_MUTEX_MAGIC))
67 return EINVAL;
68 #endif
69
70 while (/*CONSTCOND*/1) {
71 if (__cpu_simple_lock_try(&mutex->ptm_lock))
72 break; /* got it! */
73
74 self = pthread__self();
75 /* Okay, didn't look free. Get the interlock... */
76 pthread_spinlock(self, &mutex->ptm_interlock);
77 /* The mutex_unlock routine will get the interlock
78 * before looking at the list of sleepers, so if the
79 * lock is held we can safely put ourselves on the
80 * sleep queue. If it's not held, we can try taking it
81 * again.
82 */
83 if (mutex->ptm_lock == __SIMPLELOCK_LOCKED) {
84 PTQ_INSERT_TAIL(&mutex->ptm_blocked, self, pt_sleep);
85 self->pt_state = PT_STATE_BLOCKED;
86 pthread__block(self, &mutex->ptm_interlock);
87 /* interlock is not held when we return */
88 } else {
89 pthread_spinunlock(self, &mutex->ptm_interlock);
90 }
91 /* Go around for another try. */
92 }
93
94 /* We have the lock! */
95 #ifdef ERRORCHECK
96 mutex->ptm_owner = self;
97 #endif
98 return 0;
99 }
100
101
102 int
103 pthread_mutex_trylock(pthread_mutex_t *mutex)
104 {
105
106 #ifdef ERRORCHECK
107 if ((mutex == NULL) || (mutex->ptm_magic != PT_MUTEX_MAGIC))
108 return EINVAL;
109 #endif
110
111 if (__cpu_simple_lock_try(&mutex->ptm_lock) == 0)
112 return EBUSY;
113
114 #ifdef ERRORCHECK
115 mutex->ptm_owner = pthread__self();
116 #endif
117 return 0;
118 }
119
120
121 int
122 pthread_mutex_unlock(pthread_mutex_t *mutex)
123 {
124 pthread_t self, blocked;
125 struct pt_queue_t blockedq, nullq = PTQ_HEAD_INITIALIZER;
126
127 #ifdef ERRORCHECK
128 if ((mutex == NULL) || (mutex->ptm_magic != PT_MUTEX_MAGIC))
129 return EINVAL;
130
131 if (mutex->ptm_lock != __SIMPLELOCK_LOCKED)
132 return EPERM; /* Not exactly the right error. */
133
134 /* One is only permitted to unlock one's own mutexes. */
135 if (mutex->ptm_owner != self)
136 return EPERM;
137 #endif
138
139 self = pthread__self();
140 pthread_spinlock(self, &mutex->ptm_interlock);
141 blockedq = mutex->ptm_blocked;
142 mutex->ptm_blocked = nullq;
143 #ifdef ERRORCHECK
144 mutex->ptm_owner = NULL;
145 #endif
146 __cpu_simple_unlock(&mutex->ptm_lock);
147 pthread_spinunlock(self, &mutex->ptm_interlock);
148
149 /* Give everyone on the sleep queue another chance at the lock. */
150 PTQ_FOREACH(blocked, &blockedq, pt_sleep)
151 pthread__sched(self, blocked);
152
153 return 0;
154 }
155