timer_symbian.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <pj/timer.h>
  20. #include <pj/pool.h>
  21. #include <pj/assert.h>
  22. #include <pj/errno.h>
  23. #include <pj/lock.h>
  24. #include "os_symbian.h"
  25. #define DEFAULT_MAX_TIMED_OUT_PER_POLL (64)
  26. // Maximum number of miliseconds that RTimer.At() supports
  27. #define MAX_RTIMER_INTERVAL 2147
  28. /* Absolute maximum number of timer entries */
  29. #ifndef PJ_SYMBIAN_TIMER_MAX_COUNT
  30. # define PJ_SYMBIAN_TIMER_MAX_COUNT 65535
  31. #endif
  32. /* Get the number of free slots in the timer heap */
  33. #define FREECNT(th) (th->max_size - th->cur_size)
  34. // Forward declaration
  35. class CPjTimerEntry;
  36. /**
  37. * The implementation of timer heap.
  38. */
  39. struct pj_timer_heap_t
  40. {
  41. /** Maximum size of the heap. */
  42. pj_size_t max_size;
  43. /** Current size of the heap. */
  44. pj_size_t cur_size;
  45. /** Array of timer entries. A scheduled timer will occupy one slot, and
  46. * the slot number will be saved in entry->_timer_id
  47. */
  48. CPjTimerEntry **entries;
  49. /** Array of free slot indexes in the "entries" array */
  50. int *free_slots;
  51. };
  52. /**
  53. * Active object for each timer entry.
  54. */
  55. class CPjTimerEntry : public CActive
  56. {
  57. public:
  58. pj_timer_entry *entry_;
  59. static CPjTimerEntry* NewL( pj_timer_heap_t *timer_heap,
  60. pj_timer_entry *entry,
  61. const pj_time_val *delay);
  62. ~CPjTimerEntry();
  63. virtual void RunL();
  64. virtual void DoCancel();
  65. private:
  66. pj_timer_heap_t *timer_heap_;
  67. RTimer rtimer_;
  68. pj_uint32_t interval_left_;
  69. CPjTimerEntry(pj_timer_heap_t *timer_heap, pj_timer_entry *entry);
  70. void ConstructL(const pj_time_val *delay);
  71. void Schedule();
  72. };
  73. //////////////////////////////////////////////////////////////////////////////
  74. /*
  75. * Implementation.
  76. */
  77. /* Grow timer heap to the specified size */
  78. static pj_status_t realloc_timer_heap(pj_timer_heap_t *th, pj_size_t new_size)
  79. {
  80. typedef CPjTimerEntry *entry_ptr;
  81. CPjTimerEntry **entries = NULL;
  82. int *free_slots = NULL;
  83. unsigned i, j;
  84. if (new_size > PJ_SYMBIAN_TIMER_MAX_COUNT) {
  85. /* Just some sanity limit */
  86. new_size = PJ_SYMBIAN_TIMER_MAX_COUNT;
  87. if (new_size <= th->max_size) {
  88. /* We've grown large enough */
  89. pj_assert(!"Too many timer heap entries");
  90. return PJ_ETOOMANY;
  91. }
  92. }
  93. /* Allocate entries, move entries from the old array if there is one */
  94. entries = new entry_ptr[new_size];
  95. if (th->entries) {
  96. pj_memcpy(entries, th->entries, th->max_size * sizeof(th->entries[0]));
  97. }
  98. /* Initialize the remaining new area */
  99. pj_bzero(&entries[th->max_size],
  100. (new_size - th->max_size) * sizeof(th->entries[0]));
  101. /* Allocate free slots array */
  102. free_slots = new int[new_size];
  103. if (th->free_slots) {
  104. pj_memcpy(free_slots, th->free_slots,
  105. FREECNT(th) * sizeof(th->free_slots[0]));
  106. }
  107. /* Initialize the remaining new area */
  108. for (i=FREECNT(th), j=th->max_size; j<new_size; ++i, ++j) {
  109. free_slots[i] = j;
  110. }
  111. for ( ; i<new_size; ++i) {
  112. free_slots[i] = -1;
  113. }
  114. /* Apply */
  115. delete [] th->entries;
  116. th->entries = entries;
  117. th->max_size = new_size;
  118. delete [] th->free_slots;
  119. th->free_slots = free_slots;
  120. return PJ_SUCCESS;
  121. }
  122. /* Allocate and register an entry to timer heap for newly scheduled entry */
  123. static pj_status_t add_entry(pj_timer_heap_t *th, CPjTimerEntry *entry)
  124. {
  125. pj_status_t status;
  126. int slot;
  127. /* Check that there's still capacity left in the timer heap */
  128. if (FREECNT(th) < 1) {
  129. // Grow the timer heap twice the capacity
  130. status = realloc_timer_heap(th, th->max_size * 2);
  131. if (status != PJ_SUCCESS)
  132. return status;
  133. }
  134. /* Allocate one free slot. Use LIFO */
  135. slot = th->free_slots[FREECNT(th)-1];
  136. PJ_ASSERT_RETURN((slot >= 0) && (slot < (int)th->max_size) &&
  137. (th->entries[slot]==NULL), PJ_EBUG);
  138. th->free_slots[FREECNT(th)-1] = -1;
  139. th->entries[slot] = entry;
  140. entry->entry_->_timer_id = slot;
  141. ++th->cur_size;
  142. return PJ_SUCCESS;
  143. }
  144. /* Free a slot when an entry's timer has elapsed or cancel */
  145. static pj_status_t remove_entry(pj_timer_heap_t *th, CPjTimerEntry *entry)
  146. {
  147. int slot = entry->entry_->_timer_id;
  148. PJ_ASSERT_RETURN(slot >= 0 && slot < (int)th->max_size, PJ_EBUG);
  149. PJ_ASSERT_RETURN(FREECNT(th) < th->max_size, PJ_EBUG);
  150. PJ_ASSERT_RETURN(th->entries[slot]==entry, PJ_EBUG);
  151. PJ_ASSERT_RETURN(th->free_slots[FREECNT(th)]==-1, PJ_EBUG);
  152. th->entries[slot] = NULL;
  153. th->free_slots[FREECNT(th)] = slot;
  154. entry->entry_->_timer_id = -1;
  155. --th->cur_size;
  156. return PJ_SUCCESS;
  157. }
  158. CPjTimerEntry::CPjTimerEntry(pj_timer_heap_t *timer_heap,
  159. pj_timer_entry *entry)
  160. : CActive(PJ_SYMBIAN_TIMER_PRIORITY), entry_(entry), timer_heap_(timer_heap),
  161. interval_left_(0)
  162. {
  163. }
  164. CPjTimerEntry::~CPjTimerEntry()
  165. {
  166. Cancel();
  167. rtimer_.Close();
  168. }
  169. void CPjTimerEntry::Schedule()
  170. {
  171. pj_int32_t interval;
  172. if (interval_left_ > MAX_RTIMER_INTERVAL) {
  173. interval = MAX_RTIMER_INTERVAL;
  174. } else {
  175. interval = interval_left_;
  176. }
  177. interval_left_ -= interval;
  178. rtimer_.After(iStatus, interval * 1000);
  179. SetActive();
  180. }
  181. void CPjTimerEntry::ConstructL(const pj_time_val *delay)
  182. {
  183. rtimer_.CreateLocal();
  184. CActiveScheduler::Add(this);
  185. interval_left_ = PJ_TIME_VAL_MSEC(*delay);
  186. Schedule();
  187. }
  188. CPjTimerEntry* CPjTimerEntry::NewL(pj_timer_heap_t *timer_heap,
  189. pj_timer_entry *entry,
  190. const pj_time_val *delay)
  191. {
  192. CPjTimerEntry *self = new CPjTimerEntry(timer_heap, entry);
  193. CleanupStack::PushL(self);
  194. self->ConstructL(delay);
  195. CleanupStack::Pop(self);
  196. return self;
  197. }
  198. void CPjTimerEntry::RunL()
  199. {
  200. if (interval_left_ > 0) {
  201. Schedule();
  202. return;
  203. }
  204. remove_entry(timer_heap_, this);
  205. entry_->cb(timer_heap_, entry_);
  206. // Finger's crossed!
  207. delete this;
  208. }
  209. void CPjTimerEntry::DoCancel()
  210. {
  211. /* It's possible that _timer_id is -1, see schedule(). In this case,
  212. * the entry has not been added to the timer heap, so don't remove
  213. * it.
  214. */
  215. if (entry_ && entry_->_timer_id != -1)
  216. remove_entry(timer_heap_, this);
  217. rtimer_.Cancel();
  218. }
  219. //////////////////////////////////////////////////////////////////////////////
  220. /*
  221. * Calculate memory size required to create a timer heap.
  222. */
  223. PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
  224. {
  225. return /* size of the timer heap itself: */
  226. sizeof(pj_timer_heap_t) +
  227. /* size of each entry: */
  228. (count+2) * (sizeof(void*)+sizeof(int)) +
  229. /* lock, pool etc: */
  230. 132;
  231. }
  232. /*
  233. * Create a new timer heap.
  234. */
  235. PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
  236. pj_size_t size,
  237. pj_timer_heap_t **p_heap)
  238. {
  239. pj_timer_heap_t *ht;
  240. pj_status_t status;
  241. PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
  242. *p_heap = NULL;
  243. /* Allocate timer heap data structure from the pool */
  244. ht = PJ_POOL_ZALLOC_T(pool, pj_timer_heap_t);
  245. if (!ht)
  246. return PJ_ENOMEM;
  247. /* Allocate slots */
  248. status = realloc_timer_heap(ht, size);
  249. if (status != PJ_SUCCESS)
  250. return status;
  251. *p_heap = ht;
  252. return PJ_SUCCESS;
  253. }
  254. PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )
  255. {
  256. /* Cancel and delete pending active objects */
  257. if (ht->entries) {
  258. unsigned i;
  259. for (i=0; i<ht->max_size; ++i) {
  260. if (ht->entries[i]) {
  261. ht->entries[i]->entry_ = NULL;
  262. ht->entries[i]->Cancel();
  263. delete ht->entries[i];
  264. ht->entries[i] = NULL;
  265. }
  266. }
  267. }
  268. delete [] ht->entries;
  269. delete [] ht->free_slots;
  270. ht->entries = NULL;
  271. ht->free_slots = NULL;
  272. }
  273. PJ_DEF(void) pj_timer_heap_set_lock( pj_timer_heap_t *ht,
  274. pj_lock_t *lock,
  275. pj_bool_t auto_del )
  276. {
  277. PJ_UNUSED_ARG(ht);
  278. if (auto_del)
  279. pj_lock_destroy(lock);
  280. }
  281. PJ_DEF(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,
  282. unsigned count )
  283. {
  284. /* Not applicable */
  285. PJ_UNUSED_ARG(count);
  286. return ht->max_size;
  287. }
  288. PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
  289. int id,
  290. void *user_data,
  291. pj_timer_heap_callback *cb )
  292. {
  293. pj_assert(entry && cb);
  294. entry->_timer_id = -1;
  295. entry->id = id;
  296. entry->user_data = user_data;
  297. entry->cb = cb;
  298. return entry;
  299. }
  300. PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
  301. pj_timer_entry *entry,
  302. const pj_time_val *delay)
  303. {
  304. CPjTimerEntry *timerObj;
  305. pj_status_t status;
  306. PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
  307. PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
  308. /* Prevent same entry from being scheduled more than once */
  309. PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
  310. entry->_timer_id = -1;
  311. timerObj = CPjTimerEntry::NewL(ht, entry, delay);
  312. status = add_entry(ht, timerObj);
  313. if (status != PJ_SUCCESS) {
  314. timerObj->Cancel();
  315. delete timerObj;
  316. return status;
  317. }
  318. return PJ_SUCCESS;
  319. }
  320. PJ_DEF(pj_status_t) pj_timer_heap_schedule_w_grp_lock(pj_timer_heap_t *ht,
  321. pj_timer_entry *entry,
  322. const pj_time_val *delay,
  323. int id_val,
  324. pj_grp_lock_t *grp_lock)
  325. {
  326. pj_status_t status;
  327. PJ_UNUSED_ARG(grp_lock);
  328. status = pj_timer_heap_schedule(ht, entry, delay);
  329. if (status == PJ_SUCCESS)
  330. entry->id = id_val;
  331. return status;
  332. }
  333. PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
  334. pj_timer_entry *entry)
  335. {
  336. PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
  337. if (entry->_timer_id >= 0 && entry->_timer_id < (int)ht->max_size) {
  338. CPjTimerEntry *timerObj = ht->entries[entry->_timer_id];
  339. if (timerObj) {
  340. timerObj->Cancel();
  341. delete timerObj;
  342. return 1;
  343. } else {
  344. return 0;
  345. }
  346. } else {
  347. return 0;
  348. }
  349. }
  350. PJ_DEF(int) pj_timer_heap_cancel_if_active(pj_timer_heap_t *ht,
  351. pj_timer_entry *entry,
  352. int id_val)
  353. {
  354. int count = pj_timer_heap_cancel(ht, entry);
  355. if (count == 1)
  356. entry->id = id_val;
  357. return count;
  358. }
  359. PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht,
  360. pj_time_val *next_delay )
  361. {
  362. /* Polling is not necessary on Symbian, since all async activities
  363. * are registered to active scheduler.
  364. */
  365. PJ_UNUSED_ARG(ht);
  366. if (next_delay) {
  367. next_delay->sec = 1;
  368. next_delay->msec = 0;
  369. }
  370. return 0;
  371. }
  372. PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
  373. {
  374. PJ_ASSERT_RETURN(ht, 0);
  375. return ht->cur_size;
  376. }
  377. PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
  378. pj_time_val *timeval)
  379. {
  380. /* We don't support this! */
  381. PJ_UNUSED_ARG(ht);
  382. timeval->sec = 1;
  383. timeval->msec = 0;
  384. return PJ_SUCCESS;
  385. }