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