/* $Id$ */ /* * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) * Copyright (C) 2003-2008 Benny Prijono * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include "os_symbian.h" #define DEFAULT_MAX_TIMED_OUT_PER_POLL (64) /** * The implementation of timer heap. */ struct pj_timer_heap_t { /** Maximum size of the heap. */ pj_size_t max_size; /** Current size of the heap. */ pj_size_t cur_size; /** Max timed out entries to process per poll. */ unsigned max_entries_per_poll; }; ////////////////////////////////////////////////////////////////////////////// /** * Active object for each timer entry. */ class CPjTimerEntry : public CActive { public: static CPjTimerEntry* NewL( pj_timer_heap_t *timer_heap, pj_timer_entry *entry, const pj_time_val *delay); ~CPjTimerEntry(); virtual void RunL(); virtual void DoCancel(); private: pj_timer_heap_t *timer_heap_; pj_timer_entry *entry_; RTimer rtimer_; CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry); void ConstructL(const pj_time_val *delay); }; CPjTimerEntry::CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry) : CActive(PJ_SYMBIAN_TIMER_PRIORITY), timer_heap_(timer_heap), entry_(entry) { } CPjTimerEntry::~CPjTimerEntry() { Cancel(); rtimer_.Close(); } void CPjTimerEntry::ConstructL(const pj_time_val *delay) { rtimer_.CreateLocal(); CActiveScheduler::Add(this); pj_int32_t interval = PJ_TIME_VAL_MSEC(*delay) * 1000; if (interval < 0) { interval = 0; } rtimer_.After(iStatus, interval); SetActive(); } CPjTimerEntry* CPjTimerEntry::NewL(pj_timer_heap_t *timer_heap, pj_timer_entry *entry, const pj_time_val *delay) { CPjTimerEntry *self = new CPjTimerEntry(timer_heap, entry); CleanupStack::PushL(self); self->ConstructL(delay); CleanupStack::Pop(self); return self; } void CPjTimerEntry::RunL() { --timer_heap_->cur_size; entry_->_timer_id = NULL; entry_->cb(timer_heap_, entry_); // Finger's crossed! delete this; } void CPjTimerEntry::DoCancel() { rtimer_.Cancel(); } ////////////////////////////////////////////////////////////////////////////// /* * Calculate memory size required to create a timer heap. */ PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count) { return /* size of the timer heap itself: */ sizeof(pj_timer_heap_t) + /* size of each entry: */ (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) + /* lock, pool etc: */ 132; } /* * Create a new timer heap. */ PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool, pj_size_t size, pj_timer_heap_t **p_heap) { pj_timer_heap_t *ht; PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL); *p_heap = NULL; /* Allocate timer heap data structure from the pool */ ht = PJ_POOL_ALLOC_T(pool, pj_timer_heap_t); if (!ht) return PJ_ENOMEM; /* Initialize timer heap sizes */ ht->max_size = size; ht->cur_size = 0; ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL; *p_heap = ht; return PJ_SUCCESS; } PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht ) { PJ_UNUSED_ARG(ht); } PJ_DEF(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht, pj_lock_t *lock, pj_bool_t auto_del ) { PJ_UNUSED_ARG(ht); if (auto_del) pj_lock_destroy(lock); } PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht, unsigned count ) { unsigned old_count = ht->max_entries_per_poll; ht->max_entries_per_poll = count; return old_count; } PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry, int id, void *user_data, pj_timer_heap_callback *cb ) { pj_assert(entry && cb); entry->_timer_id = NULL; entry->id = id; entry->user_data = user_data; entry->cb = cb; return entry; } PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, pj_timer_entry *entry, const pj_time_val *delay) { CPjTimerEntry *timerObj; PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL); PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL); /* Prevent same entry from being scheduled more than once */ PJ_ASSERT_RETURN(entry->_timer_id == NULL, PJ_EINVALIDOP); timerObj = CPjTimerEntry::NewL(ht, entry, delay); entry->_timer_id = (void*) timerObj; ++ht->cur_size; return PJ_SUCCESS; } PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, pj_timer_entry *entry) { PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL); if (entry->_timer_id != NULL) { CPjTimerEntry *timerObj = (CPjTimerEntry*) entry->_timer_id; timerObj->Cancel(); delete timerObj; entry->_timer_id = NULL; --ht->cur_size; return 1; } else { return 0; } } PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay ) { /* Polling is not necessary on Symbian, since all async activities * are registered to active scheduler. */ PJ_UNUSED_ARG(ht); if (next_delay) { next_delay->sec = 1; next_delay->msec = 0; } return 0; } PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht ) { PJ_ASSERT_RETURN(ht, 0); return ht->cur_size; } PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht, pj_time_val *timeval) { /* We don't support this! */ PJ_UNUSED_ARG(ht); timeval->sec = 1; timeval->msec = 0; return PJ_SUCCESS; }