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 
21 #include <pj/os.h>
22 #include <pj/assert.h>
23 #include <pj/pool.h>
24 #include <pj/log.h>
25 #include <pj/rand.h>
26 #include <pj/string.h>
27 #include <pj/guid.h>
28 #include <pj/except.h>
29 #include <pj/errno.h>
30 
31 #include "os_symbian.h"
32 
33 
34 #define PJ_MAX_TLS	    32
35 #define DUMMY_MUTEX	    ((pj_mutex_t*)101)
36 #define DUMMY_SEMAPHORE	    ((pj_sem_t*)102)
37 #define THIS_FILE	    "os_core_symbian.c"
38 
39 /* Default message slot number for RSocketServ::Connect().
40  * Increase it to 32 from the default 8 (KESockDefaultMessageSlots)
41  */
42 #ifndef PJ_SYMBIAN_SOCK_MSG_SLOTS
43 #  define PJ_SYMBIAN_SOCK_MSG_SLOTS  32
44 #endif
45 
46 /*
47  * Note:
48  *
49  * The Symbian implementation does not support threading!
50  */
51 
52 struct pj_thread_t
53 {
54     char	    obj_name[PJ_MAX_OBJ_NAME];
55     void	   *tls_values[PJ_MAX_TLS];
56 
57 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
58     pj_uint32_t	    stk_size;
59     pj_uint32_t	    stk_max_usage;
60     char	   *stk_start;
61     const char	   *caller_file;
62     int		    caller_line;
63 #endif
64 
65 } main_thread;
66 
67 struct pj_atomic_t
68 {
69     pj_atomic_value_t	value;
70 };
71 
72 struct pj_sem_t
73 {
74     int value;
75     int max;
76 };
77 
78 /* Flag and reference counter for PJLIB instance */
79 static int initialized;
80 
81 /* Flags to indicate which TLS variables have been used */
82 static int tls_vars[PJ_MAX_TLS];
83 
84 /* atexit handlers */
85 static unsigned atexit_count;
86 static void (*atexit_func[32])(void);
87 
88 
89 /////////////////////////////////////////////////////////////////////////////
90 //
91 // CPjTimeoutTimer implementation
92 //
93 
CPjTimeoutTimer()94 CPjTimeoutTimer::CPjTimeoutTimer()
95 : CActive(PJ_SYMBIAN_TIMER_PRIORITY), hasTimedOut_(PJ_FALSE)
96 {
97 }
98 
~CPjTimeoutTimer()99 CPjTimeoutTimer::~CPjTimeoutTimer()
100 {
101     Cancel();
102     timer_.Close();
103 }
104 
ConstructL()105 void CPjTimeoutTimer::ConstructL()
106 {
107     hasTimedOut_ = PJ_FALSE;
108     timer_.CreateLocal();
109     CActiveScheduler::Add(this);
110 }
111 
NewL()112 CPjTimeoutTimer *CPjTimeoutTimer::NewL()
113 {
114     CPjTimeoutTimer *self = new CPjTimeoutTimer;
115     CleanupStack::PushL(self);
116 
117     self->ConstructL();
118 
119     CleanupStack::Pop(self);
120     return self;
121 
122 }
123 
StartTimer(TUint miliSeconds)124 void CPjTimeoutTimer::StartTimer(TUint miliSeconds)
125 {
126     Cancel();
127 
128     hasTimedOut_ = PJ_FALSE;
129     timer_.After(iStatus, miliSeconds * 1000);
130     SetActive();
131 }
132 
HasTimedOut() const133 bool CPjTimeoutTimer::HasTimedOut() const
134 {
135     return hasTimedOut_ != 0;
136 }
137 
RunL()138 void CPjTimeoutTimer::RunL()
139 {
140     hasTimedOut_ = PJ_TRUE;
141 }
142 
DoCancel()143 void CPjTimeoutTimer::DoCancel()
144 {
145     timer_.Cancel();
146 }
147 
RunError(TInt aError)148 TInt CPjTimeoutTimer::RunError(TInt aError)
149 {
150     PJ_UNUSED_ARG(aError);
151     return KErrNone;
152 }
153 
154 
155 
156 /////////////////////////////////////////////////////////////////////////////
157 //
158 // PjSymbianOS implementation
159 //
160 
PjSymbianOS()161 PjSymbianOS::PjSymbianOS()
162 : isConnectionUp_(false),
163   isSocketServInitialized_(false), isResolverInitialized_(false),
164   console_(NULL), selectTimeoutTimer_(NULL),
165   appSocketServ_(NULL), appConnection_(NULL), appHostResolver_(NULL),
166   appHostResolver6_(NULL)
167 {
168 }
169 
170 // Set parameters
SetParameters(pj_symbianos_params * params)171 void PjSymbianOS::SetParameters(pj_symbianos_params *params)
172 {
173     appSocketServ_ = (RSocketServ*) params->rsocketserv;
174     appConnection_ = (RConnection*) params->rconnection;
175     appHostResolver_ = (RHostResolver*) params->rhostresolver;
176     appHostResolver6_ = (RHostResolver*) params->rhostresolver6;
177 }
178 
179 // Get PjSymbianOS instance
Instance()180 PjSymbianOS *PjSymbianOS::Instance()
181 {
182     static PjSymbianOS instance_;
183     return &instance_;
184 }
185 
186 
187 // Initialize
Initialize()188 TInt PjSymbianOS::Initialize()
189 {
190     TInt err;
191 
192     selectTimeoutTimer_ = CPjTimeoutTimer::NewL();
193 
194 #if 0
195     pj_assert(console_ == NULL);
196     TRAPD(err, console_ = Console::NewL(_L("PJLIB"),
197 				        TSize(KConsFullScreen,KConsFullScreen)));
198     return err;
199 #endif
200 
201     /* Only create RSocketServ if application doesn't specify it
202      * in the parameters
203      */
204     if (!isSocketServInitialized_ && appSocketServ_ == NULL) {
205 	err = socketServ_.Connect(PJ_SYMBIAN_SOCK_MSG_SLOTS);
206 	if (err != KErrNone)
207 	    goto on_error;
208 
209 	isSocketServInitialized_ = true;
210     }
211 
212     if (!isResolverInitialized_) {
213     	if (appHostResolver_ == NULL) {
214     	    if (Connection())
215     	    	err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream,
216     	    			     	 *Connection());
217     	    else
218 	    	err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream);
219 
220 	    if (err != KErrNone)
221 	    	goto on_error;
222     	}
223 
224 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
225     	if (appHostResolver6_ == NULL) {
226     	    if (Connection())
227     	    	err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream,
228     	    			     	  *Connection());
229     	    else
230 	    	err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream);
231 
232 	    if (err != KErrNone)
233 	    	goto on_error;
234     	}
235 #endif
236 
237 
238 	isResolverInitialized_ = true;
239     }
240 
241     isConnectionUp_ = true;
242 
243     return KErrNone;
244 
245 on_error:
246     Shutdown();
247     return err;
248 }
249 
250 // Shutdown
Shutdown()251 void PjSymbianOS::Shutdown()
252 {
253     isConnectionUp_ = false;
254 
255     if (isResolverInitialized_) {
256 		hostResolver_.Close();
257 #if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
258     	hostResolver6_.Close();
259 #endif
260     	isResolverInitialized_ = false;
261     }
262 
263     if (isSocketServInitialized_) {
264 	socketServ_.Close();
265 	isSocketServInitialized_ = false;
266     }
267 
268     delete console_;
269     console_ = NULL;
270 
271     delete selectTimeoutTimer_;
272     selectTimeoutTimer_ = NULL;
273 
274     appSocketServ_ = NULL;
275     appConnection_ = NULL;
276     appHostResolver_ = NULL;
277     appHostResolver6_ = NULL;
278 }
279 
280 // Convert to Unicode
ConvertToUnicode(TDes16 & aUnicode,const TDesC8 & aForeign)281 TInt PjSymbianOS::ConvertToUnicode(TDes16 &aUnicode, const TDesC8 &aForeign)
282 {
283 #if 0
284     pj_assert(conv_ != NULL);
285     return conv_->ConvertToUnicode(aUnicode, aForeign, convToUnicodeState_);
286 #else
287     return CnvUtfConverter::ConvertToUnicodeFromUtf8(aUnicode, aForeign);
288 #endif
289 }
290 
291 // Convert from Unicode
ConvertFromUnicode(TDes8 & aForeign,const TDesC16 & aUnicode)292 TInt PjSymbianOS::ConvertFromUnicode(TDes8 &aForeign, const TDesC16 &aUnicode)
293 {
294 #if 0
295     pj_assert(conv_ != NULL);
296     return conv_->ConvertFromUnicode(aForeign, aUnicode, convToAnsiState_);
297 #else
298     return CnvUtfConverter::ConvertFromUnicodeToUtf8(aForeign, aUnicode);
299 #endif
300 }
301 
302 
303 /////////////////////////////////////////////////////////////////////////////
304 //
305 // PJLIB os.h implementation
306 //
307 
pj_getpid(void)308 PJ_DEF(pj_uint32_t) pj_getpid(void)
309 {
310     return 0;
311 }
312 
313 
314 /* Set Symbian specific parameters */
pj_symbianos_set_params(pj_symbianos_params * prm)315 PJ_DEF(pj_status_t) pj_symbianos_set_params(pj_symbianos_params *prm)
316 {
317     PJ_ASSERT_RETURN(prm != NULL, PJ_EINVAL);
318     PjSymbianOS::Instance()->SetParameters(prm);
319     return PJ_SUCCESS;
320 }
321 
322 
323 /* Set connection status */
pj_symbianos_set_connection_status(pj_bool_t up)324 PJ_DEF(void) pj_symbianos_set_connection_status(pj_bool_t up)
325 {
326     PjSymbianOS::Instance()->SetConnectionStatus(up != 0);
327 }
328 
329 
330 /*
331  * pj_init(void).
332  * Init PJLIB!
333  */
pj_init(void)334 PJ_DEF(pj_status_t) pj_init(void)
335 {
336 	char stack_ptr;
337     pj_status_t status;
338 
339     /* Check if PJLIB have been initialized */
340     if (initialized) {
341 	++initialized;
342 	return PJ_SUCCESS;
343     }
344 
345     pj_ansi_strcpy(main_thread.obj_name, "pjthread");
346 
347     // Init main thread
348     pj_memset(&main_thread, 0, sizeof(main_thread));
349 
350     // Initialize PjSymbianOS instance
351     PjSymbianOS *os = PjSymbianOS::Instance();
352 
353     PJ_LOG(4,(THIS_FILE, "Initializing PJLIB for Symbian OS.."));
354 
355     TInt err;
356     err = os->Initialize();
357     if (err != KErrNone)
358     	return PJ_RETURN_OS_ERROR(err);
359 
360     /* Init logging */
361     pj_log_init();
362 
363     /* Initialize exception ID for the pool.
364      * Must do so after critical section is configured.
365      */
366     status = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
367     if (status != PJ_SUCCESS)
368         goto on_error;
369 
370 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
371     main_thread.stk_start = &stack_ptr;
372     main_thread.stk_size = 0xFFFFFFFFUL;
373     main_thread.stk_max_usage = 0;
374 #else
375     stack_ptr = '\0';
376 #endif
377 
378     /* Flag PJLIB as initialized */
379     ++initialized;
380     pj_assert(initialized == 1);
381 
382     PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
383     return PJ_SUCCESS;
384 
385 on_error:
386     pj_shutdown();
387     return PJ_RETURN_OS_ERROR(err);
388 }
389 
390 
pj_atexit(pj_exit_callback func)391 PJ_DEF(pj_status_t) pj_atexit(pj_exit_callback func)
392 {
393     if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
394 	return PJ_ETOOMANY;
395 
396     atexit_func[atexit_count++] = func;
397     return PJ_SUCCESS;
398 }
399 
400 
401 
pj_shutdown(void)402 PJ_DEF(void) pj_shutdown(void)
403 {
404     /* Only perform shutdown operation when 'initialized' reaches zero */
405     pj_assert(initialized > 0);
406     if (--initialized != 0)
407 	return;
408 
409     /* Call atexit() functions */
410     while (atexit_count > 0) {
411 	(*atexit_func[atexit_count-1])();
412 	--atexit_count;
413     }
414 
415     /* Free exception ID */
416     if (PJ_NO_MEMORY_EXCEPTION != -1) {
417 	pj_exception_id_free(PJ_NO_MEMORY_EXCEPTION);
418 	PJ_NO_MEMORY_EXCEPTION = -1;
419     }
420 
421     /* Clear static variables */
422     pj_errno_clear_handlers();
423 
424     PjSymbianOS *os = PjSymbianOS::Instance();
425     os->Shutdown();
426 }
427 
428 /////////////////////////////////////////////////////////////////////////////
429 
430 class CPollTimeoutTimer : public CActive
431 {
432 public:
433     static CPollTimeoutTimer* NewL(int msec, TInt prio);
434     ~CPollTimeoutTimer();
435 
436     virtual void RunL();
437     virtual void DoCancel();
438 
439 private:
440     RTimer	     rtimer_;
441 
442     explicit CPollTimeoutTimer(TInt prio);
443     void ConstructL(int msec);
444 };
445 
CPollTimeoutTimer(TInt prio)446 CPollTimeoutTimer::CPollTimeoutTimer(TInt prio)
447 : CActive(prio)
448 {
449 }
450 
451 
~CPollTimeoutTimer()452 CPollTimeoutTimer::~CPollTimeoutTimer()
453 {
454     rtimer_.Close();
455 }
456 
ConstructL(int msec)457 void CPollTimeoutTimer::ConstructL(int msec)
458 {
459     rtimer_.CreateLocal();
460     CActiveScheduler::Add(this);
461     rtimer_.After(iStatus, msec*1000);
462     SetActive();
463 }
464 
NewL(int msec,TInt prio)465 CPollTimeoutTimer* CPollTimeoutTimer::NewL(int msec, TInt prio)
466 {
467     CPollTimeoutTimer *self = new CPollTimeoutTimer(prio);
468     CleanupStack::PushL(self);
469     self->ConstructL(msec);
470     CleanupStack::Pop(self);
471 
472     return self;
473 }
474 
RunL()475 void CPollTimeoutTimer::RunL()
476 {
477 }
478 
DoCancel()479 void CPollTimeoutTimer::DoCancel()
480 {
481      rtimer_.Cancel();
482 }
483 
484 
485 /*
486  * Wait the completion of any Symbian active objects.
487  */
pj_symbianos_poll(int priority,int ms_timeout)488 PJ_DEF(pj_bool_t) pj_symbianos_poll(int priority, int ms_timeout)
489 {
490     CPollTimeoutTimer *timer = NULL;
491 
492     if (priority==-1)
493     	priority = EPriorityNull;
494 
495     if (ms_timeout >= 0) {
496     	timer = CPollTimeoutTimer::NewL(ms_timeout, priority);
497     }
498 
499     PjSymbianOS::Instance()->WaitForActiveObjects(priority);
500 
501     if (timer) {
502         bool timer_is_active = timer->IsActive();
503 
504 	timer->Cancel();
505 
506         delete timer;
507 
508     	return timer_is_active ? PJ_TRUE : PJ_FALSE;
509 
510     } else {
511     	return PJ_TRUE;
512     }
513 }
514 
515 
516 /*
517  * pj_thread_is_registered()
518  */
pj_thread_is_registered(void)519 PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
520 {
521     return PJ_FALSE;
522 }
523 
524 
525 /*
526  * Get thread priority value for the thread.
527  */
pj_thread_get_prio(pj_thread_t * thread)528 PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
529 {
530     PJ_UNUSED_ARG(thread);
531     return 1;
532 }
533 
534 
535 /*
536  * Set the thread priority.
537  */
pj_thread_set_prio(pj_thread_t * thread,int prio)538 PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread,  int prio)
539 {
540     PJ_UNUSED_ARG(thread);
541     PJ_UNUSED_ARG(prio);
542     return PJ_SUCCESS;
543 }
544 
545 
546 /*
547  * Get the lowest priority value available on this system.
548  */
pj_thread_get_prio_min(pj_thread_t * thread)549 PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
550 {
551     PJ_UNUSED_ARG(thread);
552     return 1;
553 }
554 
555 
556 /*
557  * Get the highest priority value available on this system.
558  */
pj_thread_get_prio_max(pj_thread_t * thread)559 PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
560 {
561     PJ_UNUSED_ARG(thread);
562     return 1;
563 }
564 
565 
566 /*
567  * pj_thread_get_os_handle()
568  */
pj_thread_get_os_handle(pj_thread_t * thread)569 PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
570 {
571     PJ_UNUSED_ARG(thread);
572     return NULL;
573 }
574 
575 /*
576  * pj_thread_register(..)
577  */
pj_thread_register(const char * cstr_thread_name,pj_thread_desc desc,pj_thread_t ** thread_ptr)578 PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
579 					 pj_thread_desc desc,
580                                          pj_thread_t **thread_ptr)
581 {
582     PJ_UNUSED_ARG(cstr_thread_name);
583     PJ_UNUSED_ARG(desc);
584     PJ_UNUSED_ARG(thread_ptr);
585     return PJ_EINVALIDOP;
586 }
587 
588 
589 /*
590  * pj_thread_create(...)
591  */
pj_thread_create(pj_pool_t * pool,const char * thread_name,pj_thread_proc * proc,void * arg,pj_size_t stack_size,unsigned flags,pj_thread_t ** ptr_thread)592 PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
593 				      const char *thread_name,
594 				      pj_thread_proc *proc,
595 				      void *arg,
596 				      pj_size_t stack_size,
597 				      unsigned flags,
598 				      pj_thread_t **ptr_thread)
599 {
600     PJ_UNUSED_ARG(pool);
601     PJ_UNUSED_ARG(thread_name);
602     PJ_UNUSED_ARG(proc);
603     PJ_UNUSED_ARG(arg);
604     PJ_UNUSED_ARG(stack_size);
605     PJ_UNUSED_ARG(flags);
606     PJ_UNUSED_ARG(ptr_thread);
607 
608     /* Sorry mate, we don't support threading */
609     return PJ_ENOTSUP;
610 }
611 
612 /*
613  * pj_thread-get_name()
614  */
pj_thread_get_name(pj_thread_t * p)615 PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
616 {
617     pj_assert(p == &main_thread);
618     return p->obj_name;
619 }
620 
621 /*
622  * pj_thread_resume()
623  */
pj_thread_resume(pj_thread_t * p)624 PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
625 {
626     PJ_UNUSED_ARG(p);
627     return PJ_EINVALIDOP;
628 }
629 
630 /*
631  * pj_thread_this()
632  */
pj_thread_this(void)633 PJ_DEF(pj_thread_t*) pj_thread_this(void)
634 {
635     return &main_thread;
636 }
637 
638 /*
639  * pj_thread_join()
640  */
pj_thread_join(pj_thread_t * rec)641 PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *rec)
642 {
643     PJ_UNUSED_ARG(rec);
644     return PJ_EINVALIDOP;
645 }
646 
647 /*
648  * pj_thread_destroy()
649  */
pj_thread_destroy(pj_thread_t * rec)650 PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *rec)
651 {
652     PJ_UNUSED_ARG(rec);
653     return PJ_EINVALIDOP;
654 }
655 
656 /*
657  * pj_thread_sleep()
658  */
pj_thread_sleep(unsigned msec)659 PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
660 {
661     User::After(msec*1000);
662 
663     return PJ_SUCCESS;
664 }
665 
666 
667 ///////////////////////////////////////////////////////////////////////////////
668 /*
669  * pj_thread_local_alloc()
670  */
671 
pj_thread_local_alloc(long * index)672 PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
673 {
674     unsigned i;
675 
676     /* Find unused TLS variable */
677     for (i=0; i<PJ_ARRAY_SIZE(tls_vars); ++i) {
678 	if (tls_vars[i] == 0)
679 	    break;
680     }
681 
682     if (i == PJ_ARRAY_SIZE(tls_vars))
683 	return PJ_ETOOMANY;
684 
685     tls_vars[i] = 1;
686     *index = i;
687 
688     return PJ_SUCCESS;
689 }
690 
691 /*
692  * pj_thread_local_free()
693  */
pj_thread_local_free(long index)694 PJ_DEF(void) pj_thread_local_free(long index)
695 {
696     PJ_ASSERT_ON_FAIL(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
697 		     tls_vars[index] != 0, return);
698 
699     tls_vars[index] = 0;
700 }
701 
702 
703 /*
704  * pj_thread_local_set()
705  */
pj_thread_local_set(long index,void * value)706 PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
707 {
708     pj_thread_t *rec = pj_thread_this();
709 
710     PJ_ASSERT_RETURN(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
711 		     tls_vars[index] != 0, PJ_EINVAL);
712 
713     rec->tls_values[index] = value;
714     return PJ_SUCCESS;
715 }
716 
717 /*
718  * pj_thread_local_get()
719  */
pj_thread_local_get(long index)720 PJ_DEF(void*) pj_thread_local_get(long index)
721 {
722     pj_thread_t *rec = pj_thread_this();
723 
724     PJ_ASSERT_RETURN(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
725 		     tls_vars[index] != 0, NULL);
726 
727     return rec->tls_values[index];
728 }
729 
730 
731 ///////////////////////////////////////////////////////////////////////////////
732 /*
733  * Create atomic variable.
734  */
pj_atomic_create(pj_pool_t * pool,pj_atomic_value_t initial,pj_atomic_t ** atomic)735 PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
736 				      pj_atomic_value_t initial,
737 				      pj_atomic_t **atomic )
738 {
739     *atomic = (pj_atomic_t*)pj_pool_alloc(pool, sizeof(struct pj_atomic_t));
740     (*atomic)->value = initial;
741     return PJ_SUCCESS;
742 }
743 
744 
745 /*
746  * Destroy atomic variable.
747  */
pj_atomic_destroy(pj_atomic_t * atomic_var)748 PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
749 {
750     PJ_UNUSED_ARG(atomic_var);
751     return PJ_SUCCESS;
752 }
753 
754 
755 /*
756  * Set the value of an atomic type, and return the previous value.
757  */
pj_atomic_set(pj_atomic_t * atomic_var,pj_atomic_value_t value)758 PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var,
759 			    pj_atomic_value_t value)
760 {
761     atomic_var->value = value;
762 }
763 
764 
765 /*
766  * Get the value of an atomic type.
767  */
pj_atomic_get(pj_atomic_t * atomic_var)768 PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
769 {
770     return atomic_var->value;
771 }
772 
773 
774 /*
775  * Increment the value of an atomic type.
776  */
pj_atomic_inc(pj_atomic_t * atomic_var)777 PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
778 {
779     ++atomic_var->value;
780 }
781 
782 
783 /*
784  * Increment the value of an atomic type and get the result.
785  */
pj_atomic_inc_and_get(pj_atomic_t * atomic_var)786 PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
787 {
788     return ++atomic_var->value;
789 }
790 
791 
792 /*
793  * Decrement the value of an atomic type.
794  */
pj_atomic_dec(pj_atomic_t * atomic_var)795 PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
796 {
797     --atomic_var->value;
798 }
799 
800 
801 /*
802  * Decrement the value of an atomic type and get the result.
803  */
pj_atomic_dec_and_get(pj_atomic_t * atomic_var)804 PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
805 {
806     return --atomic_var->value;
807 }
808 
809 
810 /*
811  * Add a value to an atomic type.
812  */
pj_atomic_add(pj_atomic_t * atomic_var,pj_atomic_value_t value)813 PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
814 			    pj_atomic_value_t value)
815 {
816     atomic_var->value += value;
817 }
818 
819 
820 /*
821  * Add a value to an atomic type and get the result.
822  */
pj_atomic_add_and_get(pj_atomic_t * atomic_var,pj_atomic_value_t value)823 PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
824 			                         pj_atomic_value_t value)
825 {
826     atomic_var->value += value;
827     return atomic_var->value;
828 }
829 
830 
831 
832 /////////////////////////////////////////////////////////////////////////////
833 
pj_mutex_create(pj_pool_t * pool,const char * name,int type,pj_mutex_t ** mutex)834 PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
835                                      const char *name,
836 				     int type,
837                                      pj_mutex_t **mutex)
838 {
839     PJ_UNUSED_ARG(pool);
840     PJ_UNUSED_ARG(name);
841     PJ_UNUSED_ARG(type);
842 
843     *mutex = DUMMY_MUTEX;
844     return PJ_SUCCESS;
845 }
846 
847 /*
848  * pj_mutex_create_simple()
849  */
pj_mutex_create_simple(pj_pool_t * pool,const char * name,pj_mutex_t ** mutex)850 PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
851                                             const char *name,
852 					    pj_mutex_t **mutex )
853 {
854     return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
855 }
856 
857 
pj_mutex_create_recursive(pj_pool_t * pool,const char * name,pj_mutex_t ** mutex)858 PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
859 					       const char *name,
860 					       pj_mutex_t **mutex )
861 {
862     return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
863 }
864 
865 
866 /*
867  * pj_mutex_lock()
868  */
pj_mutex_lock(pj_mutex_t * mutex)869 PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
870 {
871     pj_assert(mutex == DUMMY_MUTEX);
872     return PJ_SUCCESS;
873 }
874 
875 /*
876  * pj_mutex_trylock()
877  */
pj_mutex_trylock(pj_mutex_t * mutex)878 PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
879 {
880     pj_assert(mutex == DUMMY_MUTEX);
881     return PJ_SUCCESS;
882 }
883 
884 /*
885  * pj_mutex_unlock()
886  */
pj_mutex_unlock(pj_mutex_t * mutex)887 PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
888 {
889     pj_assert(mutex == DUMMY_MUTEX);
890     return PJ_SUCCESS;
891 }
892 
893 /*
894  * pj_mutex_destroy()
895  */
pj_mutex_destroy(pj_mutex_t * mutex)896 PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
897 {
898     pj_assert(mutex == DUMMY_MUTEX);
899     return PJ_SUCCESS;
900 }
901 
902 
903 /////////////////////////////////////////////////////////////////////////////
904 /*
905  * RW Mutex
906  */
907 #include "os_rwmutex.c"
908 
909 
910 /////////////////////////////////////////////////////////////////////////////
911 
912 /*
913  * Enter critical section.
914  */
pj_enter_critical_section(void)915 PJ_DEF(void) pj_enter_critical_section(void)
916 {
917     /* Nothing to do */
918 }
919 
920 
921 /*
922  * Leave critical section.
923  */
pj_leave_critical_section(void)924 PJ_DEF(void) pj_leave_critical_section(void)
925 {
926     /* Nothing to do */
927 }
928 
929 
930 /////////////////////////////////////////////////////////////////////////////
931 
932 /*
933  * Create semaphore.
934  */
pj_sem_create(pj_pool_t * pool,const char * name,unsigned initial,unsigned max,pj_sem_t ** p_sem)935 PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
936                                    const char *name,
937 				   unsigned initial,
938                                    unsigned max,
939 				   pj_sem_t **p_sem)
940 {
941     pj_sem_t *sem;
942 
943     PJ_UNUSED_ARG(name);
944 
945     sem = (pj_sem_t*) pj_pool_zalloc(pool, sizeof(pj_sem_t));
946     sem->value = initial;
947     sem->max = max;
948 
949     *p_sem = sem;
950 
951     return PJ_SUCCESS;
952 }
953 
954 
955 /*
956  * Wait for semaphore.
957  */
pj_sem_wait(pj_sem_t * sem)958 PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
959 {
960     if (sem->value > 0) {
961 	sem->value--;
962 	return PJ_SUCCESS;
963     } else {
964 	pj_assert(!"Unexpected!");
965 	return PJ_EINVALIDOP;
966     }
967 }
968 
969 
970 /*
971  * Try wait for semaphore.
972  */
pj_sem_trywait(pj_sem_t * sem)973 PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
974 {
975     if (sem->value > 0) {
976 	sem->value--;
977 	return PJ_SUCCESS;
978     } else {
979 	pj_assert(!"Unexpected!");
980 	return PJ_EINVALIDOP;
981     }
982 }
983 
984 
985 /*
986  * Release semaphore.
987  */
pj_sem_post(pj_sem_t * sem)988 PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
989 {
990     sem->value++;
991     return PJ_SUCCESS;
992 }
993 
994 
995 /*
996  * Destroy semaphore.
997  */
pj_sem_destroy(pj_sem_t * sem)998 PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
999 {
1000     PJ_UNUSED_ARG(sem);
1001     return PJ_SUCCESS;
1002 }
1003 
1004 
1005 #if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
1006 /*
1007  * The implementation of stack checking.
1008  */
pj_thread_check_stack(const char * file,int line)1009 PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
1010 {
1011     char stk_ptr;
1012     pj_uint32_t usage;
1013     pj_thread_t *thread = pj_thread_this();
1014 
1015     pj_assert(thread);
1016 
1017     /* Calculate current usage. */
1018     usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
1019 		thread->stk_start - &stk_ptr;
1020 
1021     /* Assert if stack usage is dangerously high. */
1022     pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
1023 
1024     /* Keep statistic. */
1025     if (usage > thread->stk_max_usage) {
1026 	thread->stk_max_usage = usage;
1027 	thread->caller_file = file;
1028 	thread->caller_line = line;
1029     }
1030 }
1031 
1032 /*
1033  * Get maximum stack usage statistic.
1034  */
pj_thread_get_stack_max_usage(pj_thread_t * thread)1035 PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
1036 {
1037     return thread->stk_max_usage;
1038 }
1039 
1040 /*
1041  * Dump thread stack status.
1042  */
pj_thread_get_stack_info(pj_thread_t * thread,const char ** file,int * line)1043 PJ_DEF(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,
1044 					     const char **file,
1045 					     int *line)
1046 {
1047     pj_assert(thread);
1048 
1049     *file = thread->caller_file;
1050     *line = thread->caller_line;
1051     return 0;
1052 }
1053 
1054 #endif	/* PJ_OS_HAS_CHECK_STACK */
1055 
1056 /*
1057  * pj_run_app()
1058  */
pj_run_app(pj_main_func_ptr main_func,int argc,char * argv[],unsigned flags)1059 PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1060                        unsigned flags)
1061 {
1062     return (*main_func)(argc, argv);
1063 }
1064