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