1
/* $Id: os_core_win32.c 3999 2012-03-30 07:10:13Z bennylp $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
23
#include <pj/string.h>
26
#include <pj/assert.h>
28
#include <pj/except.h>
33
#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
37
#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
38
# include <winsock2.h>
41
/* Activate mutex related logging if PJ_DEBUG_MUTEX is set, otherwise
42
* use default level 6 logging.
44
#if defined(PJ_DEBUG_MUTEX) && PJ_DEBUG_MUTEX
47
# define LOG_MUTEX(expr) PJ_LOG(5,expr)
49
# define LOG_MUTEX(expr) PJ_LOG(6,expr)
52
#define THIS_FILE "os_core_win32.c"
55
* Implementation of pj_thread_t.
59
char obj_name[PJ_MAX_OBJ_NAME];
65
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
67
pj_uint32_t stk_max_usage;
69
const char *caller_file;
76
* Implementation of pj_mutex_t.
80
#if PJ_WIN32_WINNT >= 0x0400
81
CRITICAL_SECTION crit;
85
char obj_name[PJ_MAX_OBJ_NAME];
93
* Implementation of pj_sem_t.
95
typedef struct pj_sem_t
98
char obj_name[PJ_MAX_OBJ_NAME];
103
* Implementation of pj_event_t.
108
char obj_name[PJ_MAX_OBJ_NAME];
112
* Implementation of pj_atomic_t.
120
* Flag and reference counter for PJLIB instance.
122
static int initialized;
125
* Static global variables.
127
static pj_thread_desc main_thread;
128
static long thread_tls_id = -1;
129
static pj_mutex_t critical_section_mutex;
130
static unsigned atexit_count;
131
static void (*atexit_func[32])(void);
134
* Some static prototypes.
136
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
143
PJ_DEF(pj_status_t) pj_init(void)
146
char dummy_guid[32]; /* use maximum GUID length */
150
/* Check if PJLIB have been initialized */
157
if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
158
return PJ_RETURN_OS_ERROR(WSAGetLastError());
161
/* Init this thread's TLS. */
162
if ((rc=pj_thread_init()) != PJ_SUCCESS) {
169
/* Init random seed. */
170
/* Or probably not. Let application in charge of this */
171
/* pj_srand( GetCurrentProcessId() ); */
173
/* Initialize critical section. */
174
if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
178
guid.ptr = dummy_guid;
179
pj_generate_unique_string( &guid );
181
/* Initialize exception ID for the pool.
182
* Must do so after critical section is configured.
184
rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
185
if (rc != PJ_SUCCESS)
188
/* Startup timestamp */
189
#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
191
pj_timestamp dummy_ts;
192
if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) {
195
if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
201
/* Flag PJLIB as initialized */
203
pj_assert(initialized == 1);
205
PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
214
PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
216
if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
219
atexit_func[atexit_count++] = func;
227
PJ_DEF(void) pj_shutdown()
231
/* Only perform shutdown operation when 'initialized' reaches zero */
232
pj_assert(initialized > 0);
233
if (--initialized != 0)
236
/* Display stack usage */
237
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
239
pj_thread_t *rec = (pj_thread_t*)main_thread;
240
PJ_LOG(5,(rec->obj_name, "Main thread stack max usage=%u by %s:%d",
241
rec->stk_max_usage, rec->caller_file, rec->caller_line));
245
/* Call atexit() functions */
246
for (i=atexit_count-1; i>=0; --i) {
251
/* Free exception ID */
252
if (PJ_NO_MEMORY_EXCEPTION != -1) {
253
pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
254
PJ_NO_MEMORY_EXCEPTION = -1;
257
/* Destroy PJLIB critical section */
258
pj_mutex_destroy(&critical_section_mutex);
261
if (thread_tls_id != -1) {
262
pj_thread_local_free(thread_tls_id);
266
/* Clear static variables */
267
pj_errno_clear_handlers();
269
/* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
270
pj_bzero(main_thread, sizeof(main_thread));
272
/* Shutdown Winsock */
280
PJ_DEF(pj_uint32_t) pj_getpid(void)
283
return GetCurrentProcessId();
287
* Check if this thread has been registered to PJLIB.
289
PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
291
return pj_thread_local_get(thread_tls_id) != 0;
296
* Get thread priority value for the thread.
298
PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
300
return GetThreadPriority(thread->hthread);
305
* Set the thread priority.
307
PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread, int prio)
310
PJ_ASSERT_RETURN(thread, PJ_EINVAL);
311
PJ_ASSERT_RETURN(prio>=THREAD_PRIORITY_IDLE &&
312
prio<=THREAD_PRIORITY_TIME_CRITICAL,
315
if (SetThreadPriority(thread->hthread, prio) == FALSE)
316
return PJ_RETURN_OS_ERROR(GetLastError());
321
PJ_UNUSED_ARG(thread);
323
pj_assert("pj_thread_set_prio() called in non-threading mode!");
324
return PJ_EINVALIDOP;
330
* Get the lowest priority value available on this system.
332
PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
334
PJ_UNUSED_ARG(thread);
335
return THREAD_PRIORITY_IDLE;
340
* Get the highest priority value available on this system.
342
PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
344
PJ_UNUSED_ARG(thread);
345
return THREAD_PRIORITY_TIME_CRITICAL;
350
* Get native thread handle
352
PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
354
PJ_ASSERT_RETURN(thread, NULL);
357
return thread->hthread;
359
pj_assert("pj_thread_is_registered() called in non-threading mode!");
365
* pj_thread_register(..)
367
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
369
pj_thread_t **thread_ptr)
373
pj_thread_t *thread = (pj_thread_t *)desc;
374
pj_str_t thread_name = pj_str((char*)cstr_thread_name);
376
/* Size sanity check. */
377
if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
378
pj_assert(!"Not enough pj_thread_desc size!");
382
/* If a thread descriptor has been registered before, just return it. */
383
if (pj_thread_local_get (thread_tls_id) != 0) {
384
// 2006-02-26 bennylp:
385
// This wouldn't work in all cases!.
386
// If thread is created by external module (e.g. sound thread),
387
// thread may be reused while the pool used for the thread descriptor
388
// has been deleted by application.
389
//*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
393
/* Initialize and set the thread entry. */
394
pj_bzero(desc, sizeof(struct pj_thread_t));
395
thread->hthread = GetCurrentThread();
396
thread->idthread = GetCurrentThreadId();
398
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
399
thread->stk_start = &stack_ptr;
400
thread->stk_size = 0xFFFFFFFFUL;
401
thread->stk_max_usage = 0;
406
if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
407
pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
408
cstr_thread_name, thread->idthread);
410
pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
411
"thr%p", (void*)thread->idthread);
413
rc = pj_thread_local_set(thread_tls_id, thread);
414
if (rc != PJ_SUCCESS)
417
*thread_ptr = thread;
422
* pj_thread_init(void)
424
pj_status_t pj_thread_init(void)
429
rc = pj_thread_local_alloc(&thread_tls_id);
430
if (rc != PJ_SUCCESS)
433
return pj_thread_register("thr%p", main_thread, &thread);
436
static DWORD WINAPI thread_main(void *param)
438
pj_thread_t *rec = param;
441
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
442
rec->stk_start = (char*)&rec;
445
if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
446
pj_assert(!"TLS is not set (pj_init() error?)");
449
PJ_LOG(6,(rec->obj_name, "Thread started"));
451
result = (*rec->proc)(rec->arg);
453
PJ_LOG(6,(rec->obj_name, "Thread quitting"));
454
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
455
PJ_LOG(5,(rec->obj_name, "Thread stack max usage=%u by %s:%d",
456
rec->stk_max_usage, rec->caller_file, rec->caller_line));
459
return (DWORD)result;
463
* pj_thread_create(...)
465
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
466
const char *thread_name,
467
pj_thread_proc *proc,
469
pj_size_t stack_size,
471
pj_thread_t **thread_ptr)
477
PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
480
if (flags & PJ_THREAD_SUSPENDED)
481
dwflags |= CREATE_SUSPENDED;
483
/* Create thread record and assign name for the thread */
484
rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
490
thread_name = "thr%p";
492
if (strchr(thread_name, '%')) {
493
pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
495
pj_ansi_strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
496
rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
499
PJ_LOG(6, (rec->obj_name, "Thread created"));
501
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
502
rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
503
rec->stk_max_usage = 0;
506
/* Create the thread. */
509
rec->hthread = CreateThread(NULL, stack_size,
511
dwflags, &rec->idthread);
512
if (rec->hthread == NULL)
513
return PJ_RETURN_OS_ERROR(GetLastError());
521
* pj_thread-get_name()
523
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
525
pj_thread_t *rec = (pj_thread_t*)p;
528
PJ_ASSERT_RETURN(p, "");
530
return rec->obj_name;
536
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
538
pj_thread_t *rec = (pj_thread_t*)p;
541
PJ_ASSERT_RETURN(p, PJ_EINVAL);
543
if (ResumeThread(rec->hthread) == (DWORD)-1)
544
return PJ_RETURN_OS_ERROR(GetLastError());
552
PJ_DEF(pj_thread_t*) pj_thread_this(void)
554
pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
557
pj_assert(!"Calling pjlib from unknown/external thread. You must "
558
"register external threads with pj_thread_register() "
559
"before calling any pjlib functions.");
563
* MUST NOT check stack because this function is called
564
* by PJ_CHECK_STACK() itself!!!
574
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
576
pj_thread_t *rec = (pj_thread_t *)p;
580
PJ_ASSERT_RETURN(p, PJ_EINVAL);
582
if (p == pj_thread_this())
583
return PJ_ECANCELLED;
585
PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
587
rc = WaitForSingleObject(rec->hthread, INFINITE);
589
if (rc==WAIT_OBJECT_0)
591
else if (rc==WAIT_TIMEOUT)
594
return PJ_RETURN_OS_ERROR(GetLastError());
598
* pj_thread_destroy()
600
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
602
pj_thread_t *rec = (pj_thread_t *)p;
605
PJ_ASSERT_RETURN(p, PJ_EINVAL);
607
if (CloseHandle(rec->hthread) == TRUE)
610
return PJ_RETURN_OS_ERROR(GetLastError());
616
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
623
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
625
* pj_thread_check_stack()
626
* Implementation for PJ_CHECK_STACK()
628
PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
632
pj_thread_t *thread = pj_thread_this();
636
/* Calculate current usage. */
637
usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
638
thread->stk_start - &stk_ptr;
640
/* Assert if stack usage is dangerously high. */
641
pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
643
/* Keep statistic. */
644
if (usage > thread->stk_max_usage) {
645
thread->stk_max_usage = usage;
646
thread->caller_file = file;
647
thread->caller_line = line;
653
* pj_thread_get_stack_max_usage()
655
PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
657
return thread->stk_max_usage;
661
* pj_thread_get_stack_info()
663
PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
669
*file = thread->caller_file;
670
*line = thread->caller_line;
674
#endif /* PJ_OS_HAS_CHECK_STACK */
677
///////////////////////////////////////////////////////////////////////////////
682
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
683
pj_atomic_value_t initial,
684
pj_atomic_t **atomic_ptr)
686
pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
690
atomic_var->value = initial;
691
*atomic_ptr = atomic_var;
697
* pj_atomic_destroy()
699
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
702
PJ_ASSERT_RETURN(var, PJ_EINVAL);
710
PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
714
InterlockedExchange(&atomic_var->value, value);
720
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
723
PJ_ASSERT_RETURN(atomic_var, 0);
725
return atomic_var->value;
729
* pj_atomic_inc_and_get()
731
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
735
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
736
return InterlockedIncrement(&atomic_var->value);
738
return InterlockedIncrement(&atomic_var->value);
745
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
747
pj_atomic_inc_and_get(atomic_var);
751
* pj_atomic_dec_and_get()
753
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
757
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
758
return InterlockedDecrement(&atomic_var->value);
760
return InterlockedDecrement(&atomic_var->value);
767
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
769
pj_atomic_dec_and_get(atomic_var);
775
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
776
pj_atomic_value_t value )
778
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
779
InterlockedExchangeAdd( &atomic_var->value, value );
781
InterlockedExchangeAdd( &atomic_var->value, value );
786
* pj_atomic_add_and_get()
788
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
789
pj_atomic_value_t value)
791
#if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
792
long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
793
return oldValue + value;
795
long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
796
return oldValue + value;
800
///////////////////////////////////////////////////////////////////////////////
802
* pj_thread_local_alloc()
804
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
806
PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
808
//Can't check stack because this function is called in the
809
//beginning before main thread is initialized.
814
if (*index == TLS_OUT_OF_INDEXES)
815
return PJ_RETURN_OS_ERROR(GetLastError());
821
* pj_thread_local_free()
823
PJ_DEF(void) pj_thread_local_free(long index)
830
* pj_thread_local_set()
832
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
836
//Can't check stack because this function is called in the
837
//beginning before main thread is initialized.
839
rc = TlsSetValue(index, value);
840
return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
844
* pj_thread_local_get()
846
PJ_DEF(void*) pj_thread_local_get(long index)
848
//Can't check stack because this function is called
849
//by PJ_CHECK_STACK() itself!!!
851
return TlsGetValue(index);
854
///////////////////////////////////////////////////////////////////////////////
855
static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
860
#if PJ_WIN32_WINNT >= 0x0400
861
InitializeCriticalSection(&mutex->crit);
863
mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
864
if (!mutex->hMutex) {
865
return PJ_RETURN_OS_ERROR(GetLastError());
871
mutex->nesting_level = 0;
879
if (strchr(name, '%')) {
880
pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
882
pj_ansi_strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
883
mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
886
PJ_LOG(6, (mutex->obj_name, "Mutex created"));
893
PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
896
pj_mutex_t **mutex_ptr)
902
PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
904
mutex = pj_pool_alloc(pool, sizeof(*mutex));
908
rc = init_mutex(mutex, name);
909
if (rc != PJ_SUCCESS)
918
* pj_mutex_create_simple()
920
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
924
return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
928
* pj_mutex_create_recursive()
930
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
934
return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
940
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
945
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
947
LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is waiting",
948
pj_thread_this()->obj_name));
950
#if PJ_WIN32_WINNT >= 0x0400
951
EnterCriticalSection(&mutex->crit);
954
if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
957
status = PJ_STATUS_FROM_OS(GetLastError());
960
LOG_MUTEX((mutex->obj_name,
961
(status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
962
pj_thread_this()->obj_name));
965
if (status == PJ_SUCCESS) {
966
mutex->owner = pj_thread_this();
967
++mutex->nesting_level;
977
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
982
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
985
pj_assert(mutex->owner == pj_thread_this());
986
if (--mutex->nesting_level == 0) {
991
LOG_MUTEX((mutex->obj_name, "Mutex released by thread %s",
992
pj_thread_this()->obj_name));
994
#if PJ_WIN32_WINNT >= 0x0400
995
LeaveCriticalSection(&mutex->crit);
998
status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS :
999
PJ_STATUS_FROM_OS(GetLastError());
1005
* pj_mutex_trylock()
1007
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
1012
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1014
LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is trying",
1015
pj_thread_this()->obj_name));
1017
#if PJ_WIN32_WINNT >= 0x0400
1018
status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
1020
status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ?
1021
PJ_SUCCESS : PJ_ETIMEDOUT;
1023
if (status==PJ_SUCCESS) {
1024
LOG_MUTEX((mutex->obj_name, "Mutex acquired by thread %s",
1025
pj_thread_this()->obj_name));
1028
mutex->owner = pj_thread_this();
1029
++mutex->nesting_level;
1032
LOG_MUTEX((mutex->obj_name, "Mutex: thread %s's trylock() failed",
1033
pj_thread_this()->obj_name));
1040
* pj_mutex_destroy()
1042
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
1045
PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1047
LOG_MUTEX((mutex->obj_name, "Mutex destroyed"));
1049
#if PJ_WIN32_WINNT >= 0x0400
1050
DeleteCriticalSection(&mutex->crit);
1053
return CloseHandle(mutex->hMutex) ? PJ_SUCCESS :
1054
PJ_RETURN_OS_ERROR(GetLastError());
1059
* pj_mutex_is_locked()
1061
PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
1064
return mutex->owner == pj_thread_this();
1066
PJ_UNUSED_ARG(mutex);
1067
pj_assert(!"PJ_DEBUG is not set!");
1072
///////////////////////////////////////////////////////////////////////////////
1074
* Win32 lacks Read/Write mutex, so include the emulation.
1076
#include "os_rwmutex.c"
1078
///////////////////////////////////////////////////////////////////////////////
1080
* pj_enter_critical_section()
1082
PJ_DEF(void) pj_enter_critical_section(void)
1084
pj_mutex_lock(&critical_section_mutex);
1089
* pj_leave_critical_section()
1091
PJ_DEF(void) pj_leave_critical_section(void)
1093
pj_mutex_unlock(&critical_section_mutex);
1096
///////////////////////////////////////////////////////////////////////////////
1097
#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
1102
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
1111
PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
1113
sem = pj_pool_alloc(pool, sizeof(*sem));
1114
sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
1115
if (!sem->hSemaphore)
1116
return PJ_RETURN_OS_ERROR(GetLastError());
1122
if (strchr(name, '%')) {
1123
pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
1125
pj_ansi_strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
1126
sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1129
LOG_MUTEX((sem->obj_name, "Semaphore created"));
1135
static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
1140
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1142
LOG_MUTEX((sem->obj_name, "Semaphore: thread %s is waiting",
1143
pj_thread_this()->obj_name));
1145
result = WaitForSingleObject(sem->hSemaphore, timeout);
1146
if (result == WAIT_OBJECT_0) {
1147
LOG_MUTEX((sem->obj_name, "Semaphore acquired by thread %s",
1148
pj_thread_this()->obj_name));
1150
LOG_MUTEX((sem->obj_name, "Semaphore: thread %s FAILED to acquire",
1151
pj_thread_this()->obj_name));
1154
if (result==WAIT_OBJECT_0)
1156
else if (result==WAIT_TIMEOUT)
1157
return PJ_ETIMEDOUT;
1159
return PJ_RETURN_OS_ERROR(GetLastError());
1165
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
1168
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1170
return pj_sem_wait_for(sem, INFINITE);
1176
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
1179
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1181
return pj_sem_wait_for(sem, 0);
1187
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
1190
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1192
LOG_MUTEX((sem->obj_name, "Semaphore released by thread %s",
1193
pj_thread_this()->obj_name));
1195
if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
1198
return PJ_RETURN_OS_ERROR(GetLastError());
1204
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
1207
PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1209
LOG_MUTEX((sem->obj_name, "Semaphore destroyed by thread %s",
1210
pj_thread_this()->obj_name));
1212
if (CloseHandle(sem->hSemaphore))
1215
return PJ_RETURN_OS_ERROR(GetLastError());
1218
#endif /* PJ_HAS_SEMAPHORE */
1219
///////////////////////////////////////////////////////////////////////////////
1222
#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
1227
PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool,
1229
pj_bool_t manual_reset,
1231
pj_event_t **event_ptr)
1236
PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
1238
event = pj_pool_alloc(pool, sizeof(*event));
1242
event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE,
1243
initial?TRUE:FALSE, NULL);
1246
return PJ_RETURN_OS_ERROR(GetLastError());
1252
if (strchr(name, '%')) {
1253
pj_ansi_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
1255
pj_ansi_strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
1256
event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1259
PJ_LOG(6, (event->obj_name, "Event created"));
1265
static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
1270
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1272
PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting",
1273
pj_thread_this()->obj_name));
1275
result = WaitForSingleObject(event->hEvent, timeout);
1276
if (result == WAIT_OBJECT_0) {
1277
PJ_LOG(6, (event->obj_name, "Event: thread %s is released",
1278
pj_thread_this()->obj_name));
1280
PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire",
1281
pj_thread_this()->obj_name));
1284
if (result==WAIT_OBJECT_0)
1286
else if (result==WAIT_TIMEOUT)
1287
return PJ_ETIMEDOUT;
1289
return PJ_RETURN_OS_ERROR(GetLastError());
1295
PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
1297
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1299
return pj_event_wait_for(event, INFINITE);
1303
* pj_event_trywait()
1305
PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
1307
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1309
return pj_event_wait_for(event, 0);
1315
PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
1318
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1320
PJ_LOG(6, (event->obj_name, "Setting event"));
1322
if (SetEvent(event->hEvent))
1325
return PJ_RETURN_OS_ERROR(GetLastError());
1331
PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
1334
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1336
PJ_LOG(6, (event->obj_name, "Pulsing event"));
1338
if (PulseEvent(event->hEvent))
1341
return PJ_RETURN_OS_ERROR(GetLastError());
1347
PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
1350
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1352
PJ_LOG(6, (event->obj_name, "Event is reset"));
1354
if (ResetEvent(event->hEvent))
1357
return PJ_RETURN_OS_ERROR(GetLastError());
1361
* pj_event_destroy()
1363
PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
1366
PJ_ASSERT_RETURN(event, PJ_EINVAL);
1368
PJ_LOG(6, (event->obj_name, "Event is destroying"));
1370
if (CloseHandle(event->hEvent))
1373
return PJ_RETURN_OS_ERROR(GetLastError());
1376
#endif /* PJ_HAS_EVENT_OBJ */
1378
///////////////////////////////////////////////////////////////////////////////
1379
#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
1384
static WORD pj_color_to_os_attr(pj_color_t color)
1388
if (color & PJ_TERM_COLOR_R)
1389
attr |= FOREGROUND_RED;
1390
if (color & PJ_TERM_COLOR_G)
1391
attr |= FOREGROUND_GREEN;
1392
if (color & PJ_TERM_COLOR_B)
1393
attr |= FOREGROUND_BLUE;
1394
if (color & PJ_TERM_COLOR_BRIGHT)
1395
attr |= FOREGROUND_INTENSITY;
1400
static pj_color_t os_attr_to_pj_color(WORD attr)
1404
if (attr & FOREGROUND_RED)
1405
color |= PJ_TERM_COLOR_R;
1406
if (attr & FOREGROUND_GREEN)
1407
color |= PJ_TERM_COLOR_G;
1408
if (attr & FOREGROUND_BLUE)
1409
color |= PJ_TERM_COLOR_B;
1410
if (attr & FOREGROUND_INTENSITY)
1411
color |= PJ_TERM_COLOR_BRIGHT;
1418
* pj_term_set_color()
1420
PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
1427
attr = pj_color_to_os_attr(color);
1428
rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
1429
return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
1433
* pj_term_get_color()
1434
* Get current terminal foreground color.
1436
PJ_DEF(pj_color_t) pj_term_get_color(void)
1438
CONSOLE_SCREEN_BUFFER_INFO info;
1442
GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
1443
return os_attr_to_pj_color(info.wAttributes);
1446
#endif /* PJ_TERM_HAS_COLOR */
1451
PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1454
PJ_UNUSED_ARG(flags);
1455
return (*main_func)(argc, argv);