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 | |