| 1 | /* |
| 2 | Copyright (c) 2012, Broadcom Europe Ltd |
| 3 | All rights reserved. |
| 4 | |
| 5 | Redistribution and use in source and binary forms, with or without |
| 6 | modification, are permitted provided that the following conditions are met: |
| 7 | * Redistributions of source code must retain the above copyright |
| 8 | notice, this list of conditions and the following disclaimer. |
| 9 | * Redistributions in binary form must reproduce the above copyright |
| 10 | notice, this list of conditions and the following disclaimer in the |
| 11 | documentation and/or other materials provided with the distribution. |
| 12 | * Neither the name of the copyright holder nor the |
| 13 | names of its contributors may be used to endorse or promote products |
| 14 | derived from this software without specific prior written permission. |
| 15 | |
| 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
| 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | /*============================================================================= |
| 29 | VideoCore OS Abstraction Layer - pthreads types |
| 30 | =============================================================================*/ |
| 31 | |
| 32 | /* DO NOT include this file directly - instead include it via vcos.h */ |
| 33 | |
| 34 | /** @file |
| 35 | * |
| 36 | * Pthreads implementation of VCOS. |
| 37 | * |
| 38 | */ |
| 39 | |
| 40 | #ifndef VCOS_PLATFORM_H |
| 41 | #define VCOS_PLATFORM_H |
| 42 | |
| 43 | #ifdef __cplusplus |
| 44 | extern "C" { |
| 45 | #endif |
| 46 | |
| 47 | #include <pthread.h> |
| 48 | #include <semaphore.h> |
| 49 | #include <unistd.h> |
| 50 | #include <sys/types.h> |
| 51 | #include <sched.h> |
| 52 | #include <errno.h> |
| 53 | #include <unistd.h> |
| 54 | #include <string.h> |
| 55 | #include <strings.h> |
| 56 | #include <time.h> |
| 57 | #include <signal.h> |
| 58 | #include <stddef.h> |
| 59 | #include <stdlib.h> |
| 60 | #include <dlfcn.h> |
| 61 | |
| 62 | |
| 63 | #define VCOS_HAVE_RTOS 1 |
| 64 | #define VCOS_HAVE_SEMAPHORE 1 |
| 65 | #define VCOS_HAVE_EVENT 1 |
| 66 | #define VCOS_HAVE_QUEUE 0 |
| 67 | #define VCOS_HAVE_LEGACY_ISR 0 |
| 68 | #define VCOS_HAVE_TIMER 1 |
| 69 | #define VCOS_HAVE_CANCELLATION_SAFE_TIMER 1 |
| 70 | #define VCOS_HAVE_MEMPOOL 0 |
| 71 | #define VCOS_HAVE_ISR 0 |
| 72 | #define VCOS_HAVE_ATOMIC_FLAGS 1 |
| 73 | #define VCOS_HAVE_THREAD_AT_EXIT 1 |
| 74 | #define VCOS_HAVE_ONCE 1 |
| 75 | #define VCOS_HAVE_BLOCK_POOL 1 |
| 76 | #define VCOS_HAVE_FILE 0 |
| 77 | #define VCOS_HAVE_PROC 0 |
| 78 | #define VCOS_HAVE_CFG 0 |
| 79 | #define VCOS_HAVE_ALIEN_THREADS 1 |
| 80 | #define VCOS_HAVE_CMD 1 |
| 81 | #define VCOS_HAVE_EVENT_FLAGS 1 |
| 82 | #define VCOS_WANT_LOG_CMD 0 /* User apps should do their own thing */ |
| 83 | |
| 84 | #define VCOS_ALWAYS_WANT_LOGGING |
| 85 | |
| 86 | #ifdef __linux__ |
| 87 | #define VCOS_HAVE_BACKTRACE 1 |
| 88 | #endif |
| 89 | |
| 90 | #define VCOS_SO_EXT ".so" |
| 91 | |
| 92 | /* Linux/pthreads seems to have different timer characteristics */ |
| 93 | #define VCOS_TIMER_MARGIN_EARLY 0 |
| 94 | #define VCOS_TIMER_MARGIN_LATE 15 |
| 95 | |
| 96 | typedef sem_t VCOS_SEMAPHORE_T; |
| 97 | typedef uint32_t VCOS_UNSIGNED; |
| 98 | typedef uint32_t VCOS_OPTION; |
| 99 | typedef pthread_key_t VCOS_TLS_KEY_T; |
| 100 | typedef pthread_once_t VCOS_ONCE_T; |
| 101 | |
| 102 | typedef struct VCOS_LLTHREAD_T |
| 103 | { |
| 104 | pthread_t thread; // Must be first field. |
| 105 | } VCOS_LLTHREAD_T; |
| 106 | |
| 107 | /* VCOS_CASSERT(offsetof(VCOS_LLTHREAD_T, thread) == 0); */ |
| 108 | |
| 109 | #ifndef VCOS_USE_VCOS_FUTEX |
| 110 | typedef pthread_mutex_t VCOS_MUTEX_T; |
| 111 | #else |
| 112 | #include "vcos_futex_mutex.h" |
| 113 | #endif /* VCOS_USE_VCOS_FUTEX */ |
| 114 | |
| 115 | typedef struct |
| 116 | { |
| 117 | VCOS_MUTEX_T mutex; |
| 118 | sem_t sem; |
| 119 | } VCOS_EVENT_T; |
| 120 | |
| 121 | #define VCOS_ONCE_INIT PTHREAD_ONCE_INIT |
| 122 | |
| 123 | typedef struct VCOS_TIMER_T |
| 124 | { |
| 125 | pthread_t thread; /**< id of the timer thread */ |
| 126 | |
| 127 | pthread_mutex_t lock; /**< lock protecting all other members of the struct */ |
| 128 | pthread_cond_t settings_changed; /**< cond. var. for informing the timer thread about changes*/ |
| 129 | int quit; /**< non-zero if the timer thread is requested to quit*/ |
| 130 | |
| 131 | struct timespec expires; /**< absolute time of next expiration, or 0 if disarmed*/ |
| 132 | |
| 133 | void (*orig_expiration_routine)(void*);/**< the expiration routine provided by the user of the timer*/ |
| 134 | void *orig_context; /**< the context for exp. routine provided by the user*/ |
| 135 | |
| 136 | } VCOS_TIMER_T; |
| 137 | |
| 138 | /** Thread attribute structure. Don't use pthread_attr directly, as |
| 139 | * the calls can fail, and inits must match deletes. |
| 140 | */ |
| 141 | typedef struct VCOS_THREAD_ATTR_T |
| 142 | { |
| 143 | void *ta_stackaddr; |
| 144 | VCOS_UNSIGNED ta_stacksz; |
| 145 | VCOS_UNSIGNED ta_priority; |
| 146 | VCOS_UNSIGNED ta_affinity; |
| 147 | VCOS_UNSIGNED ta_timeslice; |
| 148 | VCOS_UNSIGNED legacy; |
| 149 | } VCOS_THREAD_ATTR_T; |
| 150 | |
| 151 | /** Called at thread exit. |
| 152 | */ |
| 153 | typedef struct VCOS_THREAD_EXIT_T |
| 154 | { |
| 155 | void (*pfn)(void *); |
| 156 | void *cxt; |
| 157 | } VCOS_THREAD_EXIT_T; |
| 158 | #define VCOS_MAX_EXIT_HANDLERS 4 |
| 159 | |
| 160 | typedef struct VCOS_THREAD_T |
| 161 | { |
| 162 | pthread_t thread; /**< The thread itself */ |
| 163 | VCOS_THREAD_ENTRY_FN_T entry; /**< The thread entry point */ |
| 164 | void *arg; /**< The argument to be passed to entry */ |
| 165 | VCOS_SEMAPHORE_T suspend; /**< For support event groups and similar - a per thread semaphore */ |
| 166 | |
| 167 | VCOS_TIMER_T task_timer; |
| 168 | int task_timer_created; /**< non-zero if the task timer has already been created*/ |
| 169 | void (*orig_task_timer_expiration_routine)(void*); |
| 170 | void *orig_task_timer_context; |
| 171 | |
| 172 | VCOS_UNSIGNED legacy; |
| 173 | char name[16]; /**< Record the name of this thread, for diagnostics */ |
| 174 | VCOS_UNSIGNED dummy; /**< Dummy thread created for non-vcos created threads */ |
| 175 | |
| 176 | /** Callback invoked at thread exit time */ |
| 177 | VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS]; |
| 178 | } VCOS_THREAD_T; |
| 179 | |
| 180 | #ifdef VCOS_PTHREADS_WANT_HISR_EMULATION |
| 181 | |
| 182 | typedef struct |
| 183 | { |
| 184 | VCOS_THREAD_T thread; |
| 185 | char stack[1024]; |
| 186 | VCOS_SEMAPHORE_T waitsem; |
| 187 | } VCOS_HISR_T; |
| 188 | |
| 189 | #endif |
| 190 | |
| 191 | #define VCOS_SUSPEND -1 |
| 192 | #define VCOS_NO_SUSPEND 0 |
| 193 | |
| 194 | #define VCOS_START 1 |
| 195 | #define VCOS_NO_START 0 |
| 196 | |
| 197 | #define VCOS_THREAD_PRI_MIN (sched_get_priority_min(SCHED_OTHER)) |
| 198 | #define VCOS_THREAD_PRI_MAX (sched_get_priority_max(SCHED_OTHER)) |
| 199 | |
| 200 | #define VCOS_THREAD_PRI_INCREASE (1) |
| 201 | #define VCOS_THREAD_PRI_HIGHEST VCOS_THREAD_PRI_MAX |
| 202 | #define VCOS_THREAD_PRI_LOWEST VCOS_THREAD_PRI_MIN |
| 203 | #define VCOS_THREAD_PRI_NORMAL ((VCOS_THREAD_PRI_MAX+VCOS_THREAD_PRI_MIN)/2) |
| 204 | #define VCOS_THREAD_PRI_BELOW_NORMAL (VCOS_THREAD_PRI_NORMAL-VCOS_THREAD_PRI_INCREASE) |
| 205 | #define VCOS_THREAD_PRI_ABOVE_NORMAL (VCOS_THREAD_PRI_NORMAL+VCOS_THREAD_PRI_INCREASE) |
| 206 | #define VCOS_THREAD_PRI_REALTIME VCOS_THREAD_PRI_MAX |
| 207 | |
| 208 | #define _VCOS_AFFINITY_DEFAULT 0 |
| 209 | #define _VCOS_AFFINITY_CPU0 0x100 |
| 210 | #define _VCOS_AFFINITY_CPU1 0x200 |
| 211 | #define _VCOS_AFFINITY_MASK 0x300 |
| 212 | #define VCOS_CAN_SET_STACK_ADDR 0 |
| 213 | |
| 214 | #define VCOS_TICKS_PER_SECOND _vcos_get_ticks_per_second() |
| 215 | |
| 216 | #include "interface/vcos/generic/vcos_generic_event_flags.h" |
| 217 | #include "interface/vcos/generic/vcos_generic_blockpool.h" |
| 218 | #include "interface/vcos/generic/vcos_mem_from_malloc.h" |
| 219 | |
| 220 | /** Convert errno values into the values recognized by vcos */ |
| 221 | VCOSPRE_ VCOS_STATUS_T vcos_pthreads_map_error(int error); |
| 222 | VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_pthreads_map_errno(void); |
| 223 | |
| 224 | /** Register a function to be called when the current thread exits. |
| 225 | */ |
| 226 | extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt); |
| 227 | |
| 228 | extern uint32_t _vcos_get_ticks_per_second(void); |
| 229 | |
| 230 | /** |
| 231 | * Set to 1 by default when ANDROID is defined. Allows runtime |
| 232 | * switching for console apps. |
| 233 | */ |
| 234 | extern int vcos_use_android_log; |
| 235 | |
| 236 | typedef struct { |
| 237 | VCOS_MUTEX_T mutex; |
| 238 | uint32_t flags; |
| 239 | } VCOS_ATOMIC_FLAGS_T; |
| 240 | |
| 241 | #if defined(VCOS_INLINE_BODIES) |
| 242 | |
| 243 | #undef VCOS_ASSERT_LOGGING_DISABLE |
| 244 | #define VCOS_ASSERT_LOGGING_DISABLE 1 |
| 245 | |
| 246 | |
| 247 | /* |
| 248 | * Counted Semaphores |
| 249 | */ |
| 250 | VCOS_INLINE_IMPL |
| 251 | VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) { |
| 252 | int ret; |
| 253 | /* gdb causes sem_wait() to EINTR when a breakpoint is hit, retry here */ |
| 254 | while ((ret = sem_wait(sem)) == -1 && errno == EINTR) |
| 255 | continue; |
| 256 | vcos_assert(ret==0); |
| 257 | return VCOS_SUCCESS; |
| 258 | } |
| 259 | |
| 260 | VCOS_INLINE_IMPL |
| 261 | VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem) { |
| 262 | int ret; |
| 263 | while ((ret = sem_trywait(sem)) == -1 && errno == EINTR) |
| 264 | continue; |
| 265 | if (ret == 0) |
| 266 | return VCOS_SUCCESS; |
| 267 | else if (errno == EAGAIN) |
| 268 | return VCOS_EAGAIN; |
| 269 | else { |
| 270 | vcos_assert(0); |
| 271 | return VCOS_EINVAL; |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | /** |
| 276 | * \brief Wait on a semaphore with a timeout. |
| 277 | * |
| 278 | * Note that this function may not be implemented on all |
| 279 | * platforms, and may not be efficient on all platforms |
| 280 | * (see comment in vcos_semaphore_wait) |
| 281 | * |
| 282 | * Try to obtain the semaphore. If it is already taken, return |
| 283 | * VCOS_EAGAIN. |
| 284 | * @param sem Semaphore to wait on |
| 285 | * @param timeout Number of milliseconds to wait before |
| 286 | * returning if the semaphore can't be acquired. |
| 287 | * @return VCOS_SUCCESS - semaphore was taken. |
| 288 | * VCOS_EAGAIN - could not take semaphore (i.e. timeout |
| 289 | * expired) |
| 290 | * VCOS_EINVAL - Some other error (most likely bad |
| 291 | * parameters). |
| 292 | */ |
| 293 | VCOS_INLINE_IMPL |
| 294 | VCOS_STATUS_T vcos_semaphore_wait_timeout(VCOS_SEMAPHORE_T *sem, VCOS_UNSIGNED timeout) { |
| 295 | struct timespec ts; |
| 296 | int ret; |
| 297 | if (clock_gettime(CLOCK_REALTIME, &ts) == -1) |
| 298 | return VCOS_EINVAL; |
| 299 | ts.tv_sec += timeout/1000; |
| 300 | ts.tv_nsec += (timeout%1000)*1000*1000; |
| 301 | if (ts.tv_nsec > 1000000000) { |
| 302 | ts.tv_sec++; |
| 303 | ts.tv_nsec -= 1000000000; |
| 304 | } |
| 305 | |
| 306 | while (1) { |
| 307 | ret = sem_timedwait( sem, &ts ); |
| 308 | if (ret == 0) { |
| 309 | return VCOS_SUCCESS; |
| 310 | } else { |
| 311 | if (errno == EINTR) { |
| 312 | continue; |
| 313 | } else if (errno == ETIMEDOUT) { |
| 314 | return VCOS_EAGAIN; |
| 315 | } else { |
| 316 | vcos_assert(0); |
| 317 | return VCOS_EINVAL; |
| 318 | } |
| 319 | } |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | VCOS_INLINE_IMPL |
| 324 | VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, |
| 325 | const char *name, |
| 326 | VCOS_UNSIGNED initial_count) { |
| 327 | int rc = sem_init(sem, 0, initial_count); |
| 328 | (void)name; |
| 329 | if (rc != -1) return VCOS_SUCCESS; |
| 330 | else return vcos_pthreads_map_errno(); |
| 331 | } |
| 332 | |
| 333 | VCOS_INLINE_IMPL |
| 334 | void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) { |
| 335 | int rc = sem_destroy(sem); |
| 336 | vcos_assert(rc != -1); |
| 337 | (void)rc; |
| 338 | } |
| 339 | |
| 340 | VCOS_INLINE_IMPL |
| 341 | VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) { |
| 342 | int rc = sem_post(sem); |
| 343 | vcos_assert(rc == 0); |
| 344 | (void)rc; |
| 345 | return VCOS_SUCCESS; |
| 346 | } |
| 347 | |
| 348 | /*********************************************************** |
| 349 | * |
| 350 | * Threads |
| 351 | * |
| 352 | ***********************************************************/ |
| 353 | |
| 354 | |
| 355 | extern VCOS_THREAD_T *vcos_dummy_thread_create(void); |
| 356 | extern pthread_key_t _vcos_thread_current_key; |
| 357 | extern uint64_t vcos_getmicrosecs64_internal(void); |
| 358 | |
| 359 | VCOS_INLINE_IMPL |
| 360 | uint32_t vcos_getmicrosecs(void) { return (uint32_t)vcos_getmicrosecs64_internal(); } |
| 361 | |
| 362 | VCOS_INLINE_IMPL |
| 363 | uint64_t vcos_getmicrosecs64(void) { return vcos_getmicrosecs64_internal(); } |
| 364 | |
| 365 | VCOS_INLINE_IMPL |
| 366 | VCOS_THREAD_T *vcos_thread_current(void) { |
| 367 | void *ret = pthread_getspecific(_vcos_thread_current_key); |
| 368 | if (ret == NULL) |
| 369 | { |
| 370 | ret = vcos_dummy_thread_create(); |
| 371 | } |
| 372 | |
| 373 | #ifdef __cplusplus |
| 374 | return static_cast<VCOS_THREAD_T*>(ret); |
| 375 | #else |
| 376 | return (VCOS_THREAD_T *)ret; |
| 377 | #endif |
| 378 | } |
| 379 | |
| 380 | VCOS_INLINE_IMPL |
| 381 | void vcos_sleep(uint32_t ms) { |
| 382 | struct timespec ts; |
| 383 | ts.tv_sec = ms/1000; |
| 384 | ts.tv_nsec = ms % 1000 * (1000000); |
| 385 | nanosleep(&ts, NULL); |
| 386 | } |
| 387 | |
| 388 | VCOS_INLINE_IMPL |
| 389 | void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attr, void *addr, VCOS_UNSIGNED sz) { |
| 390 | attr->ta_stackaddr = addr; |
| 391 | attr->ta_stacksz = sz; |
| 392 | } |
| 393 | |
| 394 | VCOS_INLINE_IMPL |
| 395 | void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attr, VCOS_UNSIGNED sz) { |
| 396 | attr->ta_stacksz = sz; |
| 397 | } |
| 398 | |
| 399 | VCOS_INLINE_IMPL |
| 400 | void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attr, VCOS_UNSIGNED pri) { |
| 401 | (void)attr; |
| 402 | (void)pri; |
| 403 | } |
| 404 | |
| 405 | VCOS_INLINE_IMPL |
| 406 | void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) { |
| 407 | /* not implemented */ |
| 408 | (void)thread; |
| 409 | (void)p; |
| 410 | } |
| 411 | |
| 412 | VCOS_INLINE_IMPL |
| 413 | VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) { |
| 414 | /* not implemented */ |
| 415 | (void)thread; |
| 416 | return 0; |
| 417 | } |
| 418 | |
| 419 | VCOS_INLINE_IMPL |
| 420 | void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity) { |
| 421 | /* not implemented */ |
| 422 | vcos_unused(thread); |
| 423 | vcos_unused(affinity); |
| 424 | } |
| 425 | |
| 426 | |
| 427 | VCOS_INLINE_IMPL |
| 428 | void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) { |
| 429 | attrs->ta_affinity = affinity; |
| 430 | } |
| 431 | |
| 432 | VCOS_INLINE_IMPL |
| 433 | void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) { |
| 434 | attrs->ta_timeslice = ts; |
| 435 | } |
| 436 | |
| 437 | VCOS_INLINE_IMPL |
| 438 | void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) { |
| 439 | attrs->legacy = legacy; |
| 440 | } |
| 441 | |
| 442 | VCOS_INLINE_IMPL |
| 443 | void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) { |
| 444 | (void)attrs; |
| 445 | (void)autostart; |
| 446 | } |
| 447 | |
| 448 | VCOS_INLINE_IMPL |
| 449 | VCOS_LLTHREAD_T *vcos_llthread_current(void) { |
| 450 | return (VCOS_LLTHREAD_T *)pthread_self(); |
| 451 | } |
| 452 | |
| 453 | VCOS_INLINE_IMPL |
| 454 | VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread) { |
| 455 | vcos_unused(thread); |
| 456 | return _VCOS_AFFINITY_CPU0; |
| 457 | } |
| 458 | |
| 459 | VCOS_INLINE_IMPL |
| 460 | int vcos_thread_running(VCOS_THREAD_T *thread) { |
| 461 | vcos_unused(thread); |
| 462 | /* Not applicable to pthreads */ |
| 463 | return 0; |
| 464 | } |
| 465 | |
| 466 | VCOS_INLINE_IMPL |
| 467 | VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe) { |
| 468 | vcos_unused(pe); |
| 469 | /* Nothing to do */ |
| 470 | return 0; |
| 471 | } |
| 472 | |
| 473 | VCOS_INLINE_IMPL |
| 474 | void vcos_thread_relinquish(void) { |
| 475 | /* Nothing to do */ |
| 476 | } |
| 477 | |
| 478 | VCOS_INLINE_IMPL |
| 479 | void vcos_thread_resume(VCOS_THREAD_T *thread) { |
| 480 | vcos_unused(thread); |
| 481 | /* Nothing to do */ |
| 482 | } |
| 483 | |
| 484 | |
| 485 | /* |
| 486 | * Mutexes |
| 487 | */ |
| 488 | |
| 489 | #ifndef VCOS_USE_VCOS_FUTEX |
| 490 | |
| 491 | VCOS_INLINE_IMPL |
| 492 | VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) { |
| 493 | int rc = pthread_mutex_init(latch, NULL); |
| 494 | (void)name; |
| 495 | if (rc == 0) return VCOS_SUCCESS; |
| 496 | else return vcos_pthreads_map_errno(); |
| 497 | } |
| 498 | |
| 499 | VCOS_INLINE_IMPL |
| 500 | void vcos_mutex_delete(VCOS_MUTEX_T *latch) { |
| 501 | int rc = pthread_mutex_destroy(latch); |
| 502 | (void)rc; |
| 503 | vcos_assert(rc==0); |
| 504 | } |
| 505 | |
| 506 | VCOS_INLINE_IMPL |
| 507 | VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) { |
| 508 | int rc = pthread_mutex_lock(latch); |
| 509 | vcos_assert(rc==0); |
| 510 | (void)rc; |
| 511 | return VCOS_SUCCESS; |
| 512 | } |
| 513 | |
| 514 | VCOS_INLINE_IMPL |
| 515 | void vcos_mutex_unlock(VCOS_MUTEX_T *latch) { |
| 516 | int rc = pthread_mutex_unlock(latch); |
| 517 | (void)rc; |
| 518 | vcos_assert(rc==0); |
| 519 | } |
| 520 | |
| 521 | VCOS_INLINE_IMPL |
| 522 | int vcos_mutex_is_locked(VCOS_MUTEX_T *m) { |
| 523 | int rc = pthread_mutex_trylock(m); |
| 524 | if (rc == 0) { |
| 525 | pthread_mutex_unlock(m); |
| 526 | /* it wasn't locked */ |
| 527 | return 0; |
| 528 | } |
| 529 | else { |
| 530 | return 1; /* it was locked */ |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | VCOS_INLINE_IMPL |
| 535 | VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) { |
| 536 | int rc = pthread_mutex_trylock(m); |
| 537 | (void)rc; |
| 538 | return (rc == 0) ? VCOS_SUCCESS : VCOS_EAGAIN; |
| 539 | } |
| 540 | |
| 541 | #endif /* VCOS_USE_VCOS_FUTEX */ |
| 542 | |
| 543 | /* |
| 544 | * Events |
| 545 | */ |
| 546 | |
| 547 | VCOS_INLINE_IMPL |
| 548 | VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name) |
| 549 | { |
| 550 | VCOS_STATUS_T status; |
| 551 | |
| 552 | int rc = sem_init(&event->sem, 0, 0); |
| 553 | if (rc != 0) return vcos_pthreads_map_errno(); |
| 554 | |
| 555 | status = vcos_mutex_create(&event->mutex, debug_name); |
| 556 | if (status != VCOS_SUCCESS) { |
| 557 | sem_destroy(&event->sem); |
| 558 | return status; |
| 559 | } |
| 560 | |
| 561 | return VCOS_SUCCESS; |
| 562 | } |
| 563 | |
| 564 | VCOS_INLINE_IMPL |
| 565 | void vcos_event_signal(VCOS_EVENT_T *event) |
| 566 | { |
| 567 | int ok = 0; |
| 568 | int value; |
| 569 | |
| 570 | if (vcos_mutex_lock(&event->mutex) != VCOS_SUCCESS) |
| 571 | goto fail_mtx; |
| 572 | |
| 573 | if (sem_getvalue(&event->sem, &value) != 0) |
| 574 | goto fail_sem; |
| 575 | |
| 576 | if (value == 0) |
| 577 | if (sem_post(&event->sem) != 0) |
| 578 | goto fail_sem; |
| 579 | |
| 580 | ok = 1; |
| 581 | fail_sem: |
| 582 | vcos_mutex_unlock(&event->mutex); |
| 583 | fail_mtx: |
| 584 | if (!ok) |
| 585 | vcos_assert(ok); |
| 586 | } |
| 587 | |
| 588 | VCOS_INLINE_IMPL |
| 589 | VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event) |
| 590 | { |
| 591 | int ret; |
| 592 | /* gdb causes sem_wait() to EINTR when a breakpoint is hit, retry here */ |
| 593 | while ((ret = sem_wait(&event->sem)) == -1 && errno == EINTR) |
| 594 | continue; |
| 595 | vcos_assert(ret==0); |
| 596 | return ret == 0 ? VCOS_SUCCESS : (VCOS_STATUS_T)errno; |
| 597 | } |
| 598 | |
| 599 | VCOS_INLINE_IMPL |
| 600 | VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event) |
| 601 | { |
| 602 | int ret; |
| 603 | while ((ret = sem_trywait(&event->sem)) == -1 && errno == EINTR) |
| 604 | continue; |
| 605 | |
| 606 | if (ret == -1 && errno == EAGAIN) |
| 607 | return VCOS_EAGAIN; |
| 608 | else |
| 609 | return VCOS_SUCCESS; |
| 610 | } |
| 611 | |
| 612 | VCOS_INLINE_IMPL |
| 613 | void vcos_event_delete(VCOS_EVENT_T *event) |
| 614 | { |
| 615 | int rc = sem_destroy(&event->sem); |
| 616 | vcos_assert(rc != -1); |
| 617 | (void)rc; |
| 618 | |
| 619 | vcos_mutex_delete(&event->mutex); |
| 620 | } |
| 621 | |
| 622 | VCOS_INLINE_IMPL |
| 623 | VCOS_UNSIGNED vcos_process_id_current(void) { |
| 624 | return (VCOS_UNSIGNED) getpid(); |
| 625 | } |
| 626 | |
| 627 | VCOS_INLINE_IMPL |
| 628 | int vcos_strcasecmp(const char *s1, const char *s2) { |
| 629 | return strcasecmp(s1,s2); |
| 630 | } |
| 631 | |
| 632 | VCOS_INLINE_IMPL |
| 633 | int vcos_strncasecmp(const char *s1, const char *s2, size_t n) { |
| 634 | return strncasecmp(s1,s2,n); |
| 635 | } |
| 636 | |
| 637 | VCOS_INLINE_IMPL |
| 638 | int vcos_in_interrupt(void) { |
| 639 | return 0; |
| 640 | } |
| 641 | |
| 642 | /* For support event groups - per thread semaphore */ |
| 643 | VCOS_INLINE_IMPL |
| 644 | void _vcos_thread_sem_wait(void) { |
| 645 | VCOS_THREAD_T *t = vcos_thread_current(); |
| 646 | vcos_semaphore_wait(&t->suspend); |
| 647 | } |
| 648 | |
| 649 | VCOS_INLINE_IMPL |
| 650 | void _vcos_thread_sem_post(VCOS_THREAD_T *target) { |
| 651 | vcos_semaphore_post(&target->suspend); |
| 652 | } |
| 653 | |
| 654 | VCOS_INLINE_IMPL |
| 655 | VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) { |
| 656 | int st = pthread_key_create(key, NULL); |
| 657 | return st == 0 ? VCOS_SUCCESS: VCOS_ENOMEM; |
| 658 | } |
| 659 | |
| 660 | VCOS_INLINE_IMPL |
| 661 | void vcos_tls_delete(VCOS_TLS_KEY_T tls) { |
| 662 | pthread_key_delete(tls); |
| 663 | } |
| 664 | |
| 665 | VCOS_INLINE_IMPL |
| 666 | VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) { |
| 667 | pthread_setspecific(tls, v); |
| 668 | return VCOS_SUCCESS; |
| 669 | } |
| 670 | |
| 671 | VCOS_INLINE_IMPL |
| 672 | void *vcos_tls_get(VCOS_TLS_KEY_T tls) { |
| 673 | return pthread_getspecific(tls); |
| 674 | } |
| 675 | |
| 676 | /*********************************************************** |
| 677 | * |
| 678 | * Timers |
| 679 | * |
| 680 | ***********************************************************/ |
| 681 | |
| 682 | //Other platforms can call compatible OS implementations directly |
| 683 | //from inline functions with minimal overhead. |
| 684 | //Pthreads needs a little bit more, so call functions |
| 685 | //in vcos_pthreads.c from the inline functions. |
| 686 | VCOS_STATUS_T vcos_pthreads_timer_create(VCOS_TIMER_T *timer, |
| 687 | const char *name, |
| 688 | void (*expiration_routine)(void *context), |
| 689 | void *context); |
| 690 | void vcos_pthreads_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms); |
| 691 | void vcos_pthreads_timer_cancel(VCOS_TIMER_T *timer); |
| 692 | void vcos_pthreads_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms); |
| 693 | void vcos_pthreads_timer_delete(VCOS_TIMER_T *timer); |
| 694 | |
| 695 | /** Create a timer. |
| 696 | * |
| 697 | * Note that we just cast the expiry function - this assumes that UNSIGNED |
| 698 | * and VOID* are the same size. |
| 699 | */ |
| 700 | |
| 701 | |
| 702 | VCOS_INLINE_IMPL |
| 703 | VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer, |
| 704 | const char *name, |
| 705 | void (*expiration_routine)(void *context), |
| 706 | void *context) { |
| 707 | return vcos_pthreads_timer_create(timer, name, expiration_routine, context); |
| 708 | } |
| 709 | |
| 710 | VCOS_INLINE_IMPL |
| 711 | void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) { |
| 712 | return vcos_pthreads_timer_set(timer, delay_ms); |
| 713 | } |
| 714 | |
| 715 | VCOS_INLINE_IMPL |
| 716 | void vcos_timer_cancel(VCOS_TIMER_T *timer) { |
| 717 | return vcos_pthreads_timer_cancel(timer); |
| 718 | } |
| 719 | |
| 720 | VCOS_INLINE_IMPL |
| 721 | void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay) { |
| 722 | vcos_timer_set(timer, delay); |
| 723 | } |
| 724 | |
| 725 | VCOS_INLINE_IMPL |
| 726 | void vcos_timer_delete(VCOS_TIMER_T *timer) { |
| 727 | vcos_pthreads_timer_delete(timer); |
| 728 | } |
| 729 | |
| 730 | #if VCOS_HAVE_ATOMIC_FLAGS |
| 731 | |
| 732 | /* |
| 733 | * Atomic flags |
| 734 | */ |
| 735 | |
| 736 | /* TODO implement properly... */ |
| 737 | |
| 738 | VCOS_INLINE_IMPL |
| 739 | VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 740 | { |
| 741 | atomic_flags->flags = 0; |
| 742 | return vcos_mutex_create(&atomic_flags->mutex, "VCOS_ATOMIC_FLAGS_T" ); |
| 743 | } |
| 744 | |
| 745 | VCOS_INLINE_IMPL |
| 746 | void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags) |
| 747 | { |
| 748 | vcos_mutex_lock(&atomic_flags->mutex); |
| 749 | atomic_flags->flags |= flags; |
| 750 | vcos_mutex_unlock(&atomic_flags->mutex); |
| 751 | } |
| 752 | |
| 753 | VCOS_INLINE_IMPL |
| 754 | uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 755 | { |
| 756 | uint32_t flags; |
| 757 | vcos_mutex_lock(&atomic_flags->mutex); |
| 758 | flags = atomic_flags->flags; |
| 759 | atomic_flags->flags = 0; |
| 760 | vcos_mutex_unlock(&atomic_flags->mutex); |
| 761 | return flags; |
| 762 | } |
| 763 | |
| 764 | VCOS_INLINE_IMPL |
| 765 | void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags) |
| 766 | { |
| 767 | vcos_mutex_delete(&atomic_flags->mutex); |
| 768 | } |
| 769 | |
| 770 | #endif |
| 771 | |
| 772 | #ifdef VCOS_PTHREADS_WANT_HISR_EMULATION |
| 773 | VCOS_STATUS_T vcos_legacy_hisr_create(VCOS_HISR_T *hisr, const char *name, |
| 774 | void (*entry)(void), |
| 775 | VCOS_UNSIGNED pri, |
| 776 | void *stack, VCOS_UNSIGNED stack_size); |
| 777 | |
| 778 | void vcos_legacy_hisr_activate(VCOS_HISR_T *hisr); |
| 779 | |
| 780 | void vcos_legacy_hisr_delete(VCOS_HISR_T *hisr); |
| 781 | |
| 782 | #endif |
| 783 | |
| 784 | #undef VCOS_ASSERT_LOGGING_DISABLE |
| 785 | #define VCOS_ASSERT_LOGGING_DISABLE 0 |
| 786 | |
| 787 | #endif /* VCOS_INLINE_BODIES */ |
| 788 | |
| 789 | #define vcos_log_platform_init() _vcos_log_platform_init() |
| 790 | VCOSPRE_ void VCOSPOST_ _vcos_log_platform_init(void); |
| 791 | |
| 792 | VCOS_INLINE_DECL void _vcos_thread_sem_wait(void); |
| 793 | VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *); |
| 794 | |
| 795 | #define VCOS_APPLICATION_ARGC vcos_get_argc() |
| 796 | #define VCOS_APPLICATION_ARGV vcos_get_argv() |
| 797 | |
| 798 | #include "interface/vcos/generic/vcos_generic_reentrant_mtx.h" |
| 799 | #include "interface/vcos/generic/vcos_generic_named_sem.h" |
| 800 | #include "interface/vcos/generic/vcos_generic_quickslow_mutex.h" |
| 801 | #include "interface/vcos/generic/vcos_common.h" |
| 802 | |
| 803 | #define _VCOS_LOG_LEVEL() getenv("VC_LOGLEVEL") |
| 804 | |
| 805 | VCOS_STATIC_INLINE |
| 806 | char *vcos_strdup(const char *str) |
| 807 | { |
| 808 | size_t len = strlen(str) + 1; |
| 809 | void *p = malloc(len); |
| 810 | |
| 811 | if (p == NULL) |
| 812 | return NULL; |
| 813 | |
| 814 | return (char *)memcpy(p, str, len); |
| 815 | } |
| 816 | |
| 817 | typedef void (*VCOS_ISR_HANDLER_T)(VCOS_UNSIGNED vecnum); |
| 818 | |
| 819 | #define VCOS_DL_LAZY RTLD_LAZY |
| 820 | #define VCOS_DL_NOW RTLD_NOW |
| 821 | #define VCOS_DL_LOCAL RTLD_LOCAL |
| 822 | #define VCOS_DL_GLOBAL RTLD_GLOBAL |
| 823 | |
| 824 | #ifdef __cplusplus |
| 825 | } |
| 826 | #endif |
| 827 | #endif /* VCOS_PLATFORM_H */ |
| 828 | |
| 829 | |