~ubuntu-branches/ubuntu/vivid/sflphone/vivid

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject/pjlib/src/pj/timer_symbian.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2013-06-30 11:40:56 UTC
  • mfrom: (4.1.18 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130630114056-0np50jkyqo6vnmii
Tags: 1.2.3-2
* changeset_r92d62cfc54732bbbcfff2b1d36c096b120b981a5.diff 
  - fixes automatic endian detection 
* Update Vcs: fixes vcs-field-not-canonical

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: timer_symbian.cpp 3553 2011-05-05 06:14:19Z nanang $ */
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
 
#include <pj/timer.h>
21
 
#include <pj/pool.h>
22
 
#include <pj/assert.h>
23
 
#include <pj/errno.h>
24
 
#include <pj/lock.h>
25
 
 
26
 
#include "os_symbian.h"
27
 
 
28
 
 
29
 
#define DEFAULT_MAX_TIMED_OUT_PER_POLL  (64)
30
 
 
31
 
// Maximum number of miliseconds that RTimer.At() supports
32
 
#define MAX_RTIMER_INTERVAL             2147
33
 
 
34
 
/* Absolute maximum number of timer entries */
35
 
#ifndef PJ_SYMBIAN_TIMER_MAX_COUNT
36
 
#  define PJ_SYMBIAN_TIMER_MAX_COUNT    65535
37
 
#endif
38
 
 
39
 
/* Get the number of free slots in the timer heap */
40
 
#define FREECNT(th)     (th->max_size - th->cur_size)
41
 
 
42
 
// Forward declaration
43
 
class CPjTimerEntry;
44
 
 
45
 
/**
46
 
 * The implementation of timer heap.
47
 
 */
48
 
struct pj_timer_heap_t
49
 
{
50
 
    /** Maximum size of the heap. */
51
 
    pj_size_t max_size;
52
 
 
53
 
    /** Current size of the heap. */
54
 
    pj_size_t cur_size;
55
 
 
56
 
    /** Array of timer entries. A scheduled timer will occupy one slot, and
57
 
     *  the slot number will be saved in entry->_timer_id
58
 
     */
59
 
    CPjTimerEntry **entries;
60
 
    
61
 
    /** Array of free slot indexes in the "entries" array */
62
 
    int *free_slots;
63
 
};
64
 
 
65
 
/**
66
 
 * Active object for each timer entry.
67
 
 */
68
 
class CPjTimerEntry : public CActive 
69
 
{
70
 
public:
71
 
    pj_timer_entry  *entry_;
72
 
    
73
 
    static CPjTimerEntry* NewL( pj_timer_heap_t *timer_heap,
74
 
                                pj_timer_entry *entry,
75
 
                                const pj_time_val *delay);
76
 
    
77
 
    ~CPjTimerEntry();
78
 
    
79
 
    virtual void RunL();
80
 
    virtual void DoCancel();
81
 
 
82
 
private:        
83
 
    pj_timer_heap_t *timer_heap_;
84
 
    RTimer           rtimer_;
85
 
    pj_uint32_t      interval_left_;
86
 
    
87
 
    CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
88
 
    void ConstructL(const pj_time_val *delay);
89
 
    void Schedule();
90
 
};
91
 
 
92
 
//////////////////////////////////////////////////////////////////////////////
93
 
/*
94
 
 * Implementation.
95
 
 */
96
 
 
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)
99
 
{
100
 
    typedef CPjTimerEntry *entry_ptr;
101
 
    CPjTimerEntry **entries = NULL;
102
 
    int *free_slots = NULL;
103
 
    unsigned i, j;
104
 
 
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");
111
 
            return PJ_ETOOMANY;
112
 
        }
113
 
    }
114
 
    
115
 
    /* Allocate entries, move entries from the old array if there is one */
116
 
    entries = new entry_ptr[new_size];
117
 
    if (th->entries) {
118
 
        pj_memcpy(entries, th->entries, th->max_size * sizeof(th->entries[0]));
119
 
    }
120
 
    /* Initialize the remaining new area */
121
 
    pj_bzero(&entries[th->max_size], 
122
 
            (new_size - th->max_size) * sizeof(th->entries[0]));
123
 
    
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]));
129
 
    }
130
 
    /* Initialize the remaining new area */
131
 
    for (i=FREECNT(th), j=th->max_size; j<new_size; ++i, ++j) {
132
 
        free_slots[i] = j;
133
 
    }
134
 
    for ( ; i<new_size; ++i) {
135
 
        free_slots[i] = -1;
136
 
    }
137
 
    
138
 
    /* Apply */
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;
144
 
 
145
 
    return PJ_SUCCESS;
146
 
}
147
 
 
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)
150
 
{
151
 
    pj_status_t status;
152
 
    int slot;
153
 
    
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)
159
 
            return status;
160
 
    }
161
 
    
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);
166
 
    
167
 
    th->free_slots[FREECNT(th)-1] = -1;
168
 
    th->entries[slot] = entry;
169
 
    entry->entry_->_timer_id = slot;
170
 
    ++th->cur_size;
171
 
    
172
 
    return PJ_SUCCESS;
173
 
}
174
 
 
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)
177
 
{
178
 
    int slot = entry->entry_->_timer_id;
179
 
    
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);
184
 
    
185
 
    th->entries[slot] = NULL;
186
 
    th->free_slots[FREECNT(th)] = slot;
187
 
    entry->entry_->_timer_id = -1;
188
 
    --th->cur_size;
189
 
    
190
 
    return PJ_SUCCESS;
191
 
}
192
 
 
193
 
 
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), 
197
 
  interval_left_(0)
198
 
{
199
 
}
200
 
 
201
 
CPjTimerEntry::~CPjTimerEntry() 
202
 
{
203
 
    Cancel();
204
 
    rtimer_.Close();
205
 
}
206
 
 
207
 
void CPjTimerEntry::Schedule()
208
 
{
209
 
    pj_int32_t interval;
210
 
    
211
 
    if (interval_left_ > MAX_RTIMER_INTERVAL) {
212
 
        interval = MAX_RTIMER_INTERVAL;
213
 
    } else {
214
 
        interval = interval_left_;
215
 
    }
216
 
    
217
 
    interval_left_ -= interval;
218
 
    rtimer_.After(iStatus, interval * 1000);
219
 
    SetActive();
220
 
}
221
 
 
222
 
void CPjTimerEntry::ConstructL(const pj_time_val *delay) 
223
 
{
224
 
    rtimer_.CreateLocal();
225
 
    CActiveScheduler::Add(this);
226
 
    
227
 
    interval_left_ = PJ_TIME_VAL_MSEC(*delay);
228
 
    Schedule();
229
 
}
230
 
 
231
 
CPjTimerEntry* CPjTimerEntry::NewL(pj_timer_heap_t *timer_heap,
232
 
                                   pj_timer_entry *entry,
233
 
                                   const pj_time_val *delay) 
234
 
{
235
 
    CPjTimerEntry *self = new CPjTimerEntry(timer_heap, entry);
236
 
    CleanupStack::PushL(self);
237
 
    self->ConstructL(delay);
238
 
    CleanupStack::Pop(self);
239
 
 
240
 
    return self;
241
 
}
242
 
 
243
 
void CPjTimerEntry::RunL() 
244
 
{
245
 
    if (interval_left_ > 0) {
246
 
        Schedule();
247
 
        return;
248
 
    }
249
 
    
250
 
    remove_entry(timer_heap_, this);
251
 
    entry_->cb(timer_heap_, entry_);
252
 
    
253
 
    // Finger's crossed!
254
 
    delete this;
255
 
}
256
 
 
257
 
void CPjTimerEntry::DoCancel() 
258
 
{
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
261
 
     * it.
262
 
     */
263
 
    if (entry_ && entry_->_timer_id != -1)
264
 
        remove_entry(timer_heap_, this);
265
 
    
266
 
    rtimer_.Cancel();
267
 
}
268
 
 
269
 
 
270
 
//////////////////////////////////////////////////////////////////////////////
271
 
 
272
 
 
273
 
/*
274
 
 * Calculate memory size required to create a timer heap.
275
 
 */
276
 
PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
277
 
{
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: */
283
 
           132;
284
 
}
285
 
 
286
 
/*
287
 
 * Create a new timer heap.
288
 
 */
289
 
PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
290
 
                                          pj_size_t size,
291
 
                                          pj_timer_heap_t **p_heap)
292
 
{
293
 
    pj_timer_heap_t *ht;
294
 
    pj_status_t status;
295
 
 
296
 
    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
297
 
 
298
 
    *p_heap = NULL;
299
 
 
300
 
    /* Allocate timer heap data structure from the pool */
301
 
    ht = PJ_POOL_ZALLOC_T(pool, pj_timer_heap_t);
302
 
    if (!ht)
303
 
        return PJ_ENOMEM;
304
 
 
305
 
    /* Allocate slots */
306
 
    status = realloc_timer_heap(ht, size);
307
 
    if (status != PJ_SUCCESS)
308
 
        return status;
309
 
 
310
 
    *p_heap = ht;
311
 
    return PJ_SUCCESS;
312
 
}
313
 
 
314
 
PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
315
 
{
316
 
    /* Cancel and delete pending active objects */
317
 
    if (ht->entries) {
318
 
        unsigned i;
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;
325
 
            }
326
 
        }
327
 
    }
328
 
    
329
 
    delete [] ht->entries;
330
 
    delete [] ht->free_slots;
331
 
    
332
 
    ht->entries = NULL;
333
 
    ht->free_slots = NULL;
334
 
}
335
 
 
336
 
PJ_DEF(void) pj_timer_heap_set_lock(  pj_timer_heap_t *ht,
337
 
                                      pj_lock_t *lock,
338
 
                                      pj_bool_t auto_del )
339
 
{
340
 
    PJ_UNUSED_ARG(ht);
341
 
    if (auto_del)
342
 
        pj_lock_destroy(lock);
343
 
}
344
 
 
345
 
 
346
 
PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
347
 
                                                          unsigned count )
348
 
{
349
 
    /* Not applicable */
350
 
    PJ_UNUSED_ARG(count);
351
 
    return ht->max_size;
352
 
}
353
 
 
354
 
PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
355
 
                                             int id,
356
 
                                             void *user_data,
357
 
                                             pj_timer_heap_callback *cb )
358
 
{
359
 
    pj_assert(entry && cb);
360
 
 
361
 
    entry->_timer_id = -1;
362
 
    entry->id = id;
363
 
    entry->user_data = user_data;
364
 
    entry->cb = cb;
365
 
 
366
 
    return entry;
367
 
}
368
 
 
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)
372
 
{
373
 
    CPjTimerEntry *timerObj;
374
 
    pj_status_t status;
375
 
    
376
 
    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
377
 
    PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
378
 
 
379
 
    /* Prevent same entry from being scheduled more than once */
380
 
    PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
381
 
 
382
 
    entry->_timer_id = -1;
383
 
    
384
 
    timerObj = CPjTimerEntry::NewL(ht, entry, delay);
385
 
    status = add_entry(ht, timerObj);
386
 
    if (status != PJ_SUCCESS) {
387
 
        timerObj->Cancel();
388
 
        delete timerObj;
389
 
        return status;
390
 
    }
391
 
    
392
 
    return PJ_SUCCESS;
393
 
}
394
 
 
395
 
PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
396
 
                                  pj_timer_entry *entry)
397
 
{
398
 
    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
399
 
    
400
 
    if (entry->_timer_id >= 0 && entry->_timer_id < (int)ht->max_size) {
401
 
        CPjTimerEntry *timerObj = ht->entries[entry->_timer_id];
402
 
        if (timerObj) {
403
 
            timerObj->Cancel();
404
 
            delete timerObj;
405
 
            return 1;
406
 
        } else {
407
 
            return 0;
408
 
        }
409
 
    } else {
410
 
        return 0;
411
 
    }
412
 
}
413
 
 
414
 
PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 
415
 
                                     pj_time_val *next_delay )
416
 
{
417
 
    /* Polling is not necessary on Symbian, since all async activities
418
 
     * are registered to active scheduler.
419
 
     */
420
 
    PJ_UNUSED_ARG(ht);
421
 
    if (next_delay) {
422
 
        next_delay->sec = 1;
423
 
        next_delay->msec = 0;
424
 
    }
425
 
    return 0;
426
 
}
427
 
 
428
 
PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
429
 
{
430
 
    PJ_ASSERT_RETURN(ht, 0);
431
 
 
432
 
    return ht->cur_size;
433
 
}
434
 
 
435
 
PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
436
 
                                                 pj_time_val *timeval)
437
 
{
438
 
    /* We don't support this! */
439
 
    PJ_UNUSED_ARG(ht);
440
 
    
441
 
    timeval->sec = 1;
442
 
    timeval->msec = 0;
443
 
    
444
 
    return PJ_SUCCESS;
445
 
}
446