MAJOR BUG FIX - fc::usleep causing hang&leak
In certain cases when usleep is passed a small value, there is a race condition that would cause the process to hang and then when an attempt to quit the thread was made new contexts would be allocated rapidly filling all available memory.
This commit is contained in:
parent
24768d2d26
commit
7bf6374299
3 changed files with 42 additions and 20 deletions
|
|
@ -136,4 +136,6 @@ set( BOOST_LIBRARIES ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_FIL
|
|||
#target_link_libraries( test_compress fc ${BOOST_LIBRARIES} )
|
||||
#add_executable( test_aes tests/aes_test.cpp )
|
||||
#target_link_libraries( test_aes fc ${BOOST_LIBRARIES} )
|
||||
#add_executable( test_sleep tests/sleep.cpp )
|
||||
#target_link_libraries( test_sleep fc ${BOOST_LIBRARIES} )
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ namespace fc {
|
|||
cur->canceled = true;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
my->done = true;
|
||||
|
||||
// now that we have poked all fibers... switch to the next one and
|
||||
|
|
@ -177,6 +176,14 @@ namespace fc {
|
|||
my->check_fiber_exceptions();
|
||||
}
|
||||
void thread::sleep_until( const time_point& tp ) {
|
||||
//ilog( "sleep until ${tp} wait: ${delta}", ("tp",tp)("delta",(tp-fc::time_point::now()).count()) );
|
||||
|
||||
if( tp <= (time_point::now()+fc::microseconds(500)) )
|
||||
{
|
||||
this->yield(true);
|
||||
}
|
||||
my->yield_until( tp, false );
|
||||
/*
|
||||
my->check_fiber_exceptions();
|
||||
|
||||
BOOST_ASSERT( ¤t() == this );
|
||||
|
|
@ -195,6 +202,7 @@ namespace fc {
|
|||
my->current->resume_time = time_point::maximum();
|
||||
|
||||
my->check_fiber_exceptions();
|
||||
*/
|
||||
}
|
||||
int thread::wait_any_until( std::vector<promise_base::ptr>&& p, const time_point& timeout) {
|
||||
for( size_t i = 0; i < p.size(); ++i ) {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace fc {
|
|||
|
||||
#if 0
|
||||
void debug( const fc::string& s ) {
|
||||
return;
|
||||
return;
|
||||
//boost::unique_lock<boost::mutex> lock(log_mutex());
|
||||
|
||||
fc::cerr<<"--------------------- "<<s.c_str()<<" - "<<current;
|
||||
|
|
@ -165,7 +165,7 @@ namespace fc {
|
|||
void ready_push_front( const fc::context::ptr& c ) {
|
||||
BOOST_ASSERT( c->next == nullptr );
|
||||
BOOST_ASSERT( c != current );
|
||||
//if( c == current ) wlog( "pushing current to ready??" );
|
||||
//if( c == current ) wlog( "pushing current to ready??" );
|
||||
c->next = ready_head;
|
||||
ready_head = c;
|
||||
if( !ready_tail )
|
||||
|
|
@ -174,7 +174,7 @@ namespace fc {
|
|||
void ready_push_back( const fc::context::ptr& c ) {
|
||||
BOOST_ASSERT( c->next == nullptr );
|
||||
BOOST_ASSERT( c != current );
|
||||
//if( c == current ) wlog( "pushing current to ready??" );
|
||||
//if( c == current ) wlog( "pushing current to ready??" );
|
||||
c->next = 0;
|
||||
if( ready_tail ) {
|
||||
ready_tail->next = c;
|
||||
|
|
@ -246,6 +246,7 @@ namespace fc {
|
|||
if( current && current->canceled ) {
|
||||
FC_THROW_EXCEPTION( canceled_exception, "" );
|
||||
} else if( done ) {
|
||||
ilog( "throwing canceled exception" );
|
||||
FC_THROW_EXCEPTION( canceled_exception, "" );
|
||||
// BOOST_THROW_EXCEPTION( thread_quit() );
|
||||
}
|
||||
|
|
@ -398,47 +399,58 @@ namespace fc {
|
|||
*/
|
||||
time_point check_for_timeouts() {
|
||||
if( !sleep_pqueue.size() && !task_sch_queue.size() ) {
|
||||
//ilog( "no timeouts ready" );
|
||||
return time_point::maximum();
|
||||
}
|
||||
|
||||
|
||||
time_point next = time_point::maximum();
|
||||
if( task_sch_queue.size() && next > task_sch_queue.front()->_when )
|
||||
next = task_sch_queue.front()->_when;
|
||||
if( sleep_pqueue.size() && next > sleep_pqueue.front()->resume_time )
|
||||
next = sleep_pqueue.front()->resume_time;
|
||||
if( task_sch_queue.size() && next > task_sch_queue.front()->_when )
|
||||
next = task_sch_queue.front()->_when;
|
||||
|
||||
time_point now = time_point::now();
|
||||
if( now < next ) { return next; }
|
||||
|
||||
// move all expired sleeping tasks to the ready queue
|
||||
while( sleep_pqueue.size() && sleep_pqueue.front()->resume_time < now ) {
|
||||
while( sleep_pqueue.size() && sleep_pqueue.front()->resume_time < now )
|
||||
{
|
||||
fc::context::ptr c = sleep_pqueue.front();
|
||||
std::pop_heap(sleep_pqueue.begin(), sleep_pqueue.end(), sleep_priority_less() );
|
||||
//ilog( "sleep pop back..." );
|
||||
sleep_pqueue.pop_back();
|
||||
|
||||
if( c->blocking_prom.size() ) {
|
||||
if( c->blocking_prom.size() )
|
||||
{
|
||||
// ilog( "timeotu blocking prom" );
|
||||
c->timeout_blocking_promises();
|
||||
}
|
||||
else {
|
||||
if( c != current ) ready_push_front( c );
|
||||
else
|
||||
{
|
||||
//ilog( "..." );
|
||||
FC_ASSERT( c != current )
|
||||
//ilog( "ready_push_front" );
|
||||
ready_push_front( c );
|
||||
}
|
||||
}
|
||||
return time_point::min();
|
||||
}
|
||||
|
||||
void unblock( fc::context* c ) {
|
||||
if( fc::thread::current().my != this ) {
|
||||
async( [=](){ unblock(c); } );
|
||||
return;
|
||||
}
|
||||
if( c != current ) ready_push_front(c);
|
||||
}
|
||||
void unblock( fc::context* c ) {
|
||||
if( fc::thread::current().my != this ) {
|
||||
async( [=](){ unblock(c); } );
|
||||
return;
|
||||
}
|
||||
if( c != current ) ready_push_front(c);
|
||||
}
|
||||
|
||||
void yield_until( const time_point& tp, bool reschedule ) {
|
||||
check_fiber_exceptions();
|
||||
|
||||
if( tp <= time_point::now() )
|
||||
if( tp <= (time_point::now()+fc::microseconds(500)) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !current ) {
|
||||
current = new fc::context(&fc::thread::current());
|
||||
|
|
@ -450,7 +462,7 @@ namespace fc {
|
|||
sleep_pqueue.push_back(current);
|
||||
std::push_heap( sleep_pqueue.begin(),
|
||||
sleep_pqueue.end(), sleep_priority_less() );
|
||||
|
||||
|
||||
start_next_fiber(reschedule);
|
||||
|
||||
// clear current context from sleep queue...
|
||||
|
|
|
|||
Loading…
Reference in a new issue