📄 os_core_win32.c
字号:
/* $Id: os_core_win32.c 1045 2007-03-06 23:32:25Z 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 */#include <pj/os.h>#include <pj/pool.h>#include <pj/log.h>#include <pj/string.h>#include <pj/guid.h>#include <pj/rand.h>#include <pj/assert.h>#include <pj/errno.h>#include <pj/except.h>#include <stddef.h>#include <stdlib.h>#include <stdio.h>#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0# include <winsock.h>#endif#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0# include <winsock2.h>#endif#define THIS_FILE "os_core_win32.c"/* * Implementation of pj_thread_t. */struct pj_thread_t{ char obj_name[PJ_MAX_OBJ_NAME]; HANDLE hthread; DWORD idthread; pj_thread_proc *proc; void *arg;#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};/* * Implementation of pj_mutex_t. */struct pj_mutex_t{#if PJ_WIN32_WINNT >= 0x0400 CRITICAL_SECTION crit;#else HANDLE hMutex;#endif char obj_name[PJ_MAX_OBJ_NAME];#if PJ_DEBUG int nesting_level; pj_thread_t *owner;#endif};/* * Implementation of pj_sem_t. */typedef struct pj_sem_t{ HANDLE hSemaphore; char obj_name[PJ_MAX_OBJ_NAME];} pj_mem_t;/* * Implementation of pj_event_t. */struct pj_event_t{ HANDLE hEvent; char obj_name[PJ_MAX_OBJ_NAME];};/* * Implementation of pj_atomic_t. */struct pj_atomic_t{ long value;};/* * Static global variables. */static pj_thread_desc main_thread;static long thread_tls_id = -1;static pj_mutex_t critical_section_mutex;static unsigned atexit_count;static void (*atexit_func[32])(void);/* * Some static prototypes. */static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);/* * pj_init(void). * Init PJLIB! */PJ_DEF(pj_status_t) pj_init(void){ WSADATA wsa; char dummy_guid[32]; /* use maximum GUID length */ pj_str_t guid; pj_status_t rc; /* Init Winsock.. */ if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) { return PJ_RETURN_OS_ERROR(WSAGetLastError()); } /* Init this thread's TLS. */ if ((rc=pj_thread_init()) != PJ_SUCCESS) { return rc; } /* Init random seed. */ pj_srand( GetCurrentProcessId() ); /* Startup GUID. */ guid.ptr = dummy_guid; pj_generate_unique_string( &guid ); /* Initialize critical section. */ if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != 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; /* Startup timestamp */#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0 { pj_timestamp dummy_ts; if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) { return rc; } if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) { return rc; } }#endif PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 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; } /* Destroy PJLIB critical section */ pj_mutex_destroy(&critical_section_mutex); /* Free PJLIB TLS */ if (thread_tls_id != -1) { pj_thread_local_free(thread_tls_id); thread_tls_id = -1; } /* Clear static variables */ pj_errno_clear_handlers(); /* Shutdown Winsock */ //WSACleanup();}/* * pj_getpid(void) */PJ_DEF(pj_uint32_t) pj_getpid(void){ PJ_CHECK_STACK(); return GetCurrentProcessId();}/* * Check if this thread has been registered to PJLIB. */PJ_DEF(pj_bool_t) pj_thread_is_registered(void){ return pj_thread_local_get(thread_tls_id) != 0;}/* * pj_thread_register(..) */PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name, pj_thread_desc desc, pj_thread_t **thread_ptr){ 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; } /* If a thread descriptor has been registered before, just return it. */ 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; } /* Initialize and set the thread entry. */ pj_bzero(desc, sizeof(struct pj_thread_t)); thread->hthread = GetCurrentThread(); thread->idthread = GetCurrentThreadId();#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 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->idthread); else pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name), "thr%p", (void*)thread->idthread); rc = pj_thread_local_set(thread_tls_id, thread); if (rc != PJ_SUCCESS) return rc; *thread_ptr = thread; return PJ_SUCCESS;}/* * pj_thread_init(void) */pj_status_t pj_thread_init(void){ pj_status_t rc; pj_thread_t *thread; rc = pj_thread_local_alloc(&thread_tls_id); if (rc != PJ_SUCCESS) return rc; return pj_thread_register("thr%p", main_thread, &thread);}static DWORD WINAPI thread_main(void *param){ pj_thread_t *rec = param; DWORD result;#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_start = (char*)&rec;#endif if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) { pj_assert(!"TLS is not set (pj_init() error?)"); } PJ_LOG(6,(rec->obj_name, "Thread started")); result = (*rec->proc)(rec->arg); PJ_LOG(6,(rec->obj_name, "Thread quitting")); return (DWORD)result;}/* * 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 **thread_ptr){ DWORD dwflags = 0; pj_thread_t *rec; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL); /* Set flags */ if (flags & PJ_THREAD_SUSPENDED) dwflags |= CREATE_SUSPENDED; /* Create thread record and assign name for the thread */ rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t)); if (!rec) return 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 { pj_ansi_strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME); rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0'; } PJ_LOG(6, (rec->obj_name, "Thread created"));#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0 rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL; rec->stk_max_usage = 0;#endif /* Create the thread. */ rec->proc = proc; rec->arg = arg; rec->hthread = CreateThread(NULL, stack_size, thread_main, rec, dwflags, &rec->idthread); if (rec->hthread == NULL) return PJ_RETURN_OS_ERROR(GetLastError()); /* Success! */ *thread_ptr = rec; return PJ_SUCCESS;}/* * pj_thread-get_name() */PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p){ pj_thread_t *rec = (pj_thread_t*)p; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, ""); return rec->obj_name;}/* * pj_thread_resume() */PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p){ pj_thread_t *rec = (pj_thread_t*)p; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, PJ_EINVAL); if (ResumeThread(rec->hthread) == (DWORD)-1) return PJ_RETURN_OS_ERROR(GetLastError()); else return PJ_SUCCESS;}/* * pj_thread_this() */PJ_DEF(pj_thread_t*) pj_thread_this(void){ 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!!! * */ return rec;}/* * pj_thread_join() */PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p){ pj_thread_t *rec = (pj_thread_t *)p; DWORD rc; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, PJ_EINVAL); PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name)); rc = WaitForSingleObject(rec->hthread, INFINITE); if (rc==WAIT_OBJECT_0) return PJ_SUCCESS; else if (rc==WAIT_TIMEOUT) return PJ_ETIMEDOUT; else return PJ_RETURN_OS_ERROR(GetLastError());}/* * pj_thread_destroy() */PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p){ pj_thread_t *rec = (pj_thread_t *)p; PJ_CHECK_STACK(); PJ_ASSERT_RETURN(p, PJ_EINVAL); if (CloseHandle(rec->hthread) == TRUE) return PJ_SUCCESS; else return PJ_RETURN_OS_ERROR(GetLastError());}/* * pj_thread_sleep() */PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec){ PJ_CHECK_STACK(); Sleep(msec); return PJ_SUCCESS;}#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0/* * pj_thread_check_stack() * Implementation for PJ_CHECK_STACK() */PJ_DEF(void) pj_thread_check_stack(const char *file, int line){ char stk_ptr; pj_uint32_t usage; pj_thread_t *thread = pj_thread_this(); pj_assert(thread); /* Calculate current usage. */ usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start : thread->stk_start - &stk_ptr; /* Assert if stack usage is dangerously high. */ pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128)); /* Keep statistic. */ if (usage > thread->stk_max_usage) { thread->stk_max_usage = usage; thread->caller_file = file; thread->caller_line = line; }}/* * pj_thread_get_stack_max_usage() */PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread){ return thread->stk_max_usage;}/* * pj_thread_get_stack_info() */PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread, const char **file, int *line ){ pj_assert(thread); *file = thread->caller_file; *line = thread->caller_line; return 0;}#endif /* PJ_OS_HAS_CHECK_STACK */////////////////////////////////////////////////////////////////////////////////* * pj_atomic_create() */PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, pj_atomic_value_t initial, pj_atomic_t **atomic_ptr){ pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t)); if (!atomic_var) return PJ_ENOMEM; atomic_var->value = initial; *atomic_ptr = atomic_var; return PJ_SUCCESS;}/* * pj_atomic_destroy() */PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var ){ PJ_UNUSED_ARG(var); PJ_ASSERT_RETURN(var, PJ_EINVAL); return 0;}/* * pj_atomic_set() */PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value){ PJ_CHECK_STACK(); InterlockedExchange(&atomic_var->value, value);}/* * pj_atomic_get() */PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var){ PJ_CHECK_STACK(); PJ_ASSERT_RETURN(atomic_var, 0); return atomic_var->value;}/* * pj_atomic_inc_and_get() */PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var){ PJ_CHECK_STACK();#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 return InterlockedIncrement(&atomic_var->value);#else return InterlockedIncrement(&atomic_var->value);#endif}/* * pj_atomic_inc() */PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var){ pj_atomic_inc_and_get(atomic_var);}/* * pj_atomic_dec_and_get() */PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var){ PJ_CHECK_STACK();#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 return InterlockedDecrement(&atomic_var->value);#else return InterlockedDecrement(&atomic_var->value);#endif}/* * pj_atomic_dec() */PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var){ pj_atomic_dec_and_get(atomic_var);}/* * pj_atomic_add() */PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var, pj_atomic_value_t value ){#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400 InterlockedExchangeAdd( &atomic_var->value, value );#else InterlockedExchangeAdd( &atomic_var->value, value );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -