📄 os_core_unix.c
字号:
/* $Id: os_core_unix.c 1075 2007-03-16 18:41:07Z bennylp $ *//* * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* * Contributors: * - Thanks for Zetron, Inc. (Phil Torre, ptorre@zetron.com) for donating * the RTEMS port. */#define _GNU_SOURCE#include <pj/os.h>#include <pj/assert.h>#include <pj/pool.h>#include <pj/log.h>#include <pj/rand.h>#include <pj/string.h>#include <pj/guid.h>#include <pj/except.h>#include <pj/errno.h>#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0# include <semaphore.h>#endif#include <unistd.h> // getpid()#include <errno.h> // errno#include <pthread.h>#define THIS_FILE "os_core_unix.c"#define SIGNATURE1 0xDEAFBEEF#define SIGNATURE2 0xDEADC0DEstruct pj_thread_t{ char obj_name[PJ_MAX_OBJ_NAME]; pthread_t thread; pj_thread_proc *proc; void *arg; pj_uint32_t signature1; pj_uint32_t signature2; pj_mutex_t *suspended_mutex;#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 pj_uint32_t stk_size; pj_uint32_t stk_max_usage; char *stk_start; const char *caller_file; int caller_line;#endif};struct pj_atomic_t{ pj_mutex_t *mutex; pj_atomic_value_t value;};struct pj_mutex_t{ pthread_mutex_t mutex; char obj_name[PJ_MAX_OBJ_NAME];#if PJ_DEBUG int nesting_level; pj_thread_t *owner; char owner_name[PJ_MAX_OBJ_NAME];#endif};#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0struct pj_sem_t{ sem_t sem; char obj_name[PJ_MAX_OBJ_NAME];};#endif /* PJ_HAS_SEMAPHORE */#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0struct pj_event_t{ char obj_name[PJ_MAX_OBJ_NAME];};#endif /* PJ_HAS_EVENT_OBJ */#if PJ_HAS_THREADS static pj_thread_t main_thread; static long thread_tls_id; static pj_mutex_t critical_section;#else# define MAX_THREADS 32 static int tls_flag[MAX_THREADS]; static void *tls[MAX_THREADS];#endifstatic unsigned atexit_count;static void (*atexit_func[32])(void);static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);/* * pj_init(void). * Init PJLIB! */PJ_DEF(pj_status_t) pj_init(void){ char dummy_guid[PJ_GUID_MAX_LENGTH]; pj_str_t guid; pj_status_t rc;#if PJ_HAS_THREADS /* Init this thread's TLS. */ if ((rc=pj_thread_init()) != 0) { return rc; } /* Critical section. */ if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_RECURSE)) != 0) return rc;#endif /* 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; /* Init random seed. */ pj_srand( clock() ); /* Startup GUID. */ guid.ptr = dummy_guid; pj_generate_unique_string( &guid ); /* Startup timestamp */#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 { pj_timestamp dummy_ts; if ((rc=pj_get_timestamp(&dummy_ts)) != 0) { return rc; } }#endif PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized", PJ_VERSION)); return PJ_SUCCESS;}/* * pj_atexit() */PJ_DEF(pj_status_t) pj_atexit(void (*func)(void)){ if (atexit_count >= PJ_ARRAY_SIZE(atexit_func)) return PJ_ETOOMANY; atexit_func[atexit_count++] = func; return PJ_SUCCESS;}/* * pj_shutdown(void) */PJ_DEF(void) pj_shutdown(){ int i; /* Call atexit() functions */ for (i=atexit_count-1; i>=0; --i) { (*atexit_func[i])(); } atexit_count = 0; /* Free exception ID */ if (PJ_NO_MEMORY_EXCEPTION != -1) { pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION); PJ_NO_MEMORY_EXCEPTION = -1; }#if PJ_HAS_THREADS /* Destroy PJLIB critical section */ pj_mutex_destroy(&critical_section); /* Free PJLIB TLS */ if (thread_tls_id != -1) { pj_thread_local_free(thread_tls_id); thread_tls_id = -1; }#endif /* Clear static variables */ pj_errno_clear_handlers();}/* * pj_getpid(void) */PJ_DEF(pj_uint32_t) pj_getpid(void){ PJ_CHECK_STACK(); return getpid();}/* * Check if this thread has been registered to PJLIB. */PJ_DEF(pj_bool_t) pj_thread_is_registered(void){#if PJ_HAS_THREADS return pj_thread_local_get(thread_tls_id) != 0;#else pj_assert("pj_thread_is_registered() called in non-threading mode!"); return PJ_TRUE;#endif}/* * pj_thread_register(..) */PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, pj_thread_desc desc, pj_thread_t **ptr_thread){#if PJ_HAS_THREADS char stack_ptr; pj_status_t rc; 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; } /* Warn if this thread has been registered before */ if (pj_thread_local_get (thread_tls_id) != 0) { // 2006-02-26 bennylp: // This wouldn't work in all cases!. // If thread is created by external module (e.g. sound thread), // thread may be reused while the pool used for the thread descriptor // has been deleted by application. //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id); //return PJ_SUCCESS; PJ_LOG(4,(THIS_FILE, "Info: possibly re-registering existing " "thread")); } /* On the other hand, also warn if the thread descriptor buffer seem to * have been used to register other threads. */ pj_assert(thread->signature1 != SIGNATURE1 || thread->signature2 != SIGNATURE2 || (thread->thread == pthread_self())); /* Initialize and set the thread entry. */ pj_bzero(desc, sizeof(struct pj_thread_t)); thread->thread = pthread_self(); thread->signature1 = SIGNATURE1; thread->signature2 = SIGNATURE2; if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1) pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), cstr_thread_name, thread->thread); else pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), "thr%p", (void*)thread->thread); rc = pj_thread_local_set(thread_tls_id, thread); if (rc != PJ_SUCCESS) { pj_bzero(desc, sizeof(struct pj_thread_t)); return rc; }#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;#else pj_thread_t *thread = (pj_thread_t*)desc; *ptr_thread = thread; return PJ_SUCCESS;#endif}/* * pj_thread_init(void) */pj_status_t pj_thread_init(void){#if PJ_HAS_THREADS 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("thr%p", (long*)&main_thread, &dummy);#else PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!")); return PJ_EINVALIDOP;#endif}#if PJ_HAS_THREADS/* * thread_main() * * This is the main entry for all threads. */static void *thread_main(void *param){ pj_thread_t *rec = param; void *result; pj_status_t rc;#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_start = (char*)&rec;#endif /* Set current thread id. */ rc = pj_thread_local_set(thread_tls_id, rec); if (rc != PJ_SUCCESS) { pj_assert(!"Thread TLS ID is not set (pj_init() error?)"); } /* Check if suspension is required. */ if (rec->suspended_mutex) pj_mutex_lock(rec->suspended_mutex); PJ_LOG(6,(rec->obj_name, "Thread started")); /* Call user's entry! */ result = (void*)(long)(*rec->proc)(rec->arg); /* Done. */ PJ_LOG(6,(rec->obj_name, "Thread quitting")); return result;}#endif/* * pj_thread_create(...) */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){#if PJ_HAS_THREADS pj_thread_t *rec; pthread_attr_t thread_attr; void *stack_addr; int rc; PJ_UNUSED_ARG(stack_addr); PJ_CHECK_STACK(); PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL); /* Create thread record and assign name for the thread */ rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t)); PJ_ASSERT_RETURN(rec, PJ_ENOMEM); /* Set name. */ if (!thread_name) thread_name = "thr%p"; if (strchr(thread_name, '%')) { pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec); } else { strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; } /* Set default stack size */ if (stack_size == 0) stack_size = PJ_THREAD_DEFAULT_STACK_SIZE;#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_size = stack_size; rec->stk_max_usage = 0;#endif /* Emulate suspended thread with mutex. */ if (flags & PJ_THREAD_SUSPENDED) { rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex); if (rc != PJ_SUCCESS) { return rc; } pj_mutex_lock(rec->suspended_mutex); } else { pj_assert(rec->suspended_mutex == NULL); } /* Init thread attributes */ pthread_attr_init(&thread_attr);#if defined(PJ_THREAD_SET_STACK_SIZE) && PJ_THREAD_SET_STACK_SIZE!=0 /* Set thread's stack size */ rc = pthread_attr_setstacksize(&thread_attr, stack_size); if (rc != 0) return PJ_RETURN_OS_ERROR(rc);#endif /* PJ_THREAD_SET_STACK_SIZE */#if defined(PJ_THREAD_ALLOCATE_STACK) && PJ_THREAD_ALLOCATE_STACK!=0 /* Allocate memory for the stack */ stack_addr = pj_pool_alloc(pool, stack_size); PJ_ASSERT_RETURN(stack_addr, PJ_ENOMEM); rc = pthread_attr_setstackaddr(&thread_attr, stack_addr); if (rc != 0) return PJ_RETURN_OS_ERROR(rc);#endif /* PJ_THREAD_ALLOCATE_STACK */ /* Create the thread. */ rec->proc = proc; rec->arg = arg; rc = pthread_create( &rec->thread, &thread_attr, &thread_main, rec); if (rc != 0) { return PJ_RETURN_OS_ERROR(rc); } *ptr_thread = rec; PJ_LOG(6, (rec->obj_name, "Thread created")); return PJ_SUCCESS;#else pj_assert(!"Threading is disabled!"); return PJ_EINVALIDOP;#endif}/* * pj_thread-get_name() */PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p){#if PJ_HAS_THREADS pj_thread_t *rec = (pj_thread_t*)p; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, ""); return rec->obj_name;#else return "";#endif}/* * pj_thread_resume() */PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p){ pj_status_t rc; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, PJ_EINVAL); rc = pj_mutex_unlock(p->suspended_mutex); return rc;}/* * pj_thread_this() */PJ_DEF(pj_thread_t*) pj_thread_this(void){#if PJ_HAS_THREADS pj_thread_t *rec = pj_thread_local_get(thread_tls_id); if (rec == NULL) { pj_assert(!"Calling pjlib from unknown/external thread. You must " "register external threads with pj_thread_register() " "before calling any pjlib functions."); } /* * MUST NOT check stack because this function is called * by PJ_CHECK_STACK() itself!!! * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -