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 <string.h> 13 #include "semaphore.h" 14 #include "pthread_internal.h" 15 16 static sem_t *posix_sem_list = RT_NULL; 17 static struct rt_semaphore posix_sem_lock; 18 void posix_sem_system_init() 19 { 20 rt_sem_init(&posix_sem_lock, "psem", 1, RT_IPC_FLAG_FIFO); 21 } 22 23 rt_inline void posix_sem_insert(sem_t *psem) 24 { 25 psem->next = posix_sem_list; 26 posix_sem_list = psem; 27 } 28 29 static void posix_sem_delete(sem_t *psem) 30 { 31 sem_t *iter; 32 if (posix_sem_list == psem) 33 { 34 posix_sem_list = psem->next; 35 36 rt_sem_delete(psem->sem); 37 rt_free(psem); 38 39 return; 40 } 41 for (iter = posix_sem_list; iter->next != RT_NULL; iter = iter->next) 42 { 43 if (iter->next == psem) 44 { 45 /* delete this mq */ 46 if (psem->next != RT_NULL) 47 iter->next = psem->next; 48 else 49 iter->next = RT_NULL; 50 51 /* delete RT-Thread mqueue */ 52 rt_sem_delete(psem->sem); 53 rt_free(psem); 54 55 return ; 56 } 57 } 58 } 59 60 static sem_t *posix_sem_find(const char* name) 61 { 62 sem_t *iter; 63 rt_object_t object; 64 65 for (iter = posix_sem_list; iter != RT_NULL; iter = iter->next) 66 { 67 object = (rt_object_t)&(iter->sem); 68 69 if (strncmp(object->name, name, RT_NAME_MAX) == 0) 70 { 71 return iter; 72 } 73 } 74 75 return RT_NULL; 76 } 77 78 int sem_close(sem_t *sem) 79 { 80 if (sem == RT_NULL) 81 { 82 rt_set_errno(EINVAL); 83 84 return -1; 85 } 86 87 /* lock posix semaphore list */ 88 rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); 89 sem->refcount --; 90 if (sem->refcount == 0) 91 { 92 /* delete from posix semaphore list */ 93 if (sem->unlinked) 94 posix_sem_delete(sem); 95 sem = RT_NULL; 96 } 97 rt_sem_release(&posix_sem_lock); 98 99 return 0; 100 } 101 RTM_EXPORT(sem_close); 102 103 int sem_destroy(sem_t *sem) 104 { 105 rt_err_t result; 106 107 if ((!sem) || !(sem->unamed)) 108 { 109 rt_set_errno(EINVAL); 110 111 return -1; 112 } 113 114 /* lock posix semaphore list */ 115 rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); 116 result = rt_sem_trytake(sem->sem); 117 if (result != RT_EOK) 118 { 119 rt_sem_release(&posix_sem_lock); 120 rt_set_errno(EBUSY); 121 122 return -1; 123 } 124 125 /* destroy an unamed posix semaphore */ 126 posix_sem_delete(sem); 127 rt_sem_release(&posix_sem_lock); 128 129 return 0; 130 } 131 RTM_EXPORT(sem_destroy); 132 133 int sem_unlink(const char *name) 134 { 135 sem_t *psem; 136 137 /* lock posix semaphore list */ 138 rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); 139 psem = posix_sem_find(name); 140 if (psem != RT_NULL) 141 { 142 psem->unlinked = 1; 143 if (psem->refcount == 0) 144 { 145 /* remove this semaphore */ 146 posix_sem_delete(psem); 147 } 148 rt_sem_release(&posix_sem_lock); 149 150 return 0; 151 } 152 rt_sem_release(&posix_sem_lock); 153 154 /* no this entry */ 155 rt_set_errno(ENOENT); 156 157 return -1; 158 } 159 RTM_EXPORT(sem_unlink); 160 161 int sem_getvalue(sem_t *sem, int *sval) 162 { 163 if (!sem || !sval) 164 { 165 rt_set_errno(EINVAL); 166 167 return -1; 168 } 169 *sval = sem->sem->value; 170 171 return 0; 172 } 173 RTM_EXPORT(sem_getvalue); 174 175 int sem_init(sem_t *sem, int pshared, unsigned int value) 176 { 177 char name[RT_NAME_MAX]; 178 static rt_uint16_t psem_number = 0; 179 180 if (sem == RT_NULL) 181 { 182 rt_set_errno(EINVAL); 183 184 return -1; 185 } 186 187 rt_snprintf(name, sizeof(name), "psem%02d", psem_number++); 188 sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); 189 if (sem == RT_NULL) 190 { 191 rt_set_errno(ENOMEM); 192 193 return -1; 194 } 195 196 /* initialize posix semaphore */ 197 sem->refcount = 1; 198 sem->unlinked = 0; 199 sem->unamed = 1; 200 /* lock posix semaphore list */ 201 rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); 202 posix_sem_insert(sem); 203 rt_sem_release(&posix_sem_lock); 204 205 return 0; 206 } 207 RTM_EXPORT(sem_init); 208 209 sem_t *sem_open(const char *name, int oflag, ...) 210 { 211 sem_t* sem; 212 va_list arg; 213 mode_t mode; 214 unsigned int value; 215 216 sem = RT_NULL; 217 218 /* lock posix semaphore list */ 219 rt_sem_take(&posix_sem_lock, RT_WAITING_FOREVER); 220 if (oflag & O_CREAT) 221 { 222 va_start(arg, oflag); 223 mode = (mode_t) va_arg( arg, unsigned int); mode = mode; 224 value = va_arg( arg, unsigned int); 225 va_end(arg); 226 227 if (oflag & O_EXCL) 228 { 229 if (posix_sem_find(name) != RT_NULL) 230 { 231 rt_set_errno(EEXIST); 232 goto __return; 233 } 234 } 235 sem = (sem_t*) rt_malloc (sizeof(struct posix_sem)); 236 if (sem == RT_NULL) 237 { 238 rt_set_errno(ENFILE); 239 goto __return; 240 } 241 242 /* create RT-Thread semaphore */ 243 sem->sem = rt_sem_create(name, value, RT_IPC_FLAG_FIFO); 244 if (sem->sem == RT_NULL) /* create failed */ 245 { 246 rt_set_errno(ENFILE); 247 goto __return; 248 } 249 /* initialize reference count */ 250 sem->refcount = 1; 251 sem->unlinked = 0; 252 sem->unamed = 0; 253 254 /* insert semaphore to posix semaphore list */ 255 posix_sem_insert(sem); 256 } 257 else 258 { 259 /* find semaphore */ 260 sem = posix_sem_find(name); 261 if (sem != RT_NULL) 262 { 263 sem->refcount ++; /* increase reference count */ 264 } 265 else 266 { 267 rt_set_errno(ENOENT); 268 goto __return; 269 } 270 } 271 rt_sem_release(&posix_sem_lock); 272 273 return sem; 274 275 __return: 276 /* release lock */ 277 rt_sem_release(&posix_sem_lock); 278 279 /* release allocated memory */ 280 if (sem != RT_NULL) 281 { 282 /* delete RT-Thread semaphore */ 283 if (sem->sem != RT_NULL) 284 rt_sem_delete(sem->sem); 285 rt_free(sem); 286 } 287 288 return RT_NULL; 289 } 290 RTM_EXPORT(sem_open); 291 292 int sem_post(sem_t *sem) 293 { 294 rt_err_t result; 295 296 if (!sem) 297 { 298 rt_set_errno(EINVAL); 299 300 return -1; 301 } 302 303 result = rt_sem_release(sem->sem); 304 if (result == RT_EOK) 305 return 0; 306 307 rt_set_errno(EINVAL); 308 309 return -1; 310 } 311 RTM_EXPORT(sem_post); 312 313 int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout) 314 { 315 rt_err_t result; 316 rt_int32_t tick; 317 318 if (!sem || !abs_timeout) 319 return EINVAL; 320 321 /* calculate os tick */ 322 tick = clock_time_to_tick(abs_timeout); 323 324 result = rt_sem_take(sem->sem, tick); 325 if (result == -RT_ETIMEOUT) 326 { 327 rt_set_errno(ETIMEDOUT); 328 329 return -1; 330 } 331 if (result == RT_EOK) 332 return 0; 333 334 rt_set_errno(EINTR); 335 336 return -1; 337 } 338 RTM_EXPORT(sem_timedwait); 339 340 int sem_trywait(sem_t *sem) 341 { 342 rt_err_t result; 343 344 if (!sem) 345 { 346 rt_set_errno(EINVAL); 347 348 return -1; 349 } 350 351 result = rt_sem_take(sem->sem, 0); 352 if (result == -RT_ETIMEOUT) 353 { 354 rt_set_errno(EAGAIN); 355 356 return -1; 357 } 358 if (result == RT_EOK) 359 return 0; 360 361 rt_set_errno(EINTR); 362 363 return -1; 364 } 365 RTM_EXPORT(sem_trywait); 366 367 int sem_wait(sem_t *sem) 368 { 369 rt_err_t result; 370 371 if (!sem) 372 { 373 rt_set_errno(EINVAL); 374 375 return -1; 376 } 377 378 result = rt_sem_take(sem->sem, RT_WAITING_FOREVER); 379 if (result == RT_EOK) 380 return 0; 381 382 rt_set_errno(EINTR); 383 384 return -1; 385 } 386 RTM_EXPORT(sem_wait); 387 388