Skip to content

Commit c5ec448

Browse files
committed
timertt updated to v1.2.4.
Version bumped to 5.8.5.1.
1 parent 00f4b53 commit c5ec448

4 files changed

Lines changed: 89 additions & 40 deletions

File tree

dev/so_5/3rd_party/timertt/all.hpp

Lines changed: 86 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
* \since
6868
* v.1.2.1
6969
*/
70-
#define TIMERTT_VERSION 1002003u
70+
#define TIMERTT_VERSION 1002004u
7171

7272
/*!
7373
* \brief Top-level project's namespace.
@@ -845,10 +845,11 @@ struct timer_wheel_engine_defaults
845845
*
846846
* This class uses <a href="http://www.cs.columbia.edu/~nahum/w6998/papers/ton97-timing-wheels.pdf">timer_wheel</a>
847847
* mechanism to work with timers.
848-
* This mechanism is efficient for working with big amount of timers.
849-
* But it requires that timer thread is working always, even in case
850-
* when there is no timers. Another price for timer_wheel is the
851-
* granularity of timer steps.
848+
* This mechanism is efficient for working with big amount of timers. But this
849+
* mechanism can consume some more resources when there is a small number of
850+
* waiting timers. It's because there is a wakeup at every time step of the
851+
* wheel, even if there is no elapsed timers for that step. Another price for
852+
* timer_wheel is the granularity of timer steps.
852853
*
853854
* Timer wheel data structure consists from one fixed size vector
854855
* (the wheel) and several double-linked list (one list for every wheel
@@ -861,7 +862,7 @@ struct timer_wheel_engine_defaults
861862
*
862863
* \note At the beginnig of time step thread detects elapsed timers, then
863864
* unblocks object mutex and calls timer actors for those timers. It means
864-
* that actors call call timer thread object. And there won't be frequent
865+
* that actors can call timer thread object. And there won't be frequent
865866
* mutex locking/unlocking operations for building and processing
866867
* list of elapsed timers. This allows to process millions of timer actor
867868
* per second.
@@ -1631,7 +1632,7 @@ struct timer_list_engine_defaults
16311632
* \tparam Thread_Safety Thread-safety indicator.
16321633
* Must be timertt::thread_safety::unsafe or timertt::thread_safety::safe.
16331634
*
1634-
* \tparam Timer_Action type of functor to perform an user-defined
1635+
* \tparam Time_Action type of functor to perform an user-defined
16351636
* action when timer expires. This must be Moveable and MoveConstructible
16361637
* type.
16371638
*
@@ -1996,7 +1997,7 @@ private :
19961997
//! Insert timer to the list.
19971998
/*!
19981999
* Insertion starts from the tail of the list. And if \a timer
1999-
* has lower timer_type::m_whan value then the last list item
2000+
* has lower timer_type::m_when value then the last list item
20002001
* there is an loop of searching appropriate place by going to
20012002
* the head of the list.
20022003
*
@@ -2231,17 +2232,14 @@ struct timer_heap_engine_defaults
22312232
* the heap. When this timer elapsed and removed next timer with the
22322233
* eralier time point is going to the top of the heap.
22332234
*
2234-
* This implementation uses array-based <a
2235-
* href="http://en.wikipedia.org/wiki/Binary_heap">binary heap</a>. The array
2236-
* is growing as necessary to hold all the timers. The initial size of that
2237-
* array can be specified in the constructor.
2235+
* This implementation uses array-based <a href="http://en.wikipedia.org/wiki/Binary_heap">binary heap</a>.
2236+
* The array is growing as necessary to hold all the timers. The initial size
2237+
* of that array can be specified in the constructor.
22382238
*
2239-
* \note Unlike timer_wheel and timer_list threads this thread unlock and
2240-
* lock its mutex for processing every timers. It means that processing
2241-
* speed of this thread will be slower then for timer_wheel or
2242-
* timer_list threads. But this type of thread doesn't consume resources
2243-
* when there is no timers (unlike timer_wheel thread). And has very
2244-
* efficient activation and deactivation procedures (unlike timer_list
2239+
* \note Unlike timer_wheel and timer_list threads this thread unlock and lock
2240+
* its mutex for processing every timers. It means that processing speed of
2241+
* this thread will be slower then for timer_wheel or timer_list threads. And
2242+
* has very efficient activation and deactivation procedures (unlike timer_list
22452243
* thread).
22462244
*
22472245
* \tparam Thread_Safety Thread-safety indicator.
@@ -2739,39 +2737,56 @@ private :
27392737
heap_remove( timer_type * timer )
27402738
{
27412739
if( timer->m_position == m_heap.size() )
2740+
{
27422741
// A special case: timer to remove is a last added item
27432742
// in the heap. It could be simply removed from heap
27442743
// without any other actions.
27452744
m_heap.pop_back();
2745+
}
27462746
else
27472747
{
27482748
auto last_item = m_heap.back();
27492749
heap_swap( timer, last_item );
27502750
m_heap.pop_back();
27512751

2752-
// last_item must be heap-down to the appropriate place.
2753-
while( true )
2752+
// If timer->m_position is not 1 then we can violate
2753+
// binary heap order. The last_item can now:
2754+
//
2755+
// - be less than its new parent;
2756+
// - be greater than any of its new children.
2757+
//
2758+
// If the last_item is less than new parent then we
2759+
// have to heap it up. If we move the last_item up then there
2760+
// is no need to check order down of it.
2761+
//
2762+
// But if the last_item wasn't moved up then we have to
2763+
// check the order down of it.
2764+
bool should_be_checked_down = true;
2765+
2766+
// NOTE: there is no need to check upward direction
2767+
// if removed timer was the head of the heap.
2768+
while( last_item->m_position > std::size_t{ 1 } )
27542769
{
2755-
auto left_index = last_item->m_position * 2;
2756-
auto right_index = left_index + 1;
2757-
auto min_index = last_item->m_position;
2758-
2759-
if( left_index <= m_heap.size() &&
2760-
heap_item( left_index )->m_when <=
2761-
heap_item( min_index )->m_when )
2762-
min_index = left_index;
2763-
2764-
if( right_index <= m_heap.size() &&
2765-
heap_item( right_index )->m_when <=
2766-
heap_item( min_index )->m_when )
2767-
min_index = right_index;
2768-
2769-
if( min_index != last_item->m_position )
2770-
heap_swap( last_item, heap_item( min_index ) );
2770+
auto parent = heap_item(
2771+
last_item->m_position / std::size_t{ 2 } );
2772+
if( parent->m_when > last_item->m_when )
2773+
{
2774+
// Timer must be heap-up on the place of the parent node.
2775+
heap_swap( parent, last_item );
2776+
// There is no need to do additional check in downward
2777+
// order (because parent is guaranteed to be less then
2778+
// children noded).
2779+
should_be_checked_down = false;
2780+
}
27712781
else
2772-
// Heap structure is correct.
2782+
{
2783+
// There is no need to modify heap structure anymore.
27732784
break;
2785+
}
27742786
}
2787+
2788+
if( should_be_checked_down )
2789+
heap_down_item( last_item );
27752790
}
27762791
}
27772792

@@ -2785,6 +2800,40 @@ private :
27852800
std::swap( a->m_position, b->m_position );
27862801
}
27872802

2803+
//! Helper method to ensure that children of the specified
2804+
//! item are greater.
2805+
//!
2806+
//! If this isn't true then \a subtree_head will be moved down
2807+
//! the heap until the appropriate place will be found.
2808+
void
2809+
heap_down_item( timer_type * subtree_head )
2810+
{
2811+
do
2812+
{
2813+
auto left_index = subtree_head->m_position * std::size_t{ 2 };
2814+
auto right_index = left_index + std::size_t{ 1 };
2815+
auto min_index = subtree_head->m_position;
2816+
2817+
if( left_index <= m_heap.size() &&
2818+
heap_item( left_index )->m_when <=
2819+
heap_item( min_index )->m_when )
2820+
min_index = left_index;
2821+
2822+
if( right_index <= m_heap.size() &&
2823+
heap_item( right_index )->m_when <=
2824+
heap_item( min_index )->m_when )
2825+
min_index = right_index;
2826+
2827+
if( min_index != subtree_head->m_position )
2828+
{
2829+
heap_swap( subtree_head, heap_item( min_index ) );
2830+
}
2831+
else
2832+
// Heap structure is correct.
2833+
break;
2834+
} while( true );
2835+
}
2836+
27882837
//! Get timer by it index.
27892838
/*!
27902839
* This accessor work with respect that positions are started from 1.

dev/so_5/cmake/target.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
set(SO_5_VERSION "5.8.5")
1+
set(SO_5_VERSION "5.8.5.1")
22
set(SO_5_SHARED_LIB so.${SO_5_VERSION})
33
set(SO_5_STATIC_LIB so_s.${SO_5_VERSION})

dev/so_5/version.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* or API fixes are added to SObjectizer but SObjectizer API is compatible on
4343
* source-code level.
4444
*/
45-
#define SO_5_VERSION_PATCH 0ull
45+
#define SO_5_VERSION_PATCH 1ull
4646

4747
/*!
4848
* Helper macro for make single number representation of SObjectizer's version.

dev/so_5/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
module So5
2-
VERSION = "5.8.5"
2+
VERSION = "5.8.5.1"
33
end
44

0 commit comments

Comments
 (0)