blob: 2daf8afaea5f9de127f664e899c362caa6c41be6 [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* 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 <pj/timer.h>
#include <pj/pool.h>
#include <pj/assert.h>
#include <pj/errno.h>
#include <pj/lock.h>
#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;
}