pthread_mutex.c revision 1.1.2.1 1 1.1.2.1 nathanw /* Copyright */
2 1.1.2.1 nathanw
3 1.1.2.1 nathanw #include <assert.h>
4 1.1.2.1 nathanw #include <errno.h>
5 1.1.2.1 nathanw #include <signal.h>
6 1.1.2.1 nathanw #include <stdlib.h>
7 1.1.2.1 nathanw #include <ucontext.h>
8 1.1.2.1 nathanw #include <sys/queue.h>
9 1.1.2.1 nathanw
10 1.1.2.1 nathanw #include "pthread.h"
11 1.1.2.1 nathanw #include "pthread_int.h"
12 1.1.2.1 nathanw #include "pthread_mutex.h"
13 1.1.2.1 nathanw
14 1.1.2.1 nathanw
15 1.1.2.1 nathanw
16 1.1.2.1 nathanw
17 1.1.2.1 nathanw int
18 1.1.2.1 nathanw pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
19 1.1.2.1 nathanw {
20 1.1.2.1 nathanw pthread_mutex_t newmutex;
21 1.1.2.1 nathanw
22 1.1.2.1 nathanw assert(mutex != NULL);
23 1.1.2.1 nathanw
24 1.1.2.1 nathanw /* XXX No mutex attr support yet. */
25 1.1.2.1 nathanw if (attr != NULL)
26 1.1.2.1 nathanw return EINVAL;
27 1.1.2.1 nathanw
28 1.1.2.1 nathanw /* Allocate. */
29 1.1.2.1 nathanw newmutex = pthread__malloc(sizeof(struct pthread_mutex_st));
30 1.1.2.1 nathanw if (newmutex == NULL)
31 1.1.2.1 nathanw return ENOMEM;
32 1.1.2.1 nathanw
33 1.1.2.1 nathanw newmutex->ptm_magic = PT_MUTEX_MAGIC;
34 1.1.2.1 nathanw newmutex->ptm_owner = NULL;
35 1.1.2.1 nathanw SIMPLEQ_INIT(&newmutex->ptm_blocked);
36 1.1.2.1 nathanw
37 1.1.2.1 nathanw *mutex = newmutex;
38 1.1.2.1 nathanw
39 1.1.2.1 nathanw return 0;
40 1.1.2.1 nathanw }
41 1.1.2.1 nathanw
42 1.1.2.1 nathanw
43 1.1.2.1 nathanw int
44 1.1.2.1 nathanw pthread_mutex_destroy(pthread_mutex_t *mutex)
45 1.1.2.1 nathanw {
46 1.1.2.1 nathanw
47 1.1.2.1 nathanw if ((mutex == NULL) || (*mutex == NULL) ||
48 1.1.2.1 nathanw (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
49 1.1.2.1 nathanw return EINVAL;
50 1.1.2.1 nathanw
51 1.1.2.1 nathanw (*mutex)->ptm_magic = PT_MUTEX_DEAD;
52 1.1.2.1 nathanw pthread__free(*mutex);
53 1.1.2.1 nathanw
54 1.1.2.1 nathanw return 0;
55 1.1.2.1 nathanw }
56 1.1.2.1 nathanw
57 1.1.2.1 nathanw
58 1.1.2.1 nathanw int
59 1.1.2.1 nathanw pthread_mutex_lock(pthread_mutex_t *mutex)
60 1.1.2.1 nathanw {
61 1.1.2.1 nathanw pthread_t self;
62 1.1.2.1 nathanw
63 1.1.2.1 nathanw if ((mutex == NULL) || (*mutex == NULL) ||
64 1.1.2.1 nathanw (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
65 1.1.2.1 nathanw return EINVAL;
66 1.1.2.1 nathanw
67 1.1.2.1 nathanw self = pthread__self();
68 1.1.2.1 nathanw
69 1.1.2.1 nathanw pthread_spinlock(self, &(*mutex)->ptm_interlock);
70 1.1.2.1 nathanw
71 1.1.2.1 nathanw while ((*mutex)->ptm_locked == PT_MUTEX_LOCKED) {
72 1.1.2.1 nathanw /* Put ourselves on the queue and go to sleep. */
73 1.1.2.1 nathanw SIMPLEQ_INSERT_TAIL(&(*mutex)->ptm_blocked, self, pt_sleep);
74 1.1.2.1 nathanw
75 1.1.2.1 nathanw self->pt_state = PT_STATE_BLOCKED;
76 1.1.2.1 nathanw pthread__block(self, &(*mutex)->ptm_interlock);
77 1.1.2.1 nathanw
78 1.1.2.1 nathanw /* We're back. Try again. */
79 1.1.2.1 nathanw pthread_spinlock(self, &(*mutex)->ptm_interlock);
80 1.1.2.1 nathanw }
81 1.1.2.1 nathanw
82 1.1.2.1 nathanw assert((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED);
83 1.1.2.1 nathanw
84 1.1.2.1 nathanw /* We have the interlock; go for the real thing. */
85 1.1.2.1 nathanw (*mutex)->ptm_locked = PT_MUTEX_LOCKED;
86 1.1.2.1 nathanw (*mutex)->ptm_owner = self;
87 1.1.2.1 nathanw
88 1.1.2.1 nathanw pthread_spinunlock(self, &(*mutex)->ptm_interlock);
89 1.1.2.1 nathanw
90 1.1.2.1 nathanw return 0;
91 1.1.2.1 nathanw }
92 1.1.2.1 nathanw
93 1.1.2.1 nathanw
94 1.1.2.1 nathanw int
95 1.1.2.1 nathanw pthread_mutex_trylock(pthread_mutex_t *mutex)
96 1.1.2.1 nathanw {
97 1.1.2.1 nathanw pthread_t self;
98 1.1.2.1 nathanw
99 1.1.2.1 nathanw if ((mutex == NULL) || (*mutex == NULL) ||
100 1.1.2.1 nathanw (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
101 1.1.2.1 nathanw return EINVAL;
102 1.1.2.1 nathanw
103 1.1.2.1 nathanw if ((*mutex)->ptm_locked == PT_MUTEX_LOCKED)
104 1.1.2.1 nathanw return EBUSY;
105 1.1.2.1 nathanw
106 1.1.2.1 nathanw self = pthread__self();
107 1.1.2.1 nathanw
108 1.1.2.1 nathanw pthread_spinlock(self, &(*mutex)->ptm_interlock);
109 1.1.2.1 nathanw if ((*mutex)->ptm_locked == PT_MUTEX_LOCKED) {
110 1.1.2.1 nathanw pthread_spinunlock(self, &(*mutex)->ptm_interlock);
111 1.1.2.1 nathanw return EBUSY;
112 1.1.2.1 nathanw }
113 1.1.2.1 nathanw
114 1.1.2.1 nathanw assert((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED);
115 1.1.2.1 nathanw
116 1.1.2.1 nathanw /* We have the interlock; go for the real thing. */
117 1.1.2.1 nathanw (*mutex)->ptm_locked = PT_MUTEX_LOCKED;
118 1.1.2.1 nathanw (*mutex)->ptm_owner = self;
119 1.1.2.1 nathanw
120 1.1.2.1 nathanw pthread_spinunlock(self, &(*mutex)->ptm_interlock);
121 1.1.2.1 nathanw
122 1.1.2.1 nathanw return 0;
123 1.1.2.1 nathanw }
124 1.1.2.1 nathanw
125 1.1.2.1 nathanw
126 1.1.2.1 nathanw int
127 1.1.2.1 nathanw pthread_mutex_unlock(pthread_mutex_t *mutex)
128 1.1.2.1 nathanw {
129 1.1.2.1 nathanw pthread_t self, blocked;
130 1.1.2.1 nathanw
131 1.1.2.1 nathanw if ((mutex == NULL) || (*mutex == NULL) ||
132 1.1.2.1 nathanw (*mutex)->ptm_magic != PT_MUTEX_MAGIC)
133 1.1.2.1 nathanw return EINVAL;
134 1.1.2.1 nathanw
135 1.1.2.1 nathanw if ((*mutex)->ptm_locked == PT_MUTEX_UNLOCKED)
136 1.1.2.1 nathanw return EPERM; /* Not exactly the right error. */
137 1.1.2.1 nathanw
138 1.1.2.1 nathanw assert((*mutex)->ptm_locked == PT_MUTEX_LOCKED);
139 1.1.2.1 nathanw
140 1.1.2.1 nathanw /* One is only permitted to unlock one's own mutexes. */
141 1.1.2.1 nathanw self = pthread__self();
142 1.1.2.1 nathanw if ((*mutex)->ptm_owner != self)
143 1.1.2.1 nathanw return EPERM;
144 1.1.2.1 nathanw
145 1.1.2.1 nathanw pthread_spinlock(self, &(*mutex)->ptm_interlock);
146 1.1.2.1 nathanw (*mutex)->ptm_locked = PT_MUTEX_UNLOCKED;
147 1.1.2.1 nathanw (*mutex)->ptm_owner = NULL;
148 1.1.2.1 nathanw
149 1.1.2.1 nathanw blocked = SIMPLEQ_FIRST(&(*mutex)->ptm_blocked);
150 1.1.2.1 nathanw if (blocked)
151 1.1.2.1 nathanw SIMPLEQ_REMOVE_HEAD(&(*mutex)->ptm_blocked, blocked, pt_sleep);
152 1.1.2.1 nathanw
153 1.1.2.1 nathanw pthread_spinunlock(self, &(*mutex)->ptm_interlock);
154 1.1.2.1 nathanw
155 1.1.2.1 nathanw if (blocked)
156 1.1.2.1 nathanw pthread__sched(self, blocked);
157 1.1.2.1 nathanw
158 1.1.2.1 nathanw return 0;
159 1.1.2.1 nathanw }
160