xref: /nrf52832-nimble/rt-thread/components/libc/pthreads/pthread_mutex.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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