1
/* $Id: timer_symbian.cpp 3553 2011-05-05 06:14:19Z nanang $ */
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 "os_symbian.h"
29
#define DEFAULT_MAX_TIMED_OUT_PER_POLL (64)
31
// Maximum number of miliseconds that RTimer.At() supports
32
#define MAX_RTIMER_INTERVAL 2147
34
/* Absolute maximum number of timer entries */
35
#ifndef PJ_SYMBIAN_TIMER_MAX_COUNT
36
# define PJ_SYMBIAN_TIMER_MAX_COUNT 65535
39
/* Get the number of free slots in the timer heap */
40
#define FREECNT(th) (th->max_size - th->cur_size)
42
// Forward declaration
46
* The implementation of timer heap.
48
struct pj_timer_heap_t
50
/** Maximum size of the heap. */
53
/** Current size of the heap. */
56
/** Array of timer entries. A scheduled timer will occupy one slot, and
57
* the slot number will be saved in entry->_timer_id
59
CPjTimerEntry **entries;
61
/** Array of free slot indexes in the "entries" array */
66
* Active object for each timer entry.
68
class CPjTimerEntry : public CActive
71
pj_timer_entry *entry_;
73
static CPjTimerEntry* NewL( pj_timer_heap_t *timer_heap,
74
pj_timer_entry *entry,
75
const pj_time_val *delay);
80
virtual void DoCancel();
83
pj_timer_heap_t *timer_heap_;
85
pj_uint32_t interval_left_;
87
CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
88
void ConstructL(const pj_time_val *delay);
92
//////////////////////////////////////////////////////////////////////////////
97
/* Grow timer heap to the specified size */
98
static pj_status_t realloc_timer_heap(pj_timer_heap_t *th, pj_size_t new_size)
100
typedef CPjTimerEntry *entry_ptr;
101
CPjTimerEntry **entries = NULL;
102
int *free_slots = NULL;
105
if (new_size > PJ_SYMBIAN_TIMER_MAX_COUNT) {
106
/* Just some sanity limit */
107
new_size = PJ_SYMBIAN_TIMER_MAX_COUNT;
108
if (new_size <= th->max_size) {
109
/* We've grown large enough */
110
pj_assert(!"Too many timer heap entries");
115
/* Allocate entries, move entries from the old array if there is one */
116
entries = new entry_ptr[new_size];
118
pj_memcpy(entries, th->entries, th->max_size * sizeof(th->entries[0]));
120
/* Initialize the remaining new area */
121
pj_bzero(&entries[th->max_size],
122
(new_size - th->max_size) * sizeof(th->entries[0]));
124
/* Allocate free slots array */
125
free_slots = new int[new_size];
126
if (th->free_slots) {
127
pj_memcpy(free_slots, th->free_slots,
128
FREECNT(th) * sizeof(th->free_slots[0]));
130
/* Initialize the remaining new area */
131
for (i=FREECNT(th), j=th->max_size; j<new_size; ++i, ++j) {
134
for ( ; i<new_size; ++i) {
139
delete [] th->entries;
140
th->entries = entries;
141
th->max_size = new_size;
142
delete [] th->free_slots;
143
th->free_slots = free_slots;
148
/* Allocate and register an entry to timer heap for newly scheduled entry */
149
static pj_status_t add_entry(pj_timer_heap_t *th, CPjTimerEntry *entry)
154
/* Check that there's still capacity left in the timer heap */
155
if (FREECNT(th) < 1) {
156
// Grow the timer heap twice the capacity
157
status = realloc_timer_heap(th, th->max_size * 2);
158
if (status != PJ_SUCCESS)
162
/* Allocate one free slot. Use LIFO */
163
slot = th->free_slots[FREECNT(th)-1];
164
PJ_ASSERT_RETURN((slot >= 0) && (slot < (int)th->max_size) &&
165
(th->entries[slot]==NULL), PJ_EBUG);
167
th->free_slots[FREECNT(th)-1] = -1;
168
th->entries[slot] = entry;
169
entry->entry_->_timer_id = slot;
175
/* Free a slot when an entry's timer has elapsed or cancel */
176
static pj_status_t remove_entry(pj_timer_heap_t *th, CPjTimerEntry *entry)
178
int slot = entry->entry_->_timer_id;
180
PJ_ASSERT_RETURN(slot >= 0 && slot < (int)th->max_size, PJ_EBUG);
181
PJ_ASSERT_RETURN(FREECNT(th) < th->max_size, PJ_EBUG);
182
PJ_ASSERT_RETURN(th->entries[slot]==entry, PJ_EBUG);
183
PJ_ASSERT_RETURN(th->free_slots[FREECNT(th)]==-1, PJ_EBUG);
185
th->entries[slot] = NULL;
186
th->free_slots[FREECNT(th)] = slot;
187
entry->entry_->_timer_id = -1;
194
CPjTimerEntry::CPjTimerEntry(pj_timer_heap_t *timer_heap,
195
pj_timer_entry *entry)
196
: CActive(PJ_SYMBIAN_TIMER_PRIORITY), entry_(entry), timer_heap_(timer_heap),
201
CPjTimerEntry::~CPjTimerEntry()
207
void CPjTimerEntry::Schedule()
211
if (interval_left_ > MAX_RTIMER_INTERVAL) {
212
interval = MAX_RTIMER_INTERVAL;
214
interval = interval_left_;
217
interval_left_ -= interval;
218
rtimer_.After(iStatus, interval * 1000);
222
void CPjTimerEntry::ConstructL(const pj_time_val *delay)
224
rtimer_.CreateLocal();
225
CActiveScheduler::Add(this);
227
interval_left_ = PJ_TIME_VAL_MSEC(*delay);
231
CPjTimerEntry* CPjTimerEntry::NewL(pj_timer_heap_t *timer_heap,
232
pj_timer_entry *entry,
233
const pj_time_val *delay)
235
CPjTimerEntry *self = new CPjTimerEntry(timer_heap, entry);
236
CleanupStack::PushL(self);
237
self->ConstructL(delay);
238
CleanupStack::Pop(self);
243
void CPjTimerEntry::RunL()
245
if (interval_left_ > 0) {
250
remove_entry(timer_heap_, this);
251
entry_->cb(timer_heap_, entry_);
257
void CPjTimerEntry::DoCancel()
259
/* It's possible that _timer_id is -1, see schedule(). In this case,
260
* the entry has not been added to the timer heap, so don't remove
263
if (entry_ && entry_->_timer_id != -1)
264
remove_entry(timer_heap_, this);
270
//////////////////////////////////////////////////////////////////////////////
274
* Calculate memory size required to create a timer heap.
276
PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
278
return /* size of the timer heap itself: */
279
sizeof(pj_timer_heap_t) +
280
/* size of each entry: */
281
(count+2) * (sizeof(void*)+sizeof(int)) +
282
/* lock, pool etc: */
287
* Create a new timer heap.
289
PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
291
pj_timer_heap_t **p_heap)
296
PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
300
/* Allocate timer heap data structure from the pool */
301
ht = PJ_POOL_ZALLOC_T(pool, pj_timer_heap_t);
306
status = realloc_timer_heap(ht, size);
307
if (status != PJ_SUCCESS)
314
PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
316
/* Cancel and delete pending active objects */
319
for (i=0; i<ht->max_size; ++i) {
320
if (ht->entries[i]) {
321
ht->entries[i]->entry_ = NULL;
322
ht->entries[i]->Cancel();
323
delete ht->entries[i];
324
ht->entries[i] = NULL;
329
delete [] ht->entries;
330
delete [] ht->free_slots;
333
ht->free_slots = NULL;
336
PJ_DEF(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,
342
pj_lock_destroy(lock);
346
PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
350
PJ_UNUSED_ARG(count);
354
PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
357
pj_timer_heap_callback *cb )
359
pj_assert(entry && cb);
361
entry->_timer_id = -1;
363
entry->user_data = user_data;
369
PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
370
pj_timer_entry *entry,
371
const pj_time_val *delay)
373
CPjTimerEntry *timerObj;
376
PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
377
PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
379
/* Prevent same entry from being scheduled more than once */
380
PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
382
entry->_timer_id = -1;
384
timerObj = CPjTimerEntry::NewL(ht, entry, delay);
385
status = add_entry(ht, timerObj);
386
if (status != PJ_SUCCESS) {
395
PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
396
pj_timer_entry *entry)
398
PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
400
if (entry->_timer_id >= 0 && entry->_timer_id < (int)ht->max_size) {
401
CPjTimerEntry *timerObj = ht->entries[entry->_timer_id];
414
PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
415
pj_time_val *next_delay )
417
/* Polling is not necessary on Symbian, since all async activities
418
* are registered to active scheduler.
423
next_delay->msec = 0;
428
PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
430
PJ_ASSERT_RETURN(ht, 0);
435
PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
436
pj_time_val *timeval)
438
/* We don't support this! */