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