~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: timer_symbian.cpp 4374 2013-02-27 07:15:57Z riza $ */
 
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(pj_status_t) pj_timer_heap_schedule_w_grp_lock(pj_timer_heap_t *ht,
 
396
                                                      pj_timer_entry *entry,
 
397
                                                      const pj_time_val *delay,
 
398
                                                      int id_val,
 
399
                                                      pj_grp_lock_t *grp_lock)
 
400
{
 
401
    pj_status_t status;
 
402
            
 
403
    PJ_UNUSED_ARG(grp_lock);
 
404
 
 
405
    status = pj_timer_heap_schedule(ht, entry, delay);
 
406
    
 
407
    if (status == PJ_SUCCESS)
 
408
        entry->id = id_val;
 
409
    
 
410
    return status;
 
411
}
 
412
 
 
413
PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
 
414
                                  pj_timer_entry *entry)
 
415
{
 
416
    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
 
417
    
 
418
    if (entry->_timer_id >= 0 && entry->_timer_id < (int)ht->max_size) {
 
419
        CPjTimerEntry *timerObj = ht->entries[entry->_timer_id];
 
420
        if (timerObj) {
 
421
            timerObj->Cancel();
 
422
            delete timerObj;
 
423
            return 1;
 
424
        } else {
 
425
            return 0;
 
426
        }
 
427
    } else {
 
428
        return 0;
 
429
    }
 
430
}
 
431
 
 
432
PJ_DEF(int) pj_timer_heap_cancel_if_active(pj_timer_heap_t *ht,
 
433
                                           pj_timer_entry *entry,
 
434
                                           int id_val)
 
435
{
 
436
    int count = pj_timer_heap_cancel(ht, entry);
 
437
    if (count == 1)
 
438
        entry->id = id_val;
 
439
    
 
440
    return count;
 
441
}
 
442
 
 
443
PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 
 
444
                                     pj_time_val *next_delay )
 
445
{
 
446
    /* Polling is not necessary on Symbian, since all async activities
 
447
     * are registered to active scheduler.
 
448
     */
 
449
    PJ_UNUSED_ARG(ht);
 
450
    if (next_delay) {
 
451
        next_delay->sec = 1;
 
452
        next_delay->msec = 0;
 
453
    }
 
454
    return 0;
 
455
}
 
456
 
 
457
PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
 
458
{
 
459
    PJ_ASSERT_RETURN(ht, 0);
 
460
 
 
461
    return ht->cur_size;
 
462
}
 
463
 
 
464
PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
 
465
                                                 pj_time_val *timeval)
 
466
{
 
467
    /* We don't support this! */
 
468
    PJ_UNUSED_ARG(ht);
 
469
    
 
470
    timeval->sec = 1;
 
471
    timeval->msec = 0;
 
472
    
 
473
    return PJ_SUCCESS;
 
474
}
 
475