@ -200,6 +200,197 @@ TEST(EnvPosixTest, TwoPools) {
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
}
TEST ( EnvPosixTest , DecreaseNumBgThreads ) {
class SleepingBackgroundTask {
public :
explicit SleepingBackgroundTask ( )
: bg_cv_ ( & mutex_ ) , should_sleep_ ( true ) , sleeping_ ( false ) { }
void DoSleep ( ) {
MutexLock l ( & mutex_ ) ;
sleeping_ = true ;
while ( should_sleep_ ) {
bg_cv_ . Wait ( ) ;
}
sleeping_ = false ;
bg_cv_ . SignalAll ( ) ;
}
void WakeUp ( ) {
MutexLock l ( & mutex_ ) ;
should_sleep_ = false ;
bg_cv_ . SignalAll ( ) ;
while ( sleeping_ ) {
bg_cv_ . Wait ( ) ;
}
}
bool IsSleeping ( ) {
MutexLock l ( & mutex_ ) ;
return sleeping_ ;
}
static void DoSleepTask ( void * arg ) {
reinterpret_cast < SleepingBackgroundTask * > ( arg ) - > DoSleep ( ) ;
}
private :
port : : Mutex mutex_ ;
port : : CondVar bg_cv_ ; // Signalled when background work finishes
bool should_sleep_ ;
bool sleeping_ ;
} ;
std : : vector < SleepingBackgroundTask > tasks ( 10 ) ;
// Set number of thread to 1 first.
env_ - > SetBackgroundThreads ( 1 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
// Schedule 3 tasks. 0 running; Task 1, 2 waiting.
for ( size_t i = 0 ; i < 3 ; i + + ) {
env_ - > Schedule ( & SleepingBackgroundTask : : DoSleepTask , & tasks [ i ] ,
Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
}
ASSERT_EQ ( 2U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 0 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 1 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 2 ] . IsSleeping ( ) ) ;
// Increase to 2 threads. Task 0, 1 running; 2 waiting
env_ - > SetBackgroundThreads ( 2 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 1U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 0 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 1 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 2 ] . IsSleeping ( ) ) ;
// Shrink back to 1 thread. Still task 0, 1 running, 2 waiting
env_ - > SetBackgroundThreads ( 1 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 1U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 0 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 1 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 2 ] . IsSleeping ( ) ) ;
// The last task finishes. Task 0 running, 2 waiting.
tasks [ 1 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 1U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 0 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 1 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 2 ] . IsSleeping ( ) ) ;
// Increase to 5 threads. Task 0 and 2 running.
env_ - > SetBackgroundThreads ( 5 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0 , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 0 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 2 ] . IsSleeping ( ) ) ;
// Change number of threads a couple of times while there is no sufficient
// tasks.
env_ - > SetBackgroundThreads ( 7 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
tasks [ 2 ] . WakeUp ( ) ;
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
env_ - > SetBackgroundThreads ( 3 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
env_ - > SetBackgroundThreads ( 4 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
env_ - > SetBackgroundThreads ( 5 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
env_ - > SetBackgroundThreads ( 4 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros * 50 ) ;
// Enqueue 5 more tasks. Thread pool size now is 4.
// Task 0, 3, 4, 5 running;6, 7 waiting.
for ( size_t i = 3 ; i < 8 ; i + + ) {
env_ - > Schedule ( & SleepingBackgroundTask : : DoSleepTask , & tasks [ i ] ,
Env : : Priority : : HIGH ) ;
}
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 2U , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 3 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 4 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 5 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 6 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 7 ] . IsSleeping ( ) ) ;
// Wake up task 0, 3 and 4. Task 5, 6, 7 running.
tasks [ 0 ] . WakeUp ( ) ;
tasks [ 3 ] . WakeUp ( ) ;
tasks [ 4 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0 , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
for ( size_t i = 5 ; i < 8 ; i + + ) {
ASSERT_TRUE ( tasks [ i ] . IsSleeping ( ) ) ;
}
// Shrink back to 1 thread. Still task 5, 6, 7 running
env_ - > SetBackgroundThreads ( 1 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( tasks [ 5 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 6 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 7 ] . IsSleeping ( ) ) ;
// Wake up task 6. Task 5, 7 running
tasks [ 6 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( tasks [ 5 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( ! tasks [ 6 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 7 ] . IsSleeping ( ) ) ;
// Wake up threads 7. Task 5 running
tasks [ 7 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( ! tasks [ 7 ] . IsSleeping ( ) ) ;
// Enqueue thread 8 and 9. Task 5 running; one of 8, 9 might be running.
env_ - > Schedule ( & SleepingBackgroundTask : : DoSleepTask , & tasks [ 8 ] ,
Env : : Priority : : HIGH ) ;
env_ - > Schedule ( & SleepingBackgroundTask : : DoSleepTask , & tasks [ 9 ] ,
Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_GT ( env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) , 0 ) ;
ASSERT_TRUE ( ! tasks [ 8 ] . IsSleeping ( ) | | ! tasks [ 9 ] . IsSleeping ( ) ) ;
// Increase to 4 threads. Task 5, 8, 9 running.
env_ - > SetBackgroundThreads ( 4 , Env : : Priority : : HIGH ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_EQ ( 0 , env_ - > GetThreadPoolQueueLen ( Env : : Priority : : HIGH ) ) ;
ASSERT_TRUE ( tasks [ 8 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 9 ] . IsSleeping ( ) ) ;
// Shrink to 1 thread
env_ - > SetBackgroundThreads ( 1 , Env : : Priority : : HIGH ) ;
// Wake up thread 9.
tasks [ 9 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( ! tasks [ 9 ] . IsSleeping ( ) ) ;
ASSERT_TRUE ( tasks [ 8 ] . IsSleeping ( ) ) ;
// Wake up thread 8
tasks [ 8 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( ! tasks [ 8 ] . IsSleeping ( ) ) ;
// Wake up the last thread
tasks [ 5 ] . WakeUp ( ) ;
Env : : Default ( ) - > SleepForMicroseconds ( kDelayMicros ) ;
ASSERT_TRUE ( ! tasks [ 5 ] . IsSleeping ( ) ) ;
}
# ifdef OS_LINUX
// To make sure the Env::GetUniqueId() related tests work correctly, The files
// should be stored in regular storage like "hard disk" or "flash device".