diff options
Diffstat (limited to 'pjlib/src/pj/os_core_linux_kernel.c')
-rw-r--r-- | pjlib/src/pj/os_core_linux_kernel.c | 1369 |
1 files changed, 695 insertions, 674 deletions
diff --git a/pjlib/src/pj/os_core_linux_kernel.c b/pjlib/src/pj/os_core_linux_kernel.c index 14337087..2bb2acfd 100644 --- a/pjlib/src/pj/os_core_linux_kernel.c +++ b/pjlib/src/pj/os_core_linux_kernel.c @@ -1,674 +1,695 @@ -/* $Id$ - * - */ -#include <pj/os.h> -#include <pj/assert.h> -#include <pj/pool.h> -#include <pj/log.h> -#include <pj/except.h> -#include <pj/errno.h> -#include <pj/string.h> -#include <pj/compat/high_precision.h> -#include <pj/compat/sprintf.h> - -#include <linux/config.h> -#include <linux/version.h> -#if defined(MODVERSIONS) -#include <linux/modversions.h> -#endif -#include <linux/kernel.h> -#include <linux/sched.h> -//#include <linux/tqueue.h> -#include <linux/wait.h> -#include <linux/signal.h> - -#include <asm/atomic.h> -#include <asm/unistd.h> -#include <asm/semaphore.h> - -#define THIS_FILE "oslinuxkern" - -struct pj_thread_t -{ - /** Thread's name. */ - char obj_name[PJ_MAX_OBJ_NAME]; - - /** Linux task structure for thread. */ - struct task_struct *thread; - - /** Flags (specified in pj_thread_create) */ - unsigned flags; - - /** Task queue needed to launch thread. */ - //struct tq_struct tq; - - /** Semaphore needed to control thread startup. */ - struct semaphore startstop_sem; - - /** Semaphore to suspend thread during startup. */ - struct semaphore suspend_sem; - - /** Queue thread is waiting on. Gets initialized by - thread_initialize, can be used by thread itself. - */ - wait_queue_head_t queue; - - /** Flag to tell thread whether to die or not. - When the thread receives a signal, it must check - the value of terminate and call thread_deinitialize and terminate - if set. - */ - int terminate; - - /** Thread's entry. */ - pj_thread_proc *func; - - /** Argument. */ - void *arg; -}; - -struct pj_atomic_t -{ - atomic_t atom; -}; - -struct pj_mutex_t -{ - struct semaphore sem; - pj_bool_t recursive; - pj_thread_t *owner; - int own_count; -}; - -struct pj_sem_t -{ - struct semaphore sem; -}; - -/* - * Static global variables. - */ -#define MAX_TLS_ID 32 -static void *tls_values[MAX_TLS_ID]; -static int tls_id; -static long thread_tls_id; -static spinlock_t critical_section = SPIN_LOCK_UNLOCKED; -static unsigned long spinlock_flags; -static pj_thread_t main_thread; - -/* private functions */ -//#define TRACE_(expr) PJ_LOG(3,expr) -#define TRACE_(x) - - -/* This must be called in the context of the new thread. */ -static void thread_initialize( pj_thread_t *thread ) -{ - TRACE_((THIS_FILE, "---new thread initializing...")); - - /* Set TLS */ - pj_thread_local_set(thread_tls_id, thread); - - /* fill in thread structure */ - thread->thread = current; - pj_assert(thread->thread != NULL); - - /* set signal mask to what we want to respond */ - siginitsetinv(¤t->blocked, - sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)); - - /* initialise wait queue */ - init_waitqueue_head(&thread->queue); - - /* initialise termination flag */ - thread->terminate = 0; - - /* set name of this process (max 15 chars + 0 !) */ - thread->obj_name[15] = '\0'; - sprintf(current->comm, thread->obj_name); - - /* tell the creator that we are ready and let him continue */ - up(&thread->startstop_sem); -} - -/* cleanup of thread. Called by the exiting thread. */ -static void thread_deinitialize(pj_thread_t *thread) -{ - /* we are terminating */ - - /* lock the kernel, the exit will unlock it */ - thread->thread = NULL; - mb(); - - /* notify the stop_kthread() routine that we are terminating. */ - up(&thread->startstop_sem); - - /* the kernel_thread that called clone() does a do_exit here. */ - - /* there is no race here between execution of the "killer" and - real termination of the thread (race window between up and do_exit), - since both the thread and the "killer" function are running with - the kernel lock held. - The kernel lock will be freed after the thread exited, so the code - is really not executed anymore as soon as the unload functions gets - the kernel lock back. - The init process may not have made the cleanup of the process here, - but the cleanup can be done safely with the module unloaded. - */ - -} - -static int thread_proc(void *arg) -{ - pj_thread_t *thread = arg; - - TRACE_((THIS_FILE, "---new thread starting!")); - - /* Initialize thread. */ - thread_initialize( thread ); - - /* Wait if created suspended. */ - if (thread->flags & PJ_THREAD_SUSPENDED) { - TRACE_((THIS_FILE, "---new thread suspended...")); - down(&thread->suspend_sem); - } - - TRACE_((THIS_FILE, "---new thread running...")); - - pj_assert(thread->func != NULL); - - /* Call thread's entry. */ - (*thread->func)(thread->arg); - - TRACE_((THIS_FILE, "---thread exiting...")); - - /* Cleanup thread. */ - thread_deinitialize(thread); - - return 0; -} - -/* The very task entry. */ -static void kthread_launcher(void *arg) -{ - TRACE_((THIS_FILE, "...launching thread!...")); - kernel_thread(&thread_proc, arg, 0); -} - -PJ_DEF(pj_status_t) pj_init(void) -{ - pj_status_t rc; - - PJ_LOG(5, ("pj_init", "Initializing PJ Library..")); - - rc = pj_thread_init(); - if (rc != PJ_SUCCESS) - return rc; - - /* Initialize exception ID for the pool. - * Must do so after critical section is configured. - */ - rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION); - if (rc != PJ_SUCCESS) - return rc; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_uint32_t) pj_getpid(void) -{ - return 1; -} - -PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, - pj_thread_desc desc, - pj_thread_t **ptr_thread) -{ - char stack_ptr; - pj_thread_t *thread = (pj_thread_t *)desc; - pj_str_t thread_name = pj_str((char*)cstr_thread_name); - - /* Size sanity check. */ - if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) { - pj_assert(!"Not enough pj_thread_desc size!"); - return PJ_EBUG; - } - - /* If a thread descriptor has been registered before, just return it. */ - if (pj_thread_local_get (thread_tls_id) != 0) { - *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id); - return PJ_SUCCESS; - } - - /* Initialize and set the thread entry. */ - pj_memset(desc, 0, sizeof(struct pj_thread_t)); - - if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) - pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread); - else - pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread); - - /* Initialize. */ - thread_initialize(thread); - - /* Eat semaphore. */ - down(&thread->startstop_sem); - -#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 - thread->stk_start = &stack_ptr; - thread->stk_size = 0xFFFFFFFFUL; - thread->stk_max_usage = 0; -#else - stack_ptr = '\0'; -#endif - - *ptr_thread = thread; - return PJ_SUCCESS; -} - - -pj_status_t pj_thread_init(void) -{ - pj_status_t rc; - pj_thread_t *dummy; - - rc = pj_thread_local_alloc(&thread_tls_id); - if (rc != PJ_SUCCESS) - return rc; - - return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy); -} - -PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name, - pj_thread_proc *proc, void *arg, - pj_size_t stack_size, unsigned flags, - pj_thread_t **ptr_thread) -{ - pj_thread_t *thread; - - TRACE_((THIS_FILE, "pj_thread_create()")); - - PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); - - thread = pj_pool_zalloc(pool, sizeof(pj_thread_t)); - if (!thread) - return PJ_ENOMEM; - - PJ_UNUSED_ARG(stack_size); - - /* Thread name. */ - if (!thread_name) - thread_name = "thr%p"; - - if (strchr(thread_name, '%')) { - pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread); - } else { - strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME); - thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; - } - - /* Init thread's semaphore. */ - TRACE_((THIS_FILE, "...init semaphores...")); - init_MUTEX_LOCKED(&thread->startstop_sem); - init_MUTEX_LOCKED(&thread->suspend_sem); - - thread->flags = flags; - - if ((flags & PJ_THREAD_SUSPENDED) == 0) { - up(&thread->suspend_sem); - } - - /* Store the functions and argument. */ - thread->func = proc; - thread->arg = arg; - - /* Save return value. */ - *ptr_thread = thread; - - /* Create the new thread by running a task through keventd. */ - -#if 0 - /* Initialize the task queue struct. */ - thread->tq.sync = 0; - INIT_LIST_HEAD(&thread->tq.list); - thread->tq.routine = kthread_launcher; - thread->tq.data = thread; - - /* and schedule it for execution. */ - schedule_task(&thread->tq); -#endif - kthread_launcher(thread); - - /* Wait until thread has reached the setup_thread routine. */ - TRACE_((THIS_FILE, "...wait for the new thread...")); - down(&thread->startstop_sem); - - TRACE_((THIS_FILE, "...main thread resumed...")); - return PJ_SUCCESS; -} - -PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread) -{ - return thread->obj_name; -} - -PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread) -{ - up(&thread->suspend_sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_thread_t*) pj_thread_this(void) -{ - return (pj_thread_t*)pj_thread_local_get(thread_tls_id); -} - -PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p) -{ - TRACE_((THIS_FILE, "pj_thread_join()")); - down(&p->startstop_sem); - TRACE_((THIS_FILE, " joined!")); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread) -{ - PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec) -{ - pj_highprec_t ticks; - pj_thread_t *thread = pj_thread_this(); - - PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG); - - /* Use high precision calculation to make sure we don't - * crop values: - * - * ticks = HZ * msec / 1000 - */ - ticks = HZ; - pj_highprec_mul(ticks, msec); - pj_highprec_div(ticks, 1000); - - TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks)); - interruptible_sleep_on_timeout( &thread->queue, ticks); - return PJ_SUCCESS; -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, - pj_atomic_value_t value, - pj_atomic_t **ptr_var) -{ - pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t)); - if (!t) return PJ_ENOMEM; - - atomic_set(&t->atom, value); - *ptr_var = t; - - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ) -{ - return PJ_SUCCESS; -} - -PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value) -{ - atomic_set(&var->atom, value); -} - -PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var) -{ - return atomic_read(&var->atom); -} - -PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var) -{ - atomic_inc(&var->atom); -} - -PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var) -{ - atomic_dec(&var->atom); -} - -PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value ) -{ - atomic_add(value, &var->atom); -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index) -{ - if (tls_id >= MAX_TLS_ID) - return PJ_ETOOMANY; - - *index = tls_id++; - - return PJ_SUCCESS; -} - -PJ_DEF(void) pj_thread_local_free(long index) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); -} - -PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); - tls_values[index] = value; - return PJ_SUCCESS; -} - -PJ_DEF(void*) pj_thread_local_get(long index) -{ - pj_assert(index >= 0 && index < MAX_TLS_ID); - return tls_values[index]; -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(void) pj_enter_critical_section(void) -{ - spin_lock_irqsave(&critical_section, spinlock_flags); -} - -PJ_DEF(void) pj_leave_critical_section(void) -{ - spin_unlock_irqrestore(&critical_section, spinlock_flags); -} - - -/////////////////////////////////////////////////////////////////////////////// -PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, - const char *name, - int type, - pj_mutex_t **ptr_mutex) -{ - pj_mutex_t *mutex; - - PJ_UNUSED_ARG(name); - - mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t)); - if (!mutex) - return PJ_ENOMEM; - - init_MUTEX(&mutex->sem); - - mutex->recursive = (type == PJ_MUTEX_RECURSE); - mutex->owner = NULL; - mutex->own_count = 0; - - /* Done. */ - *ptr_mutex = mutex; - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex); -} - -PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool, - const char *name, - pj_mutex_t **mutex ) -{ - return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex); -} - -PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - ++mutex->own_count; - } else { - down(&mutex->sem); - pj_assert(mutex->own_count == 0); - mutex->owner = this_thread; - mutex->own_count = 1; - } - } else { - down(&mutex->sem); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex) -{ - long rc; - - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - ++mutex->own_count; - } else { - rc = down_interruptible(&mutex->sem); - if (rc != 0) - return PJ_RETURN_OS_ERROR(-rc); - pj_assert(mutex->own_count == 0); - mutex->owner = this_thread; - mutex->own_count = 1; - } - } else { - int rc = down_trylock(&mutex->sem); - if (rc != 0) - return PJ_RETURN_OS_ERROR(-rc); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex, PJ_EINVAL); - - if (mutex->recursive) { - pj_thread_t *this_thread = pj_thread_this(); - if (mutex->owner == this_thread) { - pj_assert(mutex->own_count > 0); - --mutex->own_count; - if (mutex->own_count == 0) { - mutex->owner = NULL; - up(&mutex->sem); - } - } else { - pj_assert(!"Not owner!"); - return PJ_EINVALIDOP; - } - } else { - up(&mutex->sem); - } - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex) -{ - PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL); - - return PJ_SUCCESS; -} - -#if defined(PJ_DEBUG) && PJ_DEBUG != 0 -PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex) -{ - if (mutex->recursive) - return mutex->owner == pj_thread_this(); - else - return 1; -} -#endif /* PJ_DEBUG */ - - -#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0 - -PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, - const char *name, - unsigned initial, - unsigned max, - pj_sem_t **sem) -{ - pj_sem_t *sem; - - PJ_UNUSED_ARG(max); - - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - sem = pj_pool_alloc(pool, sizeof(pj_sem_t)); - sema_init(&sem->sem, initial); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - down(&sem->sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem) -{ - int rc; - - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - rc = down_trylock(&sem->sem); - if (rc != 0) { - return PJ_RETURN_OS_ERROR(-rc); - } else { - return PJ_SUCCESS; - } -} - -PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - up(&sem->sem); - return PJ_SUCCESS; -} - -PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem) -{ - PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL); - - return PJ_SUCCESS; -} - -#endif /* PJ_HAS_SEMAPHORE */ - - - - +/* $Id$
+ *
+ */
+/*
+ * PJLIB - PJ Foundation Library
+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>
+ *
+ * Author:
+ * Benny Prijono <bennylp@bulukucing.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pj/os.h>
+#include <pj/assert.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/except.h>
+#include <pj/errno.h>
+#include <pj/string.h>
+#include <pj/compat/high_precision.h>
+#include <pj/compat/sprintf.h>
+
+#include <linux/config.h>
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/sched.h>
+//#include <linux/tqueue.h>
+#include <linux/wait.h>
+#include <linux/signal.h>
+
+#include <asm/atomic.h>
+#include <asm/unistd.h>
+#include <asm/semaphore.h>
+
+#define THIS_FILE "oslinuxkern"
+
+struct pj_thread_t
+{
+ /** Thread's name. */
+ char obj_name[PJ_MAX_OBJ_NAME];
+
+ /** Linux task structure for thread. */
+ struct task_struct *thread;
+
+ /** Flags (specified in pj_thread_create) */
+ unsigned flags;
+
+ /** Task queue needed to launch thread. */
+ //struct tq_struct tq;
+
+ /** Semaphore needed to control thread startup. */
+ struct semaphore startstop_sem;
+
+ /** Semaphore to suspend thread during startup. */
+ struct semaphore suspend_sem;
+
+ /** Queue thread is waiting on. Gets initialized by
+ thread_initialize, can be used by thread itself.
+ */
+ wait_queue_head_t queue;
+
+ /** Flag to tell thread whether to die or not.
+ When the thread receives a signal, it must check
+ the value of terminate and call thread_deinitialize and terminate
+ if set.
+ */
+ int terminate;
+
+ /** Thread's entry. */
+ pj_thread_proc *func;
+
+ /** Argument. */
+ void *arg;
+};
+
+struct pj_atomic_t
+{
+ atomic_t atom;
+};
+
+struct pj_mutex_t
+{
+ struct semaphore sem;
+ pj_bool_t recursive;
+ pj_thread_t *owner;
+ int own_count;
+};
+
+struct pj_sem_t
+{
+ struct semaphore sem;
+};
+
+/*
+ * Static global variables.
+ */
+#define MAX_TLS_ID 32
+static void *tls_values[MAX_TLS_ID];
+static int tls_id;
+static long thread_tls_id;
+static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
+static unsigned long spinlock_flags;
+static pj_thread_t main_thread;
+
+/* private functions */
+//#define TRACE_(expr) PJ_LOG(3,expr)
+#define TRACE_(x)
+
+
+/* This must be called in the context of the new thread. */
+static void thread_initialize( pj_thread_t *thread )
+{
+ TRACE_((THIS_FILE, "---new thread initializing..."));
+
+ /* Set TLS */
+ pj_thread_local_set(thread_tls_id, thread);
+
+ /* fill in thread structure */
+ thread->thread = current;
+ pj_assert(thread->thread != NULL);
+
+ /* set signal mask to what we want to respond */
+ siginitsetinv(¤t->blocked,
+ sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
+
+ /* initialise wait queue */
+ init_waitqueue_head(&thread->queue);
+
+ /* initialise termination flag */
+ thread->terminate = 0;
+
+ /* set name of this process (max 15 chars + 0 !) */
+ thread->obj_name[15] = '\0';
+ sprintf(current->comm, thread->obj_name);
+
+ /* tell the creator that we are ready and let him continue */
+ up(&thread->startstop_sem);
+}
+
+/* cleanup of thread. Called by the exiting thread. */
+static void thread_deinitialize(pj_thread_t *thread)
+{
+ /* we are terminating */
+
+ /* lock the kernel, the exit will unlock it */
+ thread->thread = NULL;
+ mb();
+
+ /* notify the stop_kthread() routine that we are terminating. */
+ up(&thread->startstop_sem);
+
+ /* the kernel_thread that called clone() does a do_exit here. */
+
+ /* there is no race here between execution of the "killer" and
+ real termination of the thread (race window between up and do_exit),
+ since both the thread and the "killer" function are running with
+ the kernel lock held.
+ The kernel lock will be freed after the thread exited, so the code
+ is really not executed anymore as soon as the unload functions gets
+ the kernel lock back.
+ The init process may not have made the cleanup of the process here,
+ but the cleanup can be done safely with the module unloaded.
+ */
+
+}
+
+static int thread_proc(void *arg)
+{
+ pj_thread_t *thread = arg;
+
+ TRACE_((THIS_FILE, "---new thread starting!"));
+
+ /* Initialize thread. */
+ thread_initialize( thread );
+
+ /* Wait if created suspended. */
+ if (thread->flags & PJ_THREAD_SUSPENDED) {
+ TRACE_((THIS_FILE, "---new thread suspended..."));
+ down(&thread->suspend_sem);
+ }
+
+ TRACE_((THIS_FILE, "---new thread running..."));
+
+ pj_assert(thread->func != NULL);
+
+ /* Call thread's entry. */
+ (*thread->func)(thread->arg);
+
+ TRACE_((THIS_FILE, "---thread exiting..."));
+
+ /* Cleanup thread. */
+ thread_deinitialize(thread);
+
+ return 0;
+}
+
+/* The very task entry. */
+static void kthread_launcher(void *arg)
+{
+ TRACE_((THIS_FILE, "...launching thread!..."));
+ kernel_thread(&thread_proc, arg, 0);
+}
+
+PJ_DEF(pj_status_t) pj_init(void)
+{
+ pj_status_t rc;
+
+ PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
+
+ rc = pj_thread_init();
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ /* Initialize exception ID for the pool.
+ * Must do so after critical section is configured.
+ */
+ rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_uint32_t) pj_getpid(void)
+{
+ return 1;
+}
+
+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
+ pj_thread_desc desc,
+ pj_thread_t **ptr_thread)
+{
+ char stack_ptr;
+ pj_thread_t *thread = (pj_thread_t *)desc;
+ pj_str_t thread_name = pj_str((char*)cstr_thread_name);
+
+ /* Size sanity check. */
+ if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
+ pj_assert(!"Not enough pj_thread_desc size!");
+ return PJ_EBUG;
+ }
+
+ /* If a thread descriptor has been registered before, just return it. */
+ if (pj_thread_local_get (thread_tls_id) != 0) {
+ *ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
+ return PJ_SUCCESS;
+ }
+
+ /* Initialize and set the thread entry. */
+ pj_memset(desc, 0, sizeof(struct pj_thread_t));
+
+ if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
+ pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
+ else
+ pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
+
+ /* Initialize. */
+ thread_initialize(thread);
+
+ /* Eat semaphore. */
+ down(&thread->startstop_sem);
+
+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
+ thread->stk_start = &stack_ptr;
+ thread->stk_size = 0xFFFFFFFFUL;
+ thread->stk_max_usage = 0;
+#else
+ stack_ptr = '\0';
+#endif
+
+ *ptr_thread = thread;
+ return PJ_SUCCESS;
+}
+
+
+pj_status_t pj_thread_init(void)
+{
+ pj_status_t rc;
+ pj_thread_t *dummy;
+
+ rc = pj_thread_local_alloc(&thread_tls_id);
+ if (rc != PJ_SUCCESS)
+ return rc;
+
+ return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
+}
+
+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
+ pj_thread_proc *proc, void *arg,
+ pj_size_t stack_size, unsigned flags,
+ pj_thread_t **ptr_thread)
+{
+ pj_thread_t *thread;
+
+ TRACE_((THIS_FILE, "pj_thread_create()"));
+
+ PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
+
+ thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
+ if (!thread)
+ return PJ_ENOMEM;
+
+ PJ_UNUSED_ARG(stack_size);
+
+ /* Thread name. */
+ if (!thread_name)
+ thread_name = "thr%p";
+
+ if (strchr(thread_name, '%')) {
+ pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
+ } else {
+ strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
+ thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
+ }
+
+ /* Init thread's semaphore. */
+ TRACE_((THIS_FILE, "...init semaphores..."));
+ init_MUTEX_LOCKED(&thread->startstop_sem);
+ init_MUTEX_LOCKED(&thread->suspend_sem);
+
+ thread->flags = flags;
+
+ if ((flags & PJ_THREAD_SUSPENDED) == 0) {
+ up(&thread->suspend_sem);
+ }
+
+ /* Store the functions and argument. */
+ thread->func = proc;
+ thread->arg = arg;
+
+ /* Save return value. */
+ *ptr_thread = thread;
+
+ /* Create the new thread by running a task through keventd. */
+
+#if 0
+ /* Initialize the task queue struct. */
+ thread->tq.sync = 0;
+ INIT_LIST_HEAD(&thread->tq.list);
+ thread->tq.routine = kthread_launcher;
+ thread->tq.data = thread;
+
+ /* and schedule it for execution. */
+ schedule_task(&thread->tq);
+#endif
+ kthread_launcher(thread);
+
+ /* Wait until thread has reached the setup_thread routine. */
+ TRACE_((THIS_FILE, "...wait for the new thread..."));
+ down(&thread->startstop_sem);
+
+ TRACE_((THIS_FILE, "...main thread resumed..."));
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
+{
+ return thread->obj_name;
+}
+
+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
+{
+ up(&thread->suspend_sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_thread_t*) pj_thread_this(void)
+{
+ return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
+}
+
+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
+{
+ TRACE_((THIS_FILE, "pj_thread_join()"));
+ down(&p->startstop_sem);
+ TRACE_((THIS_FILE, " joined!"));
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
+{
+ PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
+{
+ pj_highprec_t ticks;
+ pj_thread_t *thread = pj_thread_this();
+
+ PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
+
+ /* Use high precision calculation to make sure we don't
+ * crop values:
+ *
+ * ticks = HZ * msec / 1000
+ */
+ ticks = HZ;
+ pj_highprec_mul(ticks, msec);
+ pj_highprec_div(ticks, 1000);
+
+ TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
+ interruptible_sleep_on_timeout( &thread->queue, ticks);
+ return PJ_SUCCESS;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
+ pj_atomic_value_t value,
+ pj_atomic_t **ptr_var)
+{
+ pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
+ if (!t) return PJ_ENOMEM;
+
+ atomic_set(&t->atom, value);
+ *ptr_var = t;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
+{
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
+{
+ atomic_set(&var->atom, value);
+}
+
+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
+{
+ return atomic_read(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
+{
+ atomic_inc(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
+{
+ atomic_dec(&var->atom);
+}
+
+PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
+{
+ atomic_add(value, &var->atom);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
+{
+ if (tls_id >= MAX_TLS_ID)
+ return PJ_ETOOMANY;
+
+ *index = tls_id++;
+
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void) pj_thread_local_free(long index)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+}
+
+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+ tls_values[index] = value;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(void*) pj_thread_local_get(long index)
+{
+ pj_assert(index >= 0 && index < MAX_TLS_ID);
+ return tls_values[index];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(void) pj_enter_critical_section(void)
+{
+ spin_lock_irqsave(&critical_section, spinlock_flags);
+}
+
+PJ_DEF(void) pj_leave_critical_section(void)
+{
+ spin_unlock_irqrestore(&critical_section, spinlock_flags);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
+ const char *name,
+ int type,
+ pj_mutex_t **ptr_mutex)
+{
+ pj_mutex_t *mutex;
+
+ PJ_UNUSED_ARG(name);
+
+ mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
+ if (!mutex)
+ return PJ_ENOMEM;
+
+ init_MUTEX(&mutex->sem);
+
+ mutex->recursive = (type == PJ_MUTEX_RECURSE);
+ mutex->owner = NULL;
+ mutex->own_count = 0;
+
+ /* Done. */
+ *ptr_mutex = mutex;
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
+ const char *name,
+ pj_mutex_t **mutex )
+{
+ return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
+}
+
+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ ++mutex->own_count;
+ } else {
+ down(&mutex->sem);
+ pj_assert(mutex->own_count == 0);
+ mutex->owner = this_thread;
+ mutex->own_count = 1;
+ }
+ } else {
+ down(&mutex->sem);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
+{
+ long rc;
+
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ ++mutex->own_count;
+ } else {
+ rc = down_interruptible(&mutex->sem);
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(-rc);
+ pj_assert(mutex->own_count == 0);
+ mutex->owner = this_thread;
+ mutex->own_count = 1;
+ }
+ } else {
+ int rc = down_trylock(&mutex->sem);
+ if (rc != 0)
+ return PJ_RETURN_OS_ERROR(-rc);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
+
+ if (mutex->recursive) {
+ pj_thread_t *this_thread = pj_thread_this();
+ if (mutex->owner == this_thread) {
+ pj_assert(mutex->own_count > 0);
+ --mutex->own_count;
+ if (mutex->own_count == 0) {
+ mutex->owner = NULL;
+ up(&mutex->sem);
+ }
+ } else {
+ pj_assert(!"Not owner!");
+ return PJ_EINVALIDOP;
+ }
+ } else {
+ up(&mutex->sem);
+ }
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
+{
+ PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
+
+ return PJ_SUCCESS;
+}
+
+#if defined(PJ_DEBUG) && PJ_DEBUG != 0
+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
+{
+ if (mutex->recursive)
+ return mutex->owner == pj_thread_this();
+ else
+ return 1;
+}
+#endif /* PJ_DEBUG */
+
+
+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
+
+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
+ const char *name,
+ unsigned initial,
+ unsigned max,
+ pj_sem_t **sem)
+{
+ pj_sem_t *sem;
+
+ PJ_UNUSED_ARG(max);
+
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
+ sema_init(&sem->sem, initial);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ down(&sem->sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
+{
+ int rc;
+
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ rc = down_trylock(&sem->sem);
+ if (rc != 0) {
+ return PJ_RETURN_OS_ERROR(-rc);
+ } else {
+ return PJ_SUCCESS;
+ }
+}
+
+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ up(&sem->sem);
+ return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
+{
+ PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
+
+ return PJ_SUCCESS;
+}
+
+#endif /* PJ_HAS_SEMAPHORE */
+
+
+
+
|