1 /* $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/pool.h>
22 #include <pj/log.h>
23 #include <pj/string.h>
24 #include <pj/guid.h>
25 #include <pj/rand.h>
26 #include <pj/assert.h>
27 #include <pj/errno.h>
28 #include <pj/except.h>
29 #include <stddef.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
34 # include <winsock2.h>
35 #endif
36
37 #if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
38 # include <winsock.h>
39 #endif
40
41 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
42 # include "../../../third_party/threademulation/include/ThreadEmulation.h"
43 #endif
44
45 /* Activate mutex related logging if PJ_DEBUG_MUTEX is set, otherwise
46 * use default level 6 logging.
47 */
48 #if defined(PJ_DEBUG_MUTEX) && PJ_DEBUG_MUTEX
49 # undef PJ_DEBUG
50 # define PJ_DEBUG 1
51 # define LOG_MUTEX(expr) PJ_LOG(5,expr)
52 #else
53 # define LOG_MUTEX(expr) PJ_LOG(6,expr)
54 #endif
55
56 #define THIS_FILE "os_core_win32.c"
57
58 /*
59 * Implementation of pj_thread_t.
60 */
61 struct pj_thread_t
62 {
63 char obj_name[PJ_MAX_OBJ_NAME];
64 HANDLE hthread;
65 DWORD idthread;
66 pj_thread_proc *proc;
67 void *arg;
68
69 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
70 pj_uint32_t stk_size;
71 pj_uint32_t stk_max_usage;
72 char *stk_start;
73 const char *caller_file;
74 int caller_line;
75 #endif
76 };
77
78
79 /*
80 * Implementation of pj_mutex_t.
81 */
82 struct pj_mutex_t
83 {
84 #if PJ_WIN32_WINNT >= 0x0400
85 CRITICAL_SECTION crit;
86 #else
87 HANDLE hMutex;
88 #endif
89 char obj_name[PJ_MAX_OBJ_NAME];
90 #if PJ_DEBUG
91 int nesting_level;
92 pj_thread_t *owner;
93 #endif
94 };
95
96 /*
97 * Implementation of pj_sem_t.
98 */
99 typedef struct pj_sem_t
100 {
101 HANDLE hSemaphore;
102 char obj_name[PJ_MAX_OBJ_NAME];
103 } pj_mem_t;
104
105
106 /*
107 * Implementation of pj_event_t.
108 */
109 struct pj_event_t
110 {
111 HANDLE hEvent;
112 char obj_name[PJ_MAX_OBJ_NAME];
113 };
114
115 /*
116 * Implementation of pj_atomic_t.
117 */
118 struct pj_atomic_t
119 {
120 long value;
121 };
122
123 /*
124 * Flag and reference counter for PJLIB instance.
125 */
126 static int initialized;
127
128 /*
129 * Static global variables.
130 */
131 static pj_thread_desc main_thread;
132 static long thread_tls_id = -1;
133 static pj_mutex_t critical_section_mutex;
134 static unsigned atexit_count;
135 static void (*atexit_func[32])(void);
136
137 /*
138 * Some static prototypes.
139 */
140 static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
141
142
143 /*
144 * pj_init(void).
145 * Init PJLIB!
146 */
pj_init(void)147 PJ_DEF(pj_status_t) pj_init(void)
148 {
149 WSADATA wsa;
150 char dummy_guid[32]; /* use maximum GUID length */
151 pj_str_t guid;
152 pj_status_t rc;
153
154 /* Check if PJLIB have been initialized */
155 if (initialized) {
156 ++initialized;
157 return PJ_SUCCESS;
158 }
159
160 /* Init Winsock.. */
161 if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
162 return PJ_RETURN_OS_ERROR(WSAGetLastError());
163 }
164
165 /* Init this thread's TLS. */
166 if ((rc=pj_thread_init()) != PJ_SUCCESS) {
167 return rc;
168 }
169
170 /* Init logging */
171 pj_log_init();
172
173 /* Init random seed. */
174 /* Or probably not. Let application in charge of this */
175 /* pj_srand( GetCurrentProcessId() ); */
176
177 /* Initialize critical section. */
178 if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
179 return rc;
180
181 /* Startup GUID. */
182 guid.ptr = dummy_guid;
183 pj_generate_unique_string( &guid );
184
185 /* Initialize exception ID for the pool.
186 * Must do so after critical section is configured.
187 */
188 rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
189 if (rc != PJ_SUCCESS)
190 return rc;
191
192 /* Startup timestamp */
193 #if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
194 {
195 pj_timestamp dummy_ts;
196 if ((rc=pj_get_timestamp_freq(&dummy_ts)) != PJ_SUCCESS) {
197 return rc;
198 }
199 if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
200 return rc;
201 }
202 }
203 #endif
204
205 /* Flag PJLIB as initialized */
206 ++initialized;
207 pj_assert(initialized == 1);
208
209 PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
210 PJ_VERSION));
211
212 return PJ_SUCCESS;
213 }
214
215 /*
216 * pj_atexit()
217 */
pj_atexit(void (* func)(void))218 PJ_DEF(pj_status_t) pj_atexit(void (*func)(void))
219 {
220 if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
221 return PJ_ETOOMANY;
222
223 atexit_func[atexit_count++] = func;
224 return PJ_SUCCESS;
225 }
226
227
228 /*
229 * pj_shutdown(void)
230 */
pj_shutdown()231 PJ_DEF(void) pj_shutdown()
232 {
233 int i;
234
235 /* Only perform shutdown operation when 'initialized' reaches zero */
236 pj_assert(initialized > 0);
237 if (--initialized != 0)
238 return;
239
240 /* Display stack usage */
241 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
242 {
243 pj_thread_t *rec = (pj_thread_t*)main_thread;
244 PJ_LOG(5,(rec->obj_name, "Main thread stack max usage=%u by %s:%d",
245 rec->stk_max_usage, rec->caller_file, rec->caller_line));
246 }
247 #endif
248
249 /* Call atexit() functions */
250 for (i=atexit_count-1; i>=0; --i) {
251 (*atexit_func[i])();
252 }
253 atexit_count = 0;
254
255 /* Free exception ID */
256 if (PJ_NO_MEMORY_EXCEPTION != -1) {
257 pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
258 PJ_NO_MEMORY_EXCEPTION = -1;
259 }
260
261 /* Destroy PJLIB critical section */
262 pj_mutex_destroy(&critical_section_mutex);
263
264 /* Free PJLIB TLS */
265 if (thread_tls_id != -1) {
266 pj_thread_local_free(thread_tls_id);
267 thread_tls_id = -1;
268 }
269
270 /* Clear static variables */
271 pj_errno_clear_handlers();
272
273 /* Ticket #1132: Assertion when (re)starting PJLIB on different thread */
274 pj_bzero(main_thread, sizeof(main_thread));
275
276 /* Shutdown Winsock */
277 WSACleanup();
278 }
279
280
281 /*
282 * pj_getpid(void)
283 */
pj_getpid(void)284 PJ_DEF(pj_uint32_t) pj_getpid(void)
285 {
286 PJ_CHECK_STACK();
287 return GetCurrentProcessId();
288 }
289
290 /*
291 * Check if this thread has been registered to PJLIB.
292 */
pj_thread_is_registered(void)293 PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
294 {
295 return pj_thread_local_get(thread_tls_id) != 0;
296 }
297
298
299 /*
300 * Get thread priority value for the thread.
301 */
pj_thread_get_prio(pj_thread_t * thread)302 PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
303 {
304 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
305 PJ_UNUSED_ARG(thread);
306 return -1;
307 #else
308 return GetThreadPriority(thread->hthread);
309 #endif
310 }
311
312
313 /*
314 * Set the thread priority.
315 */
pj_thread_set_prio(pj_thread_t * thread,int prio)316 PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread, int prio)
317 {
318 #if PJ_HAS_THREADS
319 PJ_ASSERT_RETURN(thread, PJ_EINVAL);
320 PJ_ASSERT_RETURN(prio>=THREAD_PRIORITY_IDLE &&
321 prio<=THREAD_PRIORITY_TIME_CRITICAL,
322 PJ_EINVAL);
323
324 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
325 if (SetThreadPriorityRT(thread->hthread, prio) == FALSE)
326 #else
327 if (SetThreadPriority(thread->hthread, prio) == FALSE)
328 #endif
329 return PJ_RETURN_OS_ERROR(GetLastError());
330
331 return PJ_SUCCESS;
332
333 #else
334 PJ_UNUSED_ARG(thread);
335 PJ_UNUSED_ARG(prio);
336 pj_assert("pj_thread_set_prio() called in non-threading mode!");
337 return PJ_EINVALIDOP;
338 #endif
339 }
340
341
342 /*
343 * Get the lowest priority value available on this system.
344 */
pj_thread_get_prio_min(pj_thread_t * thread)345 PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
346 {
347 PJ_UNUSED_ARG(thread);
348 return THREAD_PRIORITY_IDLE;
349 }
350
351
352 /*
353 * Get the highest priority value available on this system.
354 */
pj_thread_get_prio_max(pj_thread_t * thread)355 PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
356 {
357 PJ_UNUSED_ARG(thread);
358 return THREAD_PRIORITY_TIME_CRITICAL;
359 }
360
361
362 /*
363 * Get native thread handle
364 */
pj_thread_get_os_handle(pj_thread_t * thread)365 PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
366 {
367 PJ_ASSERT_RETURN(thread, NULL);
368
369 #if PJ_HAS_THREADS
370 return thread->hthread;
371 #else
372 pj_assert("pj_thread_is_registered() called in non-threading mode!");
373 return NULL;
374 #endif
375 }
376
377 /*
378 * pj_thread_register(..)
379 */
pj_thread_register(const char * cstr_thread_name,pj_thread_desc desc,pj_thread_t ** thread_ptr)380 PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
381 pj_thread_desc desc,
382 pj_thread_t **thread_ptr)
383 {
384 char stack_ptr;
385 pj_status_t rc;
386 pj_thread_t *thread = (pj_thread_t *)desc;
387 pj_str_t thread_name = pj_str((char*)cstr_thread_name);
388
389 /* Size sanity check. */
390 if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
391 pj_assert(!"Not enough pj_thread_desc size!");
392 return PJ_EBUG;
393 }
394
395 /* If a thread descriptor has been registered before, just return it. */
396 if (pj_thread_local_get (thread_tls_id) != 0) {
397 // 2006-02-26 bennylp:
398 // This wouldn't work in all cases!.
399 // If thread is created by external module (e.g. sound thread),
400 // thread may be reused while the pool used for the thread descriptor
401 // has been deleted by application.
402 //*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
403 //return PJ_SUCCESS;
404 }
405
406 /* Initialize and set the thread entry. */
407 pj_bzero(desc, sizeof(struct pj_thread_t));
408 thread->hthread = GetCurrentThread();
409 thread->idthread = GetCurrentThreadId();
410
411 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
412 thread->stk_start = &stack_ptr;
413 thread->stk_size = 0xFFFFFFFFUL;
414 thread->stk_max_usage = 0;
415 #else
416 stack_ptr = '\0';
417 #endif
418
419 if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
420 pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
421 cstr_thread_name, thread->idthread);
422 else
423 pj_ansi_snprintf(thread->obj_name, sizeof(thread->obj_name),
424 "thr%p", (void*)(pj_ssize_t)thread->idthread);
425
426 rc = pj_thread_local_set(thread_tls_id, thread);
427 if (rc != PJ_SUCCESS)
428 return rc;
429
430 *thread_ptr = thread;
431 return PJ_SUCCESS;
432 }
433
434 /*
435 * pj_thread_init(void)
436 */
pj_thread_init(void)437 pj_status_t pj_thread_init(void)
438 {
439 pj_status_t rc;
440 pj_thread_t *thread;
441
442 rc = pj_thread_local_alloc(&thread_tls_id);
443 if (rc != PJ_SUCCESS)
444 return rc;
445
446 return pj_thread_register("thr%p", main_thread, &thread);
447 }
448
thread_main(void * param)449 static DWORD WINAPI thread_main(void *param)
450 {
451 pj_thread_t *rec = param;
452 DWORD result;
453
454 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
455 rec->stk_start = (char*)&rec;
456 #endif
457
458 if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
459 pj_assert(!"TLS is not set (pj_init() error?)");
460 }
461
462 PJ_LOG(6,(rec->obj_name, "Thread started"));
463
464 result = (*rec->proc)(rec->arg);
465
466 PJ_LOG(6,(rec->obj_name, "Thread quitting"));
467 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
468 PJ_LOG(5,(rec->obj_name, "Thread stack max usage=%u by %s:%d",
469 rec->stk_max_usage, rec->caller_file, rec->caller_line));
470 #endif
471
472 return (DWORD)result;
473 }
474
475 /*
476 * pj_thread_create(...)
477 */
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)478 PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
479 const char *thread_name,
480 pj_thread_proc *proc,
481 void *arg,
482 pj_size_t stack_size,
483 unsigned flags,
484 pj_thread_t **thread_ptr)
485 {
486 DWORD dwflags = 0;
487 pj_thread_t *rec;
488
489 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
490 PJ_UNUSED_ARG(stack_size);
491 #endif
492
493 PJ_CHECK_STACK();
494 PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
495
496 /* Set flags */
497 if (flags & PJ_THREAD_SUSPENDED)
498 dwflags |= CREATE_SUSPENDED;
499
500 /* Create thread record and assign name for the thread */
501 rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
502 if (!rec)
503 return PJ_ENOMEM;
504
505 /* Set name. */
506 if (!thread_name)
507 thread_name = "thr%p";
508
509 if (strchr(thread_name, '%')) {
510 pj_ansi_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
511 } else {
512 pj_ansi_strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
513 rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
514 }
515
516 PJ_LOG(6, (rec->obj_name, "Thread created"));
517
518 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
519 rec->stk_size = stack_size ? (pj_uint32_t)stack_size : 0xFFFFFFFFUL;
520 rec->stk_max_usage = 0;
521 #endif
522
523 /* Create the thread. */
524 rec->proc = proc;
525 rec->arg = arg;
526
527 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
528 rec->hthread = CreateThreadRT(NULL, 0,
529 thread_main, rec,
530 dwflags, NULL);
531 #else
532 rec->hthread = CreateThread(NULL, stack_size,
533 thread_main, rec,
534 dwflags, &rec->idthread);
535 #endif
536
537 if (rec->hthread == NULL)
538 return PJ_RETURN_OS_ERROR(GetLastError());
539
540 /* Success! */
541 *thread_ptr = rec;
542 return PJ_SUCCESS;
543 }
544
545 /*
546 * pj_thread-get_name()
547 */
pj_thread_get_name(pj_thread_t * p)548 PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
549 {
550 pj_thread_t *rec = (pj_thread_t*)p;
551
552 PJ_CHECK_STACK();
553 PJ_ASSERT_RETURN(p, "");
554
555 return rec->obj_name;
556 }
557
558 /*
559 * pj_thread_resume()
560 */
pj_thread_resume(pj_thread_t * p)561 PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
562 {
563 pj_thread_t *rec = (pj_thread_t*)p;
564
565 PJ_CHECK_STACK();
566 PJ_ASSERT_RETURN(p, PJ_EINVAL);
567
568 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
569 if (ResumeThreadRT(rec->hthread) == (DWORD)-1)
570 #else
571 if (ResumeThread(rec->hthread) == (DWORD)-1)
572 #endif
573 return PJ_RETURN_OS_ERROR(GetLastError());
574 else
575 return PJ_SUCCESS;
576 }
577
578 /*
579 * pj_thread_this()
580 */
pj_thread_this(void)581 PJ_DEF(pj_thread_t*) pj_thread_this(void)
582 {
583 pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
584
585 if (rec == NULL) {
586 pj_assert(!"Calling pjlib from unknown/external thread. You must "
587 "register external threads with pj_thread_register() "
588 "before calling any pjlib functions.");
589 }
590
591 /*
592 * MUST NOT check stack because this function is called
593 * by PJ_CHECK_STACK() itself!!!
594 *
595 */
596
597 return rec;
598 }
599
600 /*
601 * pj_thread_join()
602 */
pj_thread_join(pj_thread_t * p)603 PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
604 {
605 pj_thread_t *rec = (pj_thread_t *)p;
606 DWORD rc;
607
608 PJ_CHECK_STACK();
609 PJ_ASSERT_RETURN(p, PJ_EINVAL);
610
611 if (p == pj_thread_this())
612 return PJ_ECANCELLED;
613
614 PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
615
616 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
617 rc = WaitForSingleObjectEx(rec->hthread, INFINITE, FALSE);
618 #else
619 rc = WaitForSingleObject(rec->hthread, INFINITE);
620 #endif
621
622 if (rc==WAIT_OBJECT_0)
623 return PJ_SUCCESS;
624 else if (rc==WAIT_TIMEOUT)
625 return PJ_ETIMEDOUT;
626 else
627 return PJ_RETURN_OS_ERROR(GetLastError());
628 }
629
630 /*
631 * pj_thread_destroy()
632 */
pj_thread_destroy(pj_thread_t * p)633 PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
634 {
635 pj_thread_t *rec = (pj_thread_t *)p;
636
637 PJ_CHECK_STACK();
638 PJ_ASSERT_RETURN(p, PJ_EINVAL);
639
640 if (CloseHandle(rec->hthread) == TRUE)
641 return PJ_SUCCESS;
642 else
643 return PJ_RETURN_OS_ERROR(GetLastError());
644 }
645
646 /*
647 * pj_thread_sleep()
648 */
pj_thread_sleep(unsigned msec)649 PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
650 {
651 PJ_CHECK_STACK();
652
653 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
654 SleepRT(msec);
655 #else
656 Sleep(msec);
657 #endif
658
659 return PJ_SUCCESS;
660 }
661
662 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
663 /*
664 * pj_thread_check_stack()
665 * Implementation for PJ_CHECK_STACK()
666 */
pj_thread_check_stack(const char * file,int line)667 PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
668 {
669 char stk_ptr;
670 pj_uint32_t usage;
671 pj_thread_t *thread = pj_thread_this();
672
673 pj_assert(thread);
674
675 /* Calculate current usage. */
676 usage = (&stk_ptr > thread->stk_start) ?
677 (pj_uint32_t)(&stk_ptr - thread->stk_start) :
678 (pj_uint32_t)(thread->stk_start - &stk_ptr);
679
680 /* Assert if stack usage is dangerously high. */
681 pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
682
683 /* Keep statistic. */
684 if (usage > thread->stk_max_usage) {
685 thread->stk_max_usage = usage;
686 thread->caller_file = file;
687 thread->caller_line = line;
688 }
689
690 }
691
692 /*
693 * pj_thread_get_stack_max_usage()
694 */
pj_thread_get_stack_max_usage(pj_thread_t * thread)695 PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
696 {
697 return thread->stk_max_usage;
698 }
699
700 /*
701 * pj_thread_get_stack_info()
702 */
pj_thread_get_stack_info(pj_thread_t * thread,const char ** file,int * line)703 PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
704 const char **file,
705 int *line )
706 {
707 pj_assert(thread);
708
709 *file = thread->caller_file;
710 *line = thread->caller_line;
711 return 0;
712 }
713
714 #endif /* PJ_OS_HAS_CHECK_STACK */
715
716
717 ///////////////////////////////////////////////////////////////////////////////
718
719 /*
720 * pj_atomic_create()
721 */
pj_atomic_create(pj_pool_t * pool,pj_atomic_value_t initial,pj_atomic_t ** atomic_ptr)722 PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
723 pj_atomic_value_t initial,
724 pj_atomic_t **atomic_ptr)
725 {
726 pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
727 if (!atomic_var)
728 return PJ_ENOMEM;
729
730 atomic_var->value = initial;
731 *atomic_ptr = atomic_var;
732
733 return PJ_SUCCESS;
734 }
735
736 /*
737 * pj_atomic_destroy()
738 */
pj_atomic_destroy(pj_atomic_t * var)739 PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
740 {
741 PJ_UNUSED_ARG(var);
742 PJ_ASSERT_RETURN(var, PJ_EINVAL);
743
744 return 0;
745 }
746
747 /*
748 * pj_atomic_set()
749 */
pj_atomic_set(pj_atomic_t * atomic_var,pj_atomic_value_t value)750 PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
751 {
752 PJ_CHECK_STACK();
753 PJ_ASSERT_ON_FAIL(atomic_var, return);
754
755 InterlockedExchange(&atomic_var->value, value);
756 }
757
758 /*
759 * pj_atomic_get()
760 */
pj_atomic_get(pj_atomic_t * atomic_var)761 PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
762 {
763 PJ_CHECK_STACK();
764 PJ_ASSERT_RETURN(atomic_var, 0);
765
766 return atomic_var->value;
767 }
768
769 /*
770 * pj_atomic_inc_and_get()
771 */
pj_atomic_inc_and_get(pj_atomic_t * atomic_var)772 PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
773 {
774 PJ_CHECK_STACK();
775
776 #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
777 return InterlockedIncrement(&atomic_var->value);
778 #else
779 return InterlockedIncrement(&atomic_var->value);
780 #endif
781 }
782
783 /*
784 * pj_atomic_inc()
785 */
pj_atomic_inc(pj_atomic_t * atomic_var)786 PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
787 {
788 PJ_ASSERT_ON_FAIL(atomic_var, return);
789 pj_atomic_inc_and_get(atomic_var);
790 }
791
792 /*
793 * pj_atomic_dec_and_get()
794 */
pj_atomic_dec_and_get(pj_atomic_t * atomic_var)795 PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
796 {
797 PJ_CHECK_STACK();
798
799 #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
800 return InterlockedDecrement(&atomic_var->value);
801 #else
802 return InterlockedDecrement(&atomic_var->value);
803 #endif
804 }
805
806 /*
807 * pj_atomic_dec()
808 */
pj_atomic_dec(pj_atomic_t * atomic_var)809 PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
810 {
811 PJ_ASSERT_ON_FAIL(atomic_var, return);
812 pj_atomic_dec_and_get(atomic_var);
813 }
814
815 /*
816 * pj_atomic_add()
817 */
pj_atomic_add(pj_atomic_t * atomic_var,pj_atomic_value_t value)818 PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
819 pj_atomic_value_t value )
820 {
821 PJ_ASSERT_ON_FAIL(atomic_var, return);
822 #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
823 InterlockedExchangeAdd( &atomic_var->value, value );
824 #else
825 InterlockedExchangeAdd( &atomic_var->value, value );
826 #endif
827 }
828
829 /*
830 * pj_atomic_add_and_get()
831 */
pj_atomic_add_and_get(pj_atomic_t * atomic_var,pj_atomic_value_t value)832 PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
833 pj_atomic_value_t value)
834 {
835 #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400
836 long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
837 return oldValue + value;
838 #else
839 long oldValue = InterlockedExchangeAdd( &atomic_var->value, value);
840 return oldValue + value;
841 #endif
842 }
843
844 ///////////////////////////////////////////////////////////////////////////////
845 /*
846 * pj_thread_local_alloc()
847 */
pj_thread_local_alloc(long * index)848 PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
849 {
850 PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
851
852 //Can't check stack because this function is called in the
853 //beginning before main thread is initialized.
854 //PJ_CHECK_STACK();
855
856 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
857 *index = TlsAllocRT();
858 #else
859 *index = TlsAlloc();
860 #endif
861
862 if (*index == TLS_OUT_OF_INDEXES)
863 return PJ_RETURN_OS_ERROR(GetLastError());
864 else
865 return PJ_SUCCESS;
866 }
867
868 /*
869 * pj_thread_local_free()
870 */
pj_thread_local_free(long index)871 PJ_DEF(void) pj_thread_local_free(long index)
872 {
873 PJ_CHECK_STACK();
874 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
875 TlsFreeRT(index);
876 #else
877 TlsFree(index);
878 #endif
879 }
880
881 /*
882 * pj_thread_local_set()
883 */
pj_thread_local_set(long index,void * value)884 PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
885 {
886 BOOL rc;
887
888 //Can't check stack because this function is called in the
889 //beginning before main thread is initialized.
890 //PJ_CHECK_STACK();
891
892 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
893 rc = TlsSetValueRT(index, value);
894 #else
895 rc = TlsSetValue(index, value);
896 #endif
897
898 return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
899 }
900
901 /*
902 * pj_thread_local_get()
903 */
pj_thread_local_get(long index)904 PJ_DEF(void*) pj_thread_local_get(long index)
905 {
906 //Can't check stack because this function is called
907 //by PJ_CHECK_STACK() itself!!!
908 //PJ_CHECK_STACK();
909 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
910 return TlsGetValueRT(index);
911 #else
912 return TlsGetValue(index);
913 #endif
914 }
915
916 ///////////////////////////////////////////////////////////////////////////////
init_mutex(pj_mutex_t * mutex,const char * name)917 static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
918 {
919
920 PJ_CHECK_STACK();
921
922 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
923 InitializeCriticalSectionEx(&mutex->crit, 0, 0);
924 #elif PJ_WIN32_WINNT >= 0x0400
925 InitializeCriticalSection(&mutex->crit);
926 #else
927 mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
928 if (!mutex->hMutex) {
929 return PJ_RETURN_OS_ERROR(GetLastError());
930 }
931 #endif
932
933 #if PJ_DEBUG
934 /* Set owner. */
935 mutex->nesting_level = 0;
936 mutex->owner = NULL;
937 #endif
938
939 /* Set name. */
940 if (!name) {
941 name = "mtx%p";
942 }
943 if (strchr(name, '%')) {
944 pj_ansi_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
945 } else {
946 pj_ansi_strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
947 mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
948 }
949
950 PJ_LOG(6, (mutex->obj_name, "Mutex created"));
951 return PJ_SUCCESS;
952 }
953
954 /*
955 * pj_mutex_create()
956 */
pj_mutex_create(pj_pool_t * pool,const char * name,int type,pj_mutex_t ** mutex_ptr)957 PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool,
958 const char *name,
959 int type,
960 pj_mutex_t **mutex_ptr)
961 {
962 pj_status_t rc;
963 pj_mutex_t *mutex;
964
965 PJ_UNUSED_ARG(type);
966 PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
967
968 mutex = pj_pool_alloc(pool, sizeof(*mutex));
969 if (!mutex)
970 return PJ_ENOMEM;
971
972 rc = init_mutex(mutex, name);
973 if (rc != PJ_SUCCESS)
974 return rc;
975
976 *mutex_ptr = mutex;
977
978 return PJ_SUCCESS;
979 }
980
981 /*
982 * pj_mutex_create_simple()
983 */
pj_mutex_create_simple(pj_pool_t * pool,const char * name,pj_mutex_t ** mutex)984 PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
985 const char *name,
986 pj_mutex_t **mutex )
987 {
988 return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
989 }
990
991 /*
992 * pj_mutex_create_recursive()
993 */
pj_mutex_create_recursive(pj_pool_t * pool,const char * name,pj_mutex_t ** mutex)994 PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
995 const char *name,
996 pj_mutex_t **mutex )
997 {
998 return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
999 }
1000
1001 /*
1002 * pj_mutex_lock()
1003 */
pj_mutex_lock(pj_mutex_t * mutex)1004 PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
1005 {
1006 pj_status_t status;
1007
1008 PJ_CHECK_STACK();
1009 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1010
1011 LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is waiting",
1012 pj_thread_this()->obj_name));
1013
1014 #if PJ_WIN32_WINNT >= 0x0400
1015 EnterCriticalSection(&mutex->crit);
1016 status=PJ_SUCCESS;
1017 #else
1018 if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
1019 status = PJ_SUCCESS;
1020 else
1021 status = PJ_STATUS_FROM_OS(GetLastError());
1022
1023 #endif
1024 LOG_MUTEX((mutex->obj_name,
1025 (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
1026 pj_thread_this()->obj_name));
1027
1028 #if PJ_DEBUG
1029 if (status == PJ_SUCCESS) {
1030 mutex->owner = pj_thread_this();
1031 ++mutex->nesting_level;
1032 }
1033 #endif
1034
1035 return status;
1036 }
1037
1038 /*
1039 * pj_mutex_unlock()
1040 */
pj_mutex_unlock(pj_mutex_t * mutex)1041 PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
1042 {
1043 pj_status_t status;
1044
1045 PJ_CHECK_STACK();
1046 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1047
1048 #if PJ_DEBUG
1049 pj_assert(mutex->owner == pj_thread_this());
1050 if (--mutex->nesting_level == 0) {
1051 mutex->owner = NULL;
1052 }
1053 #endif
1054
1055 LOG_MUTEX((mutex->obj_name, "Mutex released by thread %s",
1056 pj_thread_this()->obj_name));
1057
1058 #if PJ_WIN32_WINNT >= 0x0400
1059 LeaveCriticalSection(&mutex->crit);
1060 status=PJ_SUCCESS;
1061 #else
1062 status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS :
1063 PJ_STATUS_FROM_OS(GetLastError());
1064 #endif
1065 return status;
1066 }
1067
1068 /*
1069 * pj_mutex_trylock()
1070 */
pj_mutex_trylock(pj_mutex_t * mutex)1071 PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
1072 {
1073 pj_status_t status;
1074
1075 PJ_CHECK_STACK();
1076 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1077
1078 LOG_MUTEX((mutex->obj_name, "Mutex: thread %s is trying",
1079 pj_thread_this()->obj_name));
1080
1081 #if PJ_WIN32_WINNT >= 0x0400
1082 status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
1083 #else
1084 status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ?
1085 PJ_SUCCESS : PJ_ETIMEDOUT;
1086 #endif
1087 if (status==PJ_SUCCESS) {
1088 LOG_MUTEX((mutex->obj_name, "Mutex acquired by thread %s",
1089 pj_thread_this()->obj_name));
1090
1091 #if PJ_DEBUG
1092 mutex->owner = pj_thread_this();
1093 ++mutex->nesting_level;
1094 #endif
1095 } else {
1096 LOG_MUTEX((mutex->obj_name, "Mutex: thread %s's trylock() failed",
1097 pj_thread_this()->obj_name));
1098 }
1099
1100 return status;
1101 }
1102
1103 /*
1104 * pj_mutex_destroy()
1105 */
pj_mutex_destroy(pj_mutex_t * mutex)1106 PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
1107 {
1108 PJ_CHECK_STACK();
1109 PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
1110
1111 LOG_MUTEX((mutex->obj_name, "Mutex destroyed"));
1112
1113 #if PJ_WIN32_WINNT >= 0x0400
1114 DeleteCriticalSection(&mutex->crit);
1115 return PJ_SUCCESS;
1116 #else
1117 return CloseHandle(mutex->hMutex) ? PJ_SUCCESS :
1118 PJ_RETURN_OS_ERROR(GetLastError());
1119 #endif
1120 }
1121
1122 /*
1123 * pj_mutex_is_locked()
1124 */
pj_mutex_is_locked(pj_mutex_t * mutex)1125 PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
1126 {
1127 #if PJ_DEBUG
1128 return mutex->owner == pj_thread_this();
1129 #else
1130 PJ_UNUSED_ARG(mutex);
1131 pj_assert(!"PJ_DEBUG is not set!");
1132 return 1;
1133 #endif
1134 }
1135
1136 ///////////////////////////////////////////////////////////////////////////////
1137 /*
1138 * Win32 lacks Read/Write mutex, so include the emulation.
1139 */
1140 #include "os_rwmutex.c"
1141
1142 ///////////////////////////////////////////////////////////////////////////////
1143 /*
1144 * pj_enter_critical_section()
1145 */
pj_enter_critical_section(void)1146 PJ_DEF(void) pj_enter_critical_section(void)
1147 {
1148 pj_mutex_lock(&critical_section_mutex);
1149 }
1150
1151
1152 /*
1153 * pj_leave_critical_section()
1154 */
pj_leave_critical_section(void)1155 PJ_DEF(void) pj_leave_critical_section(void)
1156 {
1157 pj_mutex_unlock(&critical_section_mutex);
1158 }
1159
1160 ///////////////////////////////////////////////////////////////////////////////
1161 #if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
1162
1163 /*
1164 * pj_sem_create()
1165 */
pj_sem_create(pj_pool_t * pool,const char * name,unsigned initial,unsigned max,pj_sem_t ** sem_ptr)1166 PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
1167 const char *name,
1168 unsigned initial,
1169 unsigned max,
1170 pj_sem_t **sem_ptr)
1171 {
1172 pj_sem_t *sem;
1173
1174 PJ_CHECK_STACK();
1175 PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
1176
1177 sem = pj_pool_alloc(pool, sizeof(*sem));
1178
1179 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
1180 /** SEMAPHORE_ALL_ACCESS **/
1181 sem->hSemaphore = CreateSemaphoreEx(NULL, initial, max, NULL, 0,
1182 SEMAPHORE_ALL_ACCESS);
1183 #else
1184 sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
1185 #endif
1186
1187 if (!sem->hSemaphore)
1188 return PJ_RETURN_OS_ERROR(GetLastError());
1189
1190 /* Set name. */
1191 if (!name) {
1192 name = "sem%p";
1193 }
1194 if (strchr(name, '%')) {
1195 pj_ansi_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
1196 } else {
1197 pj_ansi_strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
1198 sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1199 }
1200
1201 LOG_MUTEX((sem->obj_name, "Semaphore created"));
1202
1203 *sem_ptr = sem;
1204 return PJ_SUCCESS;
1205 }
1206
pj_sem_wait_for(pj_sem_t * sem,unsigned timeout)1207 static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
1208 {
1209 DWORD result;
1210
1211 PJ_CHECK_STACK();
1212 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1213
1214 LOG_MUTEX((sem->obj_name, "Semaphore: thread %s is waiting",
1215 pj_thread_this()->obj_name));
1216
1217 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
1218 result = WaitForSingleObjectEx(sem->hSemaphore, timeout, FALSE);
1219 #else
1220 result = WaitForSingleObject(sem->hSemaphore, timeout);
1221 #endif
1222
1223 if (result == WAIT_OBJECT_0) {
1224 LOG_MUTEX((sem->obj_name, "Semaphore acquired by thread %s",
1225 pj_thread_this()->obj_name));
1226 } else {
1227 LOG_MUTEX((sem->obj_name, "Semaphore: thread %s FAILED to acquire",
1228 pj_thread_this()->obj_name));
1229 }
1230
1231 if (result==WAIT_OBJECT_0)
1232 return PJ_SUCCESS;
1233 else if (result==WAIT_TIMEOUT)
1234 return PJ_ETIMEDOUT;
1235 else
1236 return PJ_RETURN_OS_ERROR(GetLastError());
1237 }
1238
1239 /*
1240 * pj_sem_wait()
1241 */
pj_sem_wait(pj_sem_t * sem)1242 PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
1243 {
1244 PJ_CHECK_STACK();
1245 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1246
1247 return pj_sem_wait_for(sem, INFINITE);
1248 }
1249
1250 /*
1251 * pj_sem_trywait()
1252 */
pj_sem_trywait(pj_sem_t * sem)1253 PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
1254 {
1255 PJ_CHECK_STACK();
1256 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1257
1258 return pj_sem_wait_for(sem, 0);
1259 }
1260
1261 /*
1262 * pj_sem_post()
1263 */
pj_sem_post(pj_sem_t * sem)1264 PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
1265 {
1266 PJ_CHECK_STACK();
1267 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1268
1269 LOG_MUTEX((sem->obj_name, "Semaphore released by thread %s",
1270 pj_thread_this()->obj_name));
1271
1272 if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
1273 return PJ_SUCCESS;
1274 else
1275 return PJ_RETURN_OS_ERROR(GetLastError());
1276 }
1277
1278 /*
1279 * pj_sem_destroy()
1280 */
pj_sem_destroy(pj_sem_t * sem)1281 PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
1282 {
1283 PJ_CHECK_STACK();
1284 PJ_ASSERT_RETURN(sem, PJ_EINVAL);
1285
1286 LOG_MUTEX((sem->obj_name, "Semaphore destroyed by thread %s",
1287 pj_thread_this()->obj_name));
1288
1289 if (CloseHandle(sem->hSemaphore))
1290 return PJ_SUCCESS;
1291 else
1292 return PJ_RETURN_OS_ERROR(GetLastError());
1293 }
1294
1295 #endif /* PJ_HAS_SEMAPHORE */
1296 ///////////////////////////////////////////////////////////////////////////////
1297
1298
1299 #if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
1300
1301 /*
1302 * pj_event_create()
1303 */
pj_event_create(pj_pool_t * pool,const char * name,pj_bool_t manual_reset,pj_bool_t initial,pj_event_t ** event_ptr)1304 PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool,
1305 const char *name,
1306 pj_bool_t manual_reset,
1307 pj_bool_t initial,
1308 pj_event_t **event_ptr)
1309 {
1310 pj_event_t *event;
1311
1312 PJ_CHECK_STACK();
1313 PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
1314
1315 event = pj_pool_alloc(pool, sizeof(*event));
1316 if (!event)
1317 return PJ_ENOMEM;
1318
1319 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
1320 event->hEvent = CreateEventEx(NULL, NULL,
1321 (manual_reset? 0x1:0x0) | (initial? 0x2:0x0),
1322 EVENT_ALL_ACCESS);
1323 #else
1324 event->hEvent = CreateEvent(NULL, manual_reset ? TRUE : FALSE,
1325 initial ? TRUE : FALSE, NULL);
1326 #endif
1327
1328 if (!event->hEvent)
1329 return PJ_RETURN_OS_ERROR(GetLastError());
1330
1331 /* Set name. */
1332 if (!name) {
1333 name = "evt%p";
1334 }
1335 if (strchr(name, '%')) {
1336 pj_ansi_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
1337 } else {
1338 pj_ansi_strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
1339 event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
1340 }
1341
1342 PJ_LOG(6, (event->obj_name, "Event created"));
1343
1344 *event_ptr = event;
1345 return PJ_SUCCESS;
1346 }
1347
pj_event_wait_for(pj_event_t * event,unsigned timeout)1348 static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
1349 {
1350 DWORD result;
1351
1352 PJ_CHECK_STACK();
1353 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1354
1355 PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting",
1356 pj_thread_this()->obj_name));
1357
1358 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
1359 result = WaitForSingleObjectEx(event->hEvent, timeout, FALSE);
1360 #else
1361 result = WaitForSingleObject(event->hEvent, timeout);
1362 #endif
1363
1364 if (result == WAIT_OBJECT_0) {
1365 PJ_LOG(6, (event->obj_name, "Event: thread %s is released",
1366 pj_thread_this()->obj_name));
1367 } else {
1368 PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire",
1369 pj_thread_this()->obj_name));
1370 }
1371
1372 if (result==WAIT_OBJECT_0)
1373 return PJ_SUCCESS;
1374 else if (result==WAIT_TIMEOUT)
1375 return PJ_ETIMEDOUT;
1376 else
1377 return PJ_RETURN_OS_ERROR(GetLastError());
1378 }
1379
1380 /*
1381 * pj_event_wait()
1382 */
pj_event_wait(pj_event_t * event)1383 PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
1384 {
1385 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1386
1387 return pj_event_wait_for(event, INFINITE);
1388 }
1389
1390 /*
1391 * pj_event_trywait()
1392 */
pj_event_trywait(pj_event_t * event)1393 PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
1394 {
1395 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1396
1397 return pj_event_wait_for(event, 0);
1398 }
1399
1400 /*
1401 * pj_event_set()
1402 */
pj_event_set(pj_event_t * event)1403 PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
1404 {
1405 PJ_CHECK_STACK();
1406 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1407
1408 PJ_LOG(6, (event->obj_name, "Setting event"));
1409
1410 if (SetEvent(event->hEvent))
1411 return PJ_SUCCESS;
1412 else
1413 return PJ_RETURN_OS_ERROR(GetLastError());
1414 }
1415
1416 /*
1417 * pj_event_pulse()
1418 */
pj_event_pulse(pj_event_t * event)1419 PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
1420 {
1421 #if defined(PJ_WIN32_WINPHONE8) && PJ_WIN32_WINPHONE8
1422 PJ_UNUSED_ARG(event);
1423 pj_assert(!"pj_event_pulse() not supported!");
1424 return PJ_ENOTSUP;
1425 #else
1426 PJ_CHECK_STACK();
1427 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1428
1429 PJ_LOG(6, (event->obj_name, "Pulsing event"));
1430
1431 if (PulseEvent(event->hEvent))
1432 return PJ_SUCCESS;
1433 else
1434 return PJ_RETURN_OS_ERROR(GetLastError());
1435 #endif
1436 }
1437
1438 /*
1439 * pj_event_reset()
1440 */
pj_event_reset(pj_event_t * event)1441 PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
1442 {
1443 PJ_CHECK_STACK();
1444 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1445
1446 PJ_LOG(6, (event->obj_name, "Event is reset"));
1447
1448 if (ResetEvent(event->hEvent))
1449 return PJ_SUCCESS;
1450 else
1451 return PJ_RETURN_OS_ERROR(GetLastError());
1452 }
1453
1454 /*
1455 * pj_event_destroy()
1456 */
pj_event_destroy(pj_event_t * event)1457 PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
1458 {
1459 PJ_CHECK_STACK();
1460 PJ_ASSERT_RETURN(event, PJ_EINVAL);
1461
1462 PJ_LOG(6, (event->obj_name, "Event is destroying"));
1463
1464 if (CloseHandle(event->hEvent))
1465 return PJ_SUCCESS;
1466 else
1467 return PJ_RETURN_OS_ERROR(GetLastError());
1468 }
1469
1470 #endif /* PJ_HAS_EVENT_OBJ */
1471
1472 ///////////////////////////////////////////////////////////////////////////////
1473 #if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
1474 /*
1475 * Terminal color
1476 */
1477
pj_color_to_os_attr(pj_color_t color)1478 static WORD pj_color_to_os_attr(pj_color_t color)
1479 {
1480 WORD attr = 0;
1481
1482 if (color & PJ_TERM_COLOR_R)
1483 attr |= FOREGROUND_RED;
1484 if (color & PJ_TERM_COLOR_G)
1485 attr |= FOREGROUND_GREEN;
1486 if (color & PJ_TERM_COLOR_B)
1487 attr |= FOREGROUND_BLUE;
1488 if (color & PJ_TERM_COLOR_BRIGHT)
1489 attr |= FOREGROUND_INTENSITY;
1490
1491 return attr;
1492 }
1493
os_attr_to_pj_color(WORD attr)1494 static pj_color_t os_attr_to_pj_color(WORD attr)
1495 {
1496 int color = 0;
1497
1498 if (attr & FOREGROUND_RED)
1499 color |= PJ_TERM_COLOR_R;
1500 if (attr & FOREGROUND_GREEN)
1501 color |= PJ_TERM_COLOR_G;
1502 if (attr & FOREGROUND_BLUE)
1503 color |= PJ_TERM_COLOR_B;
1504 if (attr & FOREGROUND_INTENSITY)
1505 color |= PJ_TERM_COLOR_BRIGHT;
1506
1507 return color;
1508 }
1509
1510
1511 /*
1512 * pj_term_set_color()
1513 */
pj_term_set_color(pj_color_t color)1514 PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
1515 {
1516 BOOL rc;
1517 WORD attr = 0;
1518
1519 PJ_CHECK_STACK();
1520
1521 attr = pj_color_to_os_attr(color);
1522 rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
1523 return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
1524 }
1525
1526 /*
1527 * pj_term_get_color()
1528 * Get current terminal foreground color.
1529 */
pj_term_get_color(void)1530 PJ_DEF(pj_color_t) pj_term_get_color(void)
1531 {
1532 CONSOLE_SCREEN_BUFFER_INFO info;
1533
1534 PJ_CHECK_STACK();
1535
1536 GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
1537 return os_attr_to_pj_color(info.wAttributes);
1538 }
1539
1540 #endif /* PJ_TERM_HAS_COLOR */
1541
1542 /*
1543 * pj_run_app()
1544 */
pj_run_app(pj_main_func_ptr main_func,int argc,char * argv[],unsigned flags)1545 PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1546 unsigned flags)
1547 {
1548 PJ_UNUSED_ARG(flags);
1549 return (*main_func)(argc, argv);
1550 }
1551