1 /*
2 * Copyright (c) 2006-2024 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 <pthread.h>
12
pthread_barrierattr_destroy(pthread_barrierattr_t * attr)13 int pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
14 {
15 if (!attr)
16 return EINVAL;
17
18 return 0;
19 }
20 RTM_EXPORT(pthread_barrierattr_destroy);
21
pthread_barrierattr_init(pthread_barrierattr_t * attr)22 int pthread_barrierattr_init(pthread_barrierattr_t *attr)
23 {
24 if (!attr)
25 return EINVAL;
26 *attr = PTHREAD_PROCESS_PRIVATE;
27
28 return 0;
29 }
30 RTM_EXPORT(pthread_barrierattr_init);
31
pthread_barrierattr_getpshared(const pthread_barrierattr_t * attr,int * pshared)32 int pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
33 int *pshared)
34 {
35 if (!attr)
36 return EINVAL;
37 *pshared = (int)*attr;
38
39 return 0;
40 }
41 RTM_EXPORT(pthread_barrierattr_getpshared);
42
pthread_barrierattr_setpshared(pthread_barrierattr_t * attr,int pshared)43 int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
44 {
45 if (!attr)
46 return EINVAL;
47 if (pshared == PTHREAD_PROCESS_PRIVATE)
48 {
49 *attr = PTHREAD_PROCESS_PRIVATE;
50 return 0;
51 }
52
53 return EINVAL;
54 }
55 RTM_EXPORT(pthread_barrierattr_setpshared);
56
57 /**
58 * @brief Destroys a barrier object.
59 *
60 * The `pthread_barrier_destroy` function releases any resources associated
61 * with the specified barrier object. After a barrier has been destroyed,
62 * it cannot be used again unless it is reinitialized using `pthread_barrier_init`.
63 *
64 * @param[in] barrier
65 * A pointer to an initialized `pthread_barrier_t` object to be destroyed.
66 *
67 * @return
68 * - `0` on success.
69 * - `EINVAL` if the `barrier` is invalid or uninitialized.
70 * - `EBUSY` if there are threads currently blocked on the barrier.
71 *
72 * @note
73 * - Ensure that no threads are blocked on the barrier before calling this function.
74 * - Attempting to destroy a barrier that is still in use results in undefined behavior.
75 *
76 * @warning
77 * Destroying a barrier without ensuring it is no longer in use can lead to
78 * resource leaks or undefined program behavior.
79 *
80 * @see pthread_barrier_init, pthread_barrier_wait
81 */
pthread_barrier_destroy(pthread_barrier_t * barrier)82 int pthread_barrier_destroy(pthread_barrier_t *barrier)
83 {
84 rt_err_t result;
85
86 if (!barrier)
87 return EINVAL;
88
89 /* Lock the internal mutex to safely check the barrier's state*/
90 result = pthread_mutex_lock(&(barrier->mutex));
91 if (result != 0)
92 return result;
93
94 /* Check if any threads are currently waiting on the barrier*/
95 if (barrier->count != 0)
96 {
97 pthread_mutex_unlock(&(barrier->mutex));
98 return EBUSY; /* Threads are still waiting*/
99 }
100
101 /* Free resources associated with the barrier*/
102 result = pthread_mutex_unlock(&(barrier->mutex));
103 if (result != 0)
104 {
105 return result; /* Return mutex unlock error*/
106 }
107
108 result = pthread_mutex_destroy(&(barrier->mutex));
109 if (result != 0)
110 {
111 return result; /* Return mutex destroy error*/
112 }
113 result = pthread_cond_destroy(&(barrier->cond));
114
115 return result;
116 }
117 RTM_EXPORT(pthread_barrier_destroy);
118
119 /**
120 * @brief Initializes a barrier for synchronizing threads.
121 *
122 * The `pthread_barrier_init` function initializes a barrier object
123 * that allows a specified number of threads to synchronize at a barrier point.
124 * Each thread waits at the barrier until the required number of threads have called
125 * `pthread_barrier_wait`.
126 *
127 * @param[out] barrier
128 * A pointer to the `pthread_barrier_t` object to be initialized.
129 * This object must not already be initialized.
130 *
131 * @param[in] attr
132 * A pointer to a `pthread_barrierattr_t` object that specifies
133 * attributes for the barrier (e.g., process-shared or process-private).
134 * If NULL, the default attributes are used.
135 *
136 * @param[in] count
137 * The number of threads that must call `pthread_barrier_wait`
138 * before any of them successfully return from the barrier.
139 *
140 * @return
141 * - `0` on success.
142 * - `EINVAL` if the `count` is zero or `barrier` is invalid.
143 *
144 * @note The barrier must be destroyed using `pthread_barrier_destroy`
145 * when it is no longer needed.
146 *
147 * @warning If `count` is set to zero, the behavior is undefined.
148 *
149 * @see pthread_barrier_wait, pthread_barrier_destroy
150 */
pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned count)151 int pthread_barrier_init(pthread_barrier_t *barrier,
152 const pthread_barrierattr_t *attr,
153 unsigned count)
154 {
155 if (!barrier)
156 return EINVAL;
157 if (attr && (*attr != PTHREAD_PROCESS_PRIVATE))
158 return EINVAL;
159 if (count == 0)
160 return EINVAL;
161
162 barrier->count = count;
163 pthread_cond_init(&(barrier->cond), NULL);
164 pthread_mutex_init(&(barrier->mutex), NULL);
165
166 return 0;
167 }
168 RTM_EXPORT(pthread_barrier_init);
169
170 /**
171 * @brief Synchronizes threads at a barrier.
172 *
173 * The `pthread_barrier_wait` function blocks the calling thread at the specified
174 * barrier until the required number of threads have reached the barrier. Once
175 * the required number of threads have called this function, all threads are
176 * unblocked and can proceed.
177 *
178 * @param[in] barrier
179 * A pointer to an initialized `pthread_barrier_t` object representing the barrier
180 * at which threads will synchronize.
181 *
182 * @return
183 * - `0` for all threads except one.
184 * - `EINVAL` - The `barrier` is invalid or uninitialized.
185 *
186 * @note
187 * - All threads participating in the barrier must call `pthread_barrier_wait`
188 * before any of them are released.
189 *
190 * @warning
191 * Ensure that the number of threads specified during the barrier's initialization
192 * matches the number of threads calling this function, otherwise the program
193 * may hang indefinitely.
194 *
195 * @see pthread_barrier_init, pthread_barrier_destroy
196 */
pthread_barrier_wait(pthread_barrier_t * barrier)197 int pthread_barrier_wait(pthread_barrier_t *barrier)
198 {
199 rt_err_t result;
200 if (!barrier)
201 return EINVAL;
202
203 result = pthread_mutex_lock(&(barrier->mutex));
204 if (result != 0)
205 return EINVAL;
206
207 if (barrier->count == 0)
208 result = EINVAL;
209 else
210 {
211 barrier->count -= 1;
212 if (barrier->count == 0) /* broadcast condition */
213 pthread_cond_broadcast(&(barrier->cond));
214 else
215 pthread_cond_wait(&(barrier->cond), &(barrier->mutex));
216 }
217
218 pthread_mutex_unlock(&(barrier->mutex));
219
220 return result;
221 }
222 RTM_EXPORT(pthread_barrier_wait);
223
224