1
/* $Id: os_core_symbian.cpp 3999 2012-03-30 07:10:13Z bennylp $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include <pj/assert.h>
26
#include <pj/string.h>
28
#include <pj/except.h>
31
#include "os_symbian.h"
35
#define DUMMY_MUTEX ((pj_mutex_t*)101)
36
#define DUMMY_SEMAPHORE ((pj_sem_t*)102)
37
#define THIS_FILE "os_core_symbian.c"
39
/* Default message slot number for RSocketServ::Connect().
40
* Increase it to 32 from the default 8 (KESockDefaultMessageSlots)
42
#ifndef PJ_SYMBIAN_SOCK_MSG_SLOTS
43
# define PJ_SYMBIAN_SOCK_MSG_SLOTS 32
49
* The Symbian implementation does not support threading!
54
char obj_name[PJ_MAX_OBJ_NAME];
55
void *tls_values[PJ_MAX_TLS];
57
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
59
pj_uint32_t stk_max_usage;
61
const char *caller_file;
69
pj_atomic_value_t value;
78
/* Flag and reference counter for PJLIB instance */
79
static int initialized;
81
/* Flags to indicate which TLS variables have been used */
82
static int tls_vars[PJ_MAX_TLS];
85
static unsigned atexit_count;
86
static void (*atexit_func[32])(void);
89
/////////////////////////////////////////////////////////////////////////////
91
// CPjTimeoutTimer implementation
94
CPjTimeoutTimer::CPjTimeoutTimer()
95
: CActive(PJ_SYMBIAN_TIMER_PRIORITY), hasTimedOut_(PJ_FALSE)
99
CPjTimeoutTimer::~CPjTimeoutTimer()
105
void CPjTimeoutTimer::ConstructL()
107
hasTimedOut_ = PJ_FALSE;
108
timer_.CreateLocal();
109
CActiveScheduler::Add(this);
112
CPjTimeoutTimer *CPjTimeoutTimer::NewL()
114
CPjTimeoutTimer *self = new CPjTimeoutTimer;
115
CleanupStack::PushL(self);
119
CleanupStack::Pop(self);
124
void CPjTimeoutTimer::StartTimer(TUint miliSeconds)
128
hasTimedOut_ = PJ_FALSE;
129
timer_.After(iStatus, miliSeconds * 1000);
133
bool CPjTimeoutTimer::HasTimedOut() const
135
return hasTimedOut_ != 0;
138
void CPjTimeoutTimer::RunL()
140
hasTimedOut_ = PJ_TRUE;
143
void CPjTimeoutTimer::DoCancel()
148
TInt CPjTimeoutTimer::RunError(TInt aError)
150
PJ_UNUSED_ARG(aError);
156
/////////////////////////////////////////////////////////////////////////////
158
// PjSymbianOS implementation
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)
171
void PjSymbianOS::SetParameters(pj_symbianos_params *params)
173
appSocketServ_ = (RSocketServ*) params->rsocketserv;
174
appConnection_ = (RConnection*) params->rconnection;
175
appHostResolver_ = (RHostResolver*) params->rhostresolver;
176
appHostResolver6_ = (RHostResolver*) params->rhostresolver6;
179
// Get PjSymbianOS instance
180
PjSymbianOS *PjSymbianOS::Instance()
182
static PjSymbianOS instance_;
188
TInt PjSymbianOS::Initialize()
192
selectTimeoutTimer_ = CPjTimeoutTimer::NewL();
195
pj_assert(console_ == NULL);
196
TRAPD(err, console_ = Console::NewL(_L("PJLIB"),
197
TSize(KConsFullScreen,KConsFullScreen)));
201
/* Only create RSocketServ if application doesn't specify it
204
if (!isSocketServInitialized_ && appSocketServ_ == NULL) {
205
err = socketServ_.Connect(PJ_SYMBIAN_SOCK_MSG_SLOTS);
209
isSocketServInitialized_ = true;
212
if (!isResolverInitialized_) {
213
if (appHostResolver_ == NULL) {
215
err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream,
218
err = hostResolver_.Open(SocketServ(), KAfInet, KSockStream);
224
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
225
if (appHostResolver6_ == NULL) {
227
err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream,
230
err = hostResolver6_.Open(SocketServ(), KAfInet6, KSockStream);
238
isResolverInitialized_ = true;
241
isConnectionUp_ = true;
251
void PjSymbianOS::Shutdown()
253
isConnectionUp_ = false;
255
if (isResolverInitialized_) {
256
hostResolver_.Close();
257
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6!=0
258
hostResolver6_.Close();
260
isResolverInitialized_ = false;
263
if (isSocketServInitialized_) {
265
isSocketServInitialized_ = false;
271
delete selectTimeoutTimer_;
272
selectTimeoutTimer_ = NULL;
274
appSocketServ_ = NULL;
275
appConnection_ = NULL;
276
appHostResolver_ = NULL;
277
appHostResolver6_ = NULL;
280
// Convert to Unicode
281
TInt PjSymbianOS::ConvertToUnicode(TDes16 &aUnicode, const TDesC8 &aForeign)
284
pj_assert(conv_ != NULL);
285
return conv_->ConvertToUnicode(aUnicode, aForeign, convToUnicodeState_);
287
return CnvUtfConverter::ConvertToUnicodeFromUtf8(aUnicode, aForeign);
291
// Convert from Unicode
292
TInt PjSymbianOS::ConvertFromUnicode(TDes8 &aForeign, const TDesC16 &aUnicode)
295
pj_assert(conv_ != NULL);
296
return conv_->ConvertFromUnicode(aForeign, aUnicode, convToAnsiState_);
298
return CnvUtfConverter::ConvertFromUnicodeToUtf8(aForeign, aUnicode);
303
/////////////////////////////////////////////////////////////////////////////
305
// PJLIB os.h implementation
308
PJ_DEF(pj_uint32_t) pj_getpid(void)
314
/* Set Symbian specific parameters */
315
PJ_DEF(pj_status_t) pj_symbianos_set_params(pj_symbianos_params *prm)
317
PJ_ASSERT_RETURN(prm != NULL, PJ_EINVAL);
318
PjSymbianOS::Instance()->SetParameters(prm);
323
/* Set connection status */
324
PJ_DEF(void) pj_symbianos_set_connection_status(pj_bool_t up)
326
PjSymbianOS::Instance()->SetConnectionStatus(up != 0);
334
PJ_DEF(pj_status_t) pj_init(void)
339
/* Check if PJLIB have been initialized */
345
pj_ansi_strcpy(main_thread.obj_name, "pjthread");
348
pj_memset(&main_thread, 0, sizeof(main_thread));
350
// Initialize PjSymbianOS instance
351
PjSymbianOS *os = PjSymbianOS::Instance();
353
PJ_LOG(4,(THIS_FILE, "Initializing PJLIB for Symbian OS.."));
356
err = os->Initialize();
358
return PJ_RETURN_OS_ERROR(err);
363
/* Initialize exception ID for the pool.
364
* Must do so after critical section is configured.
366
status = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
367
if (status != PJ_SUCCESS)
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;
378
/* Flag PJLIB as initialized */
380
pj_assert(initialized == 1);
382
PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
387
return PJ_RETURN_OS_ERROR(err);
391
PJ_DEF(pj_status_t) pj_atexit(pj_exit_callback func)
393
if (atexit_count >= PJ_ARRAY_SIZE(atexit_func))
396
atexit_func[atexit_count++] = func;
402
PJ_DEF(void) pj_shutdown(void)
404
/* Only perform shutdown operation when 'initialized' reaches zero */
405
pj_assert(initialized > 0);
406
if (--initialized != 0)
409
/* Call atexit() functions */
410
while (atexit_count > 0) {
411
(*atexit_func[atexit_count-1])();
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;
421
/* Clear static variables */
422
pj_errno_clear_handlers();
424
PjSymbianOS *os = PjSymbianOS::Instance();
428
/////////////////////////////////////////////////////////////////////////////
430
class CPollTimeoutTimer : public CActive
433
static CPollTimeoutTimer* NewL(int msec, TInt prio);
434
~CPollTimeoutTimer();
437
virtual void DoCancel();
442
explicit CPollTimeoutTimer(TInt prio);
443
void ConstructL(int msec);
446
CPollTimeoutTimer::CPollTimeoutTimer(TInt prio)
452
CPollTimeoutTimer::~CPollTimeoutTimer()
457
void CPollTimeoutTimer::ConstructL(int msec)
459
rtimer_.CreateLocal();
460
CActiveScheduler::Add(this);
461
rtimer_.After(iStatus, msec*1000);
465
CPollTimeoutTimer* CPollTimeoutTimer::NewL(int msec, TInt prio)
467
CPollTimeoutTimer *self = new CPollTimeoutTimer(prio);
468
CleanupStack::PushL(self);
469
self->ConstructL(msec);
470
CleanupStack::Pop(self);
475
void CPollTimeoutTimer::RunL()
479
void CPollTimeoutTimer::DoCancel()
486
* Wait the completion of any Symbian active objects.
488
PJ_DEF(pj_bool_t) pj_symbianos_poll(int priority, int ms_timeout)
490
CPollTimeoutTimer *timer = NULL;
493
priority = EPriorityNull;
495
if (ms_timeout >= 0) {
496
timer = CPollTimeoutTimer::NewL(ms_timeout, priority);
499
PjSymbianOS::Instance()->WaitForActiveObjects(priority);
502
bool timer_is_active = timer->IsActive();
508
return timer_is_active ? PJ_TRUE : PJ_FALSE;
517
* pj_thread_is_registered()
519
PJ_DEF(pj_bool_t) pj_thread_is_registered(void)
526
* Get thread priority value for the thread.
528
PJ_DEF(int) pj_thread_get_prio(pj_thread_t *thread)
530
PJ_UNUSED_ARG(thread);
536
* Set the thread priority.
538
PJ_DEF(pj_status_t) pj_thread_set_prio(pj_thread_t *thread, int prio)
540
PJ_UNUSED_ARG(thread);
547
* Get the lowest priority value available on this system.
549
PJ_DEF(int) pj_thread_get_prio_min(pj_thread_t *thread)
551
PJ_UNUSED_ARG(thread);
557
* Get the highest priority value available on this system.
559
PJ_DEF(int) pj_thread_get_prio_max(pj_thread_t *thread)
561
PJ_UNUSED_ARG(thread);
567
* pj_thread_get_os_handle()
569
PJ_DEF(void*) pj_thread_get_os_handle(pj_thread_t *thread)
571
PJ_UNUSED_ARG(thread);
576
* pj_thread_register(..)
578
PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
580
pj_thread_t **thread_ptr)
582
PJ_UNUSED_ARG(cstr_thread_name);
584
PJ_UNUSED_ARG(thread_ptr);
585
return PJ_EINVALIDOP;
590
* pj_thread_create(...)
592
PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool,
593
const char *thread_name,
594
pj_thread_proc *proc,
596
pj_size_t stack_size,
598
pj_thread_t **ptr_thread)
601
PJ_UNUSED_ARG(thread_name);
604
PJ_UNUSED_ARG(stack_size);
605
PJ_UNUSED_ARG(flags);
606
PJ_UNUSED_ARG(ptr_thread);
608
/* Sorry mate, we don't support threading */
613
* pj_thread-get_name()
615
PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
617
pj_assert(p == &main_thread);
624
PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
627
return PJ_EINVALIDOP;
633
PJ_DEF(pj_thread_t*) pj_thread_this(void)
641
PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *rec)
644
return PJ_EINVALIDOP;
648
* pj_thread_destroy()
650
PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *rec)
653
return PJ_EINVALIDOP;
659
PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
661
User::After(msec*1000);
667
///////////////////////////////////////////////////////////////////////////////
669
* pj_thread_local_alloc()
672
PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
676
/* Find unused TLS variable */
677
for (i=0; i<PJ_ARRAY_SIZE(tls_vars); ++i) {
678
if (tls_vars[i] == 0)
682
if (i == PJ_ARRAY_SIZE(tls_vars))
692
* pj_thread_local_free()
694
PJ_DEF(void) pj_thread_local_free(long index)
696
PJ_ASSERT_ON_FAIL(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
697
tls_vars[index] != 0, return);
704
* pj_thread_local_set()
706
PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
708
pj_thread_t *rec = pj_thread_this();
710
PJ_ASSERT_RETURN(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
711
tls_vars[index] != 0, PJ_EINVAL);
713
rec->tls_values[index] = value;
718
* pj_thread_local_get()
720
PJ_DEF(void*) pj_thread_local_get(long index)
722
pj_thread_t *rec = pj_thread_this();
724
PJ_ASSERT_RETURN(index >= 0 && index < (int)PJ_ARRAY_SIZE(tls_vars) &&
725
tls_vars[index] != 0, NULL);
727
return rec->tls_values[index];
731
///////////////////////////////////////////////////////////////////////////////
733
* Create atomic variable.
735
PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool,
736
pj_atomic_value_t initial,
737
pj_atomic_t **atomic )
739
*atomic = (pj_atomic_t*)pj_pool_alloc(pool, sizeof(struct pj_atomic_t));
740
(*atomic)->value = initial;
746
* Destroy atomic variable.
748
PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
750
PJ_UNUSED_ARG(atomic_var);
756
* Set the value of an atomic type, and return the previous value.
758
PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var,
759
pj_atomic_value_t value)
761
atomic_var->value = value;
766
* Get the value of an atomic type.
768
PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
770
return atomic_var->value;
775
* Increment the value of an atomic type.
777
PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
784
* Increment the value of an atomic type and get the result.
786
PJ_DEF(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var)
788
return ++atomic_var->value;
793
* Decrement the value of an atomic type.
795
PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
802
* Decrement the value of an atomic type and get the result.
804
PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
806
return --atomic_var->value;
811
* Add a value to an atomic type.
813
PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
814
pj_atomic_value_t value)
816
atomic_var->value += value;
821
* Add a value to an atomic type and get the result.
823
PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,
824
pj_atomic_value_t value)
826
atomic_var->value += value;
827
return atomic_var->value;
832
/////////////////////////////////////////////////////////////////////////////
834
PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool,
843
*mutex = DUMMY_MUTEX;
848
* pj_mutex_create_simple()
850
PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool,
854
return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
858
PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
862
return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
869
PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
871
pj_assert(mutex == DUMMY_MUTEX);
878
PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
880
pj_assert(mutex == DUMMY_MUTEX);
887
PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
889
pj_assert(mutex == DUMMY_MUTEX);
896
PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
898
pj_assert(mutex == DUMMY_MUTEX);
903
/////////////////////////////////////////////////////////////////////////////
907
#include "os_rwmutex.c"
910
/////////////////////////////////////////////////////////////////////////////
913
* Enter critical section.
915
PJ_DEF(void) pj_enter_critical_section(void)
922
* Leave critical section.
924
PJ_DEF(void) pj_leave_critical_section(void)
930
/////////////////////////////////////////////////////////////////////////////
935
PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool,
945
sem = (pj_sem_t*) pj_pool_zalloc(pool, sizeof(pj_sem_t));
946
sem->value = initial;
956
* Wait for semaphore.
958
PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
960
if (sem->value > 0) {
964
pj_assert(!"Unexpected!");
965
return PJ_EINVALIDOP;
971
* Try wait for semaphore.
973
PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
975
if (sem->value > 0) {
979
pj_assert(!"Unexpected!");
980
return PJ_EINVALIDOP;
988
PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
998
PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
1005
#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
1007
* The implementation of stack checking.
1009
PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
1013
pj_thread_t *thread = pj_thread_this();
1017
/* Calculate current usage. */
1018
usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
1019
thread->stk_start - &stk_ptr;
1021
/* Assert if stack usage is dangerously high. */
1022
pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
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;
1033
* Get maximum stack usage statistic.
1035
PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
1037
return thread->stk_max_usage;
1041
* Dump thread stack status.
1043
PJ_DEF(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,
1049
*file = thread->caller_file;
1050
*line = thread->caller_line;
1054
#endif /* PJ_OS_HAS_CHECK_STACK */
1059
PJ_DEF(int) pj_run_app(pj_main_func_ptr main_func, int argc, char *argv[],
1062
return (*main_func)(argc, argv);