1 /*
2 * Copyright (c) 2006-2018, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2010-10-26 Bernard the first version
9 */
10
11 #include <rtthread.h>
12 #include "pthread.h"
13
14 #define MUTEXATTR_SHARED_MASK 0x0010
15 #define MUTEXATTR_TYPE_MASK 0x000f
16
17 const pthread_mutexattr_t pthread_default_mutexattr = PTHREAD_PROCESS_PRIVATE;
18
pthread_mutexattr_init(pthread_mutexattr_t * attr)19 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
20 {
21 if (attr)
22 {
23 *attr = pthread_default_mutexattr;
24
25 return 0;
26 }
27
28 return EINVAL;
29 }
30 RTM_EXPORT(pthread_mutexattr_init);
31
pthread_mutexattr_destroy(pthread_mutexattr_t * attr)32 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
33 {
34 if (attr)
35 {
36 *attr = -1;
37
38 return 0;
39 }
40
41 return EINVAL;
42 }
43 RTM_EXPORT(pthread_mutexattr_destroy);
44
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * type)45 int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
46 {
47 if (attr && type)
48 {
49 int atype = (*attr & MUTEXATTR_TYPE_MASK);
50
51 if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK)
52 {
53 *type = atype;
54
55 return 0;
56 }
57 }
58
59 return EINVAL;
60 }
61 RTM_EXPORT(pthread_mutexattr_gettype);
62
pthread_mutexattr_settype(pthread_mutexattr_t * attr,int type)63 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
64 {
65 if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK)
66 {
67 *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type;
68
69 return 0;
70 }
71
72 return EINVAL;
73 }
74 RTM_EXPORT(pthread_mutexattr_settype);
75
pthread_mutexattr_setpshared(pthread_mutexattr_t * attr,int pshared)76 int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
77 {
78 if (!attr)
79 return EINVAL;
80
81 switch (pshared)
82 {
83 case PTHREAD_PROCESS_PRIVATE:
84 *attr &= ~MUTEXATTR_SHARED_MASK;
85 return 0;
86
87 case PTHREAD_PROCESS_SHARED:
88 *attr |= MUTEXATTR_SHARED_MASK;
89 return 0;
90 }
91
92 return EINVAL;
93 }
94 RTM_EXPORT(pthread_mutexattr_setpshared);
95
pthread_mutexattr_getpshared(pthread_mutexattr_t * attr,int * pshared)96 int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared)
97 {
98 if (!attr || !pshared)
99 return EINVAL;
100
101 *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED
102 : PTHREAD_PROCESS_PRIVATE;
103 return 0;
104 }
105 RTM_EXPORT(pthread_mutexattr_getpshared);
106
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)107 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
108 {
109 rt_err_t result;
110 char name[RT_NAME_MAX];
111 static rt_uint16_t pthread_mutex_number = 0;
112
113 if (!mutex)
114 return EINVAL;
115
116 /* build mutex name */
117 rt_snprintf(name, sizeof(name), "pmtx%02d", pthread_mutex_number ++);
118 if (attr == RT_NULL)
119 mutex->attr = pthread_default_mutexattr;
120 else
121 mutex->attr = *attr;
122
123 /* init mutex lock */
124 result = rt_mutex_init(&(mutex->lock), name, RT_IPC_FLAG_FIFO);
125 if (result != RT_EOK)
126 return EINVAL;
127
128 /* detach the object from system object container */
129 rt_object_detach(&(mutex->lock.parent.parent));
130 mutex->lock.parent.parent.type = RT_Object_Class_Mutex;
131
132 return 0;
133 }
134 RTM_EXPORT(pthread_mutex_init);
135
pthread_mutex_destroy(pthread_mutex_t * mutex)136 int pthread_mutex_destroy(pthread_mutex_t *mutex)
137 {
138 if (!mutex || mutex->attr == -1)
139 return EINVAL;
140
141 /* it's busy */
142 if (mutex->lock.owner != RT_NULL)
143 return EBUSY;
144
145 rt_memset(mutex, 0, sizeof(pthread_mutex_t));
146 mutex->attr = -1;
147
148 return 0;
149 }
150 RTM_EXPORT(pthread_mutex_destroy);
151
pthread_mutex_lock(pthread_mutex_t * mutex)152 int pthread_mutex_lock(pthread_mutex_t *mutex)
153 {
154 int mtype;
155 rt_err_t result;
156
157 if (!mutex)
158 return EINVAL;
159
160 if (mutex->attr == -1)
161 {
162 /* init mutex */
163 pthread_mutex_init(mutex, RT_NULL);
164 }
165
166 mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
167 rt_enter_critical();
168 if (mutex->lock.owner == rt_thread_self() &&
169 mtype != PTHREAD_MUTEX_RECURSIVE)
170 {
171 rt_exit_critical();
172
173 return EDEADLK;
174 }
175 rt_exit_critical();
176
177 result = rt_mutex_take(&(mutex->lock), RT_WAITING_FOREVER);
178 if (result == RT_EOK)
179 return 0;
180
181 return EINVAL;
182 }
183 RTM_EXPORT(pthread_mutex_lock);
184
pthread_mutex_unlock(pthread_mutex_t * mutex)185 int pthread_mutex_unlock(pthread_mutex_t *mutex)
186 {
187 rt_err_t result;
188
189 if (!mutex)
190 return EINVAL;
191 if (mutex->attr == -1)
192 {
193 /* init mutex */
194 pthread_mutex_init(mutex, RT_NULL);
195 }
196
197 if (mutex->lock.owner != rt_thread_self())
198 {
199 int mtype;
200 mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
201
202 /* error check, return EPERM */
203 if (mtype == PTHREAD_MUTEX_ERRORCHECK)
204 return EPERM;
205
206 /* no thread waiting on this mutex */
207 if (mutex->lock.owner == RT_NULL)
208 return 0;
209 }
210
211 result = rt_mutex_release(&(mutex->lock));
212 if (result == RT_EOK)
213 return 0;
214
215 return EINVAL;
216 }
217 RTM_EXPORT(pthread_mutex_unlock);
218
pthread_mutex_trylock(pthread_mutex_t * mutex)219 int pthread_mutex_trylock(pthread_mutex_t *mutex)
220 {
221 rt_err_t result;
222 int mtype;
223
224 if (!mutex)
225 return EINVAL;
226 if (mutex->attr == -1)
227 {
228 /* init mutex */
229 pthread_mutex_init(mutex, RT_NULL);
230 }
231
232 mtype = mutex->attr & MUTEXATTR_TYPE_MASK;
233 rt_enter_critical();
234 if (mutex->lock.owner == rt_thread_self() &&
235 mtype != PTHREAD_MUTEX_RECURSIVE)
236 {
237 rt_exit_critical();
238
239 return EDEADLK;
240 }
241 rt_exit_critical();
242
243 result = rt_mutex_take(&(mutex->lock), 0);
244 if (result == RT_EOK) return 0;
245
246 return EBUSY;
247 }
248 RTM_EXPORT(pthread_mutex_trylock);
249