blob: c1c5ca21b775c1f08e148e5a3c40e9247e8dd33a [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pj/os.h>
21#include <pj/assert.h>
22#include <pj/pool.h>
23#include <pj/log.h>
24#include <pj/except.h>
25#include <pj/errno.h>
26#include <pj/string.h>
27#include <pj/compat/high_precision.h>
28#include <pj/compat/sprintf.h>
29
30#include <linux/config.h>
31#include <linux/version.h>
32#if defined(MODVERSIONS)
33#include <linux/modversions.h>
34#endif
35#include <linux/kernel.h>
36#include <linux/sched.h>
37//#include <linux/tqueue.h>
38#include <linux/wait.h>
39#include <linux/signal.h>
40
41#include <asm/atomic.h>
42#include <asm/unistd.h>
43#include <asm/semaphore.h>
44
45#define THIS_FILE "oslinuxkern"
46
47struct pj_thread_t
48{
49 /** Thread's name. */
50 char obj_name[PJ_MAX_OBJ_NAME];
51
52 /** Linux task structure for thread. */
53 struct task_struct *thread;
54
55 /** Flags (specified in pj_thread_create) */
56 unsigned flags;
57
58 /** Task queue needed to launch thread. */
59 //struct tq_struct tq;
60
61 /** Semaphore needed to control thread startup. */
62 struct semaphore startstop_sem;
63
64 /** Semaphore to suspend thread during startup. */
65 struct semaphore suspend_sem;
66
67 /** Queue thread is waiting on. Gets initialized by
68 thread_initialize, can be used by thread itself.
69 */
70 wait_queue_head_t queue;
71
72 /** Flag to tell thread whether to die or not.
73 When the thread receives a signal, it must check
74 the value of terminate and call thread_deinitialize and terminate
75 if set.
76 */
77 int terminate;
78
79 /** Thread's entry. */
80 pj_thread_proc *func;
81
82 /** Argument. */
83 void *arg;
84};
85
86struct pj_atomic_t
87{
88 atomic_t atom;
89};
90
91struct pj_mutex_t
92{
93 struct semaphore sem;
94 pj_bool_t recursive;
95 pj_thread_t *owner;
96 int own_count;
97};
98
99struct pj_sem_t
100{
101 struct semaphore sem;
102};
103
104/*
105 * Static global variables.
106 */
107#define MAX_TLS_ID 32
108static void *tls_values[MAX_TLS_ID];
109static int tls_id;
110static long thread_tls_id;
111static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
112static unsigned long spinlock_flags;
113static pj_thread_t main_thread;
114
115/* private functions */
116//#define TRACE_(expr) PJ_LOG(3,expr)
117#define TRACE_(x)
118
119
120/* This must be called in the context of the new thread. */
121static void thread_initialize( pj_thread_t *thread )
122{
123 TRACE_((THIS_FILE, "---new thread initializing..."));
124
125 /* Set TLS */
126 pj_thread_local_set(thread_tls_id, thread);
127
128 /* fill in thread structure */
129 thread->thread = current;
130 pj_assert(thread->thread != NULL);
131
132 /* set signal mask to what we want to respond */
133 siginitsetinv(&current->blocked,
134 sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
135
136 /* initialise wait queue */
137 init_waitqueue_head(&thread->queue);
138
139 /* initialise termination flag */
140 thread->terminate = 0;
141
142 /* set name of this process (making sure obj_name is null
143 * terminated first)
144 */
145 thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
146 sprintf(current->comm, thread->obj_name);
147
148 /* tell the creator that we are ready and let him continue */
149 up(&thread->startstop_sem);
150}
151
152/* cleanup of thread. Called by the exiting thread. */
153static void thread_deinitialize(pj_thread_t *thread)
154{
155 /* we are terminating */
156
157 /* lock the kernel, the exit will unlock it */
158 thread->thread = NULL;
159 mb();
160
161 /* notify the stop_kthread() routine that we are terminating. */
162 up(&thread->startstop_sem);
163
164 /* the kernel_thread that called clone() does a do_exit here. */
165
166 /* there is no race here between execution of the "killer" and
167 real termination of the thread (race window between up and do_exit),
168 since both the thread and the "killer" function are running with
169 the kernel lock held.
170 The kernel lock will be freed after the thread exited, so the code
171 is really not executed anymore as soon as the unload functions gets
172 the kernel lock back.
173 The init process may not have made the cleanup of the process here,
174 but the cleanup can be done safely with the module unloaded.
175 */
176
177}
178
179static int thread_proc(void *arg)
180{
181 pj_thread_t *thread = arg;
182
183 TRACE_((THIS_FILE, "---new thread starting!"));
184
185 /* Initialize thread. */
186 thread_initialize( thread );
187
188 /* Wait if created suspended. */
189 if (thread->flags & PJ_THREAD_SUSPENDED) {
190 TRACE_((THIS_FILE, "---new thread suspended..."));
191 down(&thread->suspend_sem);
192 }
193
194 TRACE_((THIS_FILE, "---new thread running..."));
195
196 pj_assert(thread->func != NULL);
197
198 /* Call thread's entry. */
199 (*thread->func)(thread->arg);
200
201 TRACE_((THIS_FILE, "---thread exiting..."));
202
203 /* Cleanup thread. */
204 thread_deinitialize(thread);
205
206 return 0;
207}
208
209/* The very task entry. */
210static void kthread_launcher(void *arg)
211{
212 TRACE_((THIS_FILE, "...launching thread!..."));
213 kernel_thread(&thread_proc, arg, 0);
214}
215
216PJ_DEF(pj_status_t) pj_init(void)
217{
218 pj_status_t rc;
219
220 PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
221
222 rc = pj_thread_init();
223 if (rc != PJ_SUCCESS)
224 return rc;
225
226 /* Initialize exception ID for the pool.
227 * Must do so after critical section is configured.
228 */
229 rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
230 if (rc != PJ_SUCCESS)
231 return rc;
232
233 return PJ_SUCCESS;
234}
235
236PJ_DEF(pj_uint32_t) pj_getpid(void)
237{
238 return 1;
239}
240
241PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
242 pj_thread_desc desc,
243 pj_thread_t **ptr_thread)
244{
245 char stack_ptr;
246 pj_thread_t *thread = (pj_thread_t *)desc;
247 pj_str_t thread_name = pj_str((char*)cstr_thread_name);
248
249 /* Size sanity check. */
250 if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
251 pj_assert(!"Not enough pj_thread_desc size!");
252 return PJ_EBUG;
253 }
254
255 /* If a thread descriptor has been registered before, just return it. */
256 if (pj_thread_local_get (thread_tls_id) != 0) {
257 // 2006-02-26 bennylp:
258 // This wouldn't work in all cases!.
259 // If thread is created by external module (e.g. sound thread),
260 // thread may be reused while the pool used for the thread descriptor
261 // has been deleted by application.
262 //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
263 //return PJ_SUCCESS;
264 }
265
266 /* Initialize and set the thread entry. */
267 pj_bzero(desc, sizeof(struct pj_thread_t));
268
269 if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
270 pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
271 else
272 pj_snprintf(thread->obj_name, sizeof(thread->obj_name),
273 "thr%p", (void*)thread->thread);
274
275 /* Initialize. */
276 thread_initialize(thread);
277
278 /* Eat semaphore. */
279 down(&thread->startstop_sem);
280
281#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
282 thread->stk_start = &stack_ptr;
283 thread->stk_size = 0xFFFFFFFFUL;
284 thread->stk_max_usage = 0;
285#else
286 stack_ptr = '\0';
287#endif
288
289 *ptr_thread = thread;
290 return PJ_SUCCESS;
291}
292
293
294pj_status_t pj_thread_init(void)
295{
296 pj_status_t rc;
297 pj_thread_t *dummy;
298
299 rc = pj_thread_local_alloc(&thread_tls_id);
300 if (rc != PJ_SUCCESS)
301 return rc;
302
303 return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
304}
305
306PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
307 pj_thread_proc *proc, void *arg,
308 pj_size_t stack_size, unsigned flags,
309 pj_thread_t **ptr_thread)
310{
311 pj_thread_t *thread;
312
313 TRACE_((THIS_FILE, "pj_thread_create()"));
314
315 PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
316
317 thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
318 if (!thread)
319 return PJ_ENOMEM;
320
321 PJ_UNUSED_ARG(stack_size);
322
323 /* Thread name. */
324 if (!thread_name)
325 thread_name = "thr%p";
326
327 if (strchr(thread_name, '%')) {
328 pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
329 } else {
330 strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
331 thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
332 }
333
334 /* Init thread's semaphore. */
335 TRACE_((THIS_FILE, "...init semaphores..."));
336 init_MUTEX_LOCKED(&thread->startstop_sem);
337 init_MUTEX_LOCKED(&thread->suspend_sem);
338
339 thread->flags = flags;
340
341 if ((flags & PJ_THREAD_SUSPENDED) == 0) {
342 up(&thread->suspend_sem);
343 }
344
345 /* Store the functions and argument. */
346 thread->func = proc;
347 thread->arg = arg;
348
349 /* Save return value. */
350 *ptr_thread = thread;
351
352 /* Create the new thread by running a task through keventd. */
353
354#if 0
355 /* Initialize the task queue struct. */
356 thread->tq.sync = 0;
357 INIT_LIST_HEAD(&thread->tq.list);
358 thread->tq.routine = kthread_launcher;
359 thread->tq.data = thread;
360
361 /* and schedule it for execution. */
362 schedule_task(&thread->tq);
363#endif
364 kthread_launcher(thread);
365
366 /* Wait until thread has reached the setup_thread routine. */
367 TRACE_((THIS_FILE, "...wait for the new thread..."));
368 down(&thread->startstop_sem);
369
370 TRACE_((THIS_FILE, "...main thread resumed..."));
371 return PJ_SUCCESS;
372}
373
374PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
375{
376 return thread->obj_name;
377}
378
379PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
380{
381 up(&thread->suspend_sem);
382 return PJ_SUCCESS;
383}
384
385PJ_DEF(pj_thread_t*) pj_thread_this(void)
386{
387 return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
388}
389
390PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
391{
392 TRACE_((THIS_FILE, "pj_thread_join()"));
393 down(&p->startstop_sem);
394 TRACE_((THIS_FILE, " joined!"));
395 return PJ_SUCCESS;
396}
397
398PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
399{
400 PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
401 return PJ_SUCCESS;
402}
403
404PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
405{
406 pj_highprec_t ticks;
407 pj_thread_t *thread = pj_thread_this();
408
409 PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
410
411 /* Use high precision calculation to make sure we don't
412 * crop values:
413 *
414 * ticks = HZ * msec / 1000
415 */
416 ticks = HZ;
417 pj_highprec_mul(ticks, msec);
418 pj_highprec_div(ticks, 1000);
419
420 TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
421 interruptible_sleep_on_timeout( &thread->queue, ticks);
422 return PJ_SUCCESS;
423}
424
425
426///////////////////////////////////////////////////////////////////////////////
427PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
428 pj_atomic_value_t value,
429 pj_atomic_t **ptr_var)
430{
431 pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
432 if (!t) return PJ_ENOMEM;
433
434 atomic_set(&t->atom, value);
435 *ptr_var = t;
436
437 return PJ_SUCCESS;
438}
439
440PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
441{
442 return PJ_SUCCESS;
443}
444
445PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
446{
447 atomic_set(&var->atom, value);
448}
449
450PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
451{
452 return atomic_read(&var->atom);
453}
454
455PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
456{
457 atomic_inc(&var->atom);
458}
459
460PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
461{
462 atomic_dec(&var->atom);
463}
464
465PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
466{
467 atomic_add(value, &var->atom);
468}
469
470
471///////////////////////////////////////////////////////////////////////////////
472PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
473{
474 if (tls_id >= MAX_TLS_ID)
475 return PJ_ETOOMANY;
476
477 *index = tls_id++;
478
479 return PJ_SUCCESS;
480}
481
482PJ_DEF(void) pj_thread_local_free(long index)
483{
484 pj_assert(index >= 0 && index < MAX_TLS_ID);
485}
486
487PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
488{
489 pj_assert(index >= 0 && index < MAX_TLS_ID);
490 tls_values[index] = value;
491 return PJ_SUCCESS;
492}
493
494PJ_DEF(void*) pj_thread_local_get(long index)
495{
496 pj_assert(index >= 0 && index < MAX_TLS_ID);
497 return tls_values[index];
498}
499
500
501///////////////////////////////////////////////////////////////////////////////
502PJ_DEF(void) pj_enter_critical_section(void)
503{
504 spin_lock_irqsave(&critical_section, spinlock_flags);
505}
506
507PJ_DEF(void) pj_leave_critical_section(void)
508{
509 spin_unlock_irqrestore(&critical_section, spinlock_flags);
510}
511
512
513///////////////////////////////////////////////////////////////////////////////
514PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
515 const char *name,
516 int type,
517 pj_mutex_t **ptr_mutex)
518{
519 pj_mutex_t *mutex;
520
521 PJ_UNUSED_ARG(name);
522
523 mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
524 if (!mutex)
525 return PJ_ENOMEM;
526
527 init_MUTEX(&mutex->sem);
528
529 mutex->recursive = (type == PJ_MUTEX_RECURSE);
530 mutex->owner = NULL;
531 mutex->own_count = 0;
532
533 /* Done. */
534 *ptr_mutex = mutex;
535 return PJ_SUCCESS;
536}
537
538PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
539 pj_mutex_t **mutex )
540{
541 return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
542}
543
544PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
545 const char *name,
546 pj_mutex_t **mutex )
547{
548 return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
549}
550
551PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
552{
553 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
554
555 if (mutex->recursive) {
556 pj_thread_t *this_thread = pj_thread_this();
557 if (mutex->owner == this_thread) {
558 ++mutex->own_count;
559 } else {
560 down(&mutex->sem);
561 pj_assert(mutex->own_count == 0);
562 mutex->owner = this_thread;
563 mutex->own_count = 1;
564 }
565 } else {
566 down(&mutex->sem);
567 }
568 return PJ_SUCCESS;
569}
570
571PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
572{
573 long rc;
574
575 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
576
577 if (mutex->recursive) {
578 pj_thread_t *this_thread = pj_thread_this();
579 if (mutex->owner == this_thread) {
580 ++mutex->own_count;
581 } else {
582 rc = down_interruptible(&mutex->sem);
583 if (rc != 0)
584 return PJ_RETURN_OS_ERROR(-rc);
585 pj_assert(mutex->own_count == 0);
586 mutex->owner = this_thread;
587 mutex->own_count = 1;
588 }
589 } else {
590 int rc = down_trylock(&mutex->sem);
591 if (rc != 0)
592 return PJ_RETURN_OS_ERROR(-rc);
593 }
594 return PJ_SUCCESS;
595}
596
597PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
598{
599 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
600
601 if (mutex->recursive) {
602 pj_thread_t *this_thread = pj_thread_this();
603 if (mutex->owner == this_thread) {
604 pj_assert(mutex->own_count > 0);
605 --mutex->own_count;
606 if (mutex->own_count == 0) {
607 mutex->owner = NULL;
608 up(&mutex->sem);
609 }
610 } else {
611 pj_assert(!"Not owner!");
612 return PJ_EINVALIDOP;
613 }
614 } else {
615 up(&mutex->sem);
616 }
617 return PJ_SUCCESS;
618}
619
620PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
621{
622 PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
623
624 return PJ_SUCCESS;
625}
626
627#if defined(PJ_DEBUG) && PJ_DEBUG != 0
628PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
629{
630 if (mutex->recursive)
631 return mutex->owner == pj_thread_this();
632 else
633 return 1;
634}
635#endif /* PJ_DEBUG */
636
637
638#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
639
640PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
641 const char *name,
642 unsigned initial,
643 unsigned max,
644 pj_sem_t **sem)
645{
646 pj_sem_t *sem;
647
648 PJ_UNUSED_ARG(max);
649
650 PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
651
652 sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
653 sema_init(&sem->sem, initial);
654 return PJ_SUCCESS;
655}
656
657PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
658{
659 PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
660
661 down(&sem->sem);
662 return PJ_SUCCESS;
663}
664
665PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
666{
667 int rc;
668
669 PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
670
671 rc = down_trylock(&sem->sem);
672 if (rc != 0) {
673 return PJ_RETURN_OS_ERROR(-rc);
674 } else {
675 return PJ_SUCCESS;
676 }
677}
678
679PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
680{
681 PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
682
683 up(&sem->sem);
684 return PJ_SUCCESS;
685}
686
687PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
688{
689 PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
690
691 return PJ_SUCCESS;
692}
693
694#endif /* PJ_HAS_SEMAPHORE */
695
696
697
698