You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.3 KiB
151 lines
4.3 KiB
// License: Apache 2.0. See LICENSE file in root directory.
|
|
// Copyright(c) 2021 Intel Corporation. All Rights Reserved.
|
|
|
|
//#cmake:dependencies rsutils
|
|
|
|
#include <unit-tests/test.h>
|
|
#include <rsutils/time/timer.h>
|
|
#include <rsutils/concurrency/concurrency.h>
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
using namespace rsutils::time;
|
|
|
|
TEST_CASE( "dequeue doesn't wait after stop" )
|
|
{
|
|
typedef std::function< void( void ) > scq_value_t;
|
|
single_consumer_queue< scq_value_t > scq;
|
|
scq_value_t f;
|
|
scq_value_t * f_ptr = &f;
|
|
|
|
scq.enqueue( []() {} );
|
|
REQUIRE( scq.size() == 1 );
|
|
REQUIRE( scq.peek( [&]( scq_value_t const & ) {} ));
|
|
|
|
REQUIRE( scq.started() );
|
|
REQUIRE_FALSE( scq.stopped() );
|
|
|
|
scq.stop();
|
|
|
|
REQUIRE_FALSE( scq.peek( [&]( scq_value_t const& ) {} ) );
|
|
REQUIRE( scq.stopped() );
|
|
REQUIRE_FALSE( scq.started() );
|
|
|
|
REQUIRE( scq.empty() );
|
|
|
|
timer t( std::chrono::seconds( 1 ) );
|
|
t.start();
|
|
scq.dequeue( &f, 2000 );
|
|
REQUIRE_FALSE( t.has_expired() ); // Verify no timeout, dequeue return in less than 10 seconds
|
|
}
|
|
|
|
|
|
TEST_CASE( "dequeue doesn't wait when queue is not empty" )
|
|
{
|
|
single_consumer_queue< std::function< void( void ) > > scq;
|
|
timer t( std::chrono::seconds( 1 ) );
|
|
std::function< void( void ) > f;
|
|
|
|
scq.enqueue( []() {} );
|
|
t.start();
|
|
scq.dequeue( &f, 3000 );
|
|
REQUIRE_FALSE( t.has_expired() ); // Verify no timeout, dequeue return in less than 1 seconds
|
|
REQUIRE( scq.empty() );
|
|
}
|
|
|
|
TEST_CASE( "dequeue wait when queue is empty" )
|
|
{
|
|
single_consumer_queue< std::function< void( void ) > > scq;
|
|
timer t( std::chrono::milliseconds( 2900 ) );
|
|
|
|
std::function< void( void ) > f;
|
|
|
|
t.start();
|
|
REQUIRE_FALSE( scq.dequeue( &f, 3000 ) );
|
|
REQUIRE( t.has_expired() ); // Verify timeout, dequeue return after >= 3 seconds
|
|
}
|
|
|
|
TEST_CASE( "try dequeue" )
|
|
{
|
|
single_consumer_queue< std::function< void( void ) > > scq;
|
|
std::function< void( void ) > f;
|
|
|
|
REQUIRE_FALSE( scq.try_dequeue( &f ) ); // nothing on queue
|
|
scq.enqueue( []() {} );
|
|
REQUIRE( scq.try_dequeue( &f ) ); // 1 item on queue
|
|
REQUIRE_FALSE( scq.try_dequeue( &f ) ); // 0 items on queue
|
|
}
|
|
|
|
TEST_CASE( "blocking enqueue" )
|
|
{
|
|
single_consumer_queue< std::function< void( void ) > > scq;
|
|
std::function< void( void ) > f;
|
|
stopwatch sw;
|
|
|
|
sw.reset();
|
|
|
|
// dequeue an item after 5 seconds, we wait for the blocking call and verify we return after this dequeue call ~ 5 seconds
|
|
std::thread dequeue_thread( [&]() {
|
|
std::this_thread::sleep_for( std::chrono::seconds( 5 ) );
|
|
scq.dequeue( &f, 1000 );
|
|
} );
|
|
|
|
REQUIRE( sw.get_elapsed_ms() < 1000 );
|
|
|
|
for( int i = 0; i < 10; ++i )
|
|
{
|
|
scq.blocking_enqueue( []() {} );
|
|
}
|
|
REQUIRE( sw.get_elapsed_ms() < 1000 );
|
|
REQUIRE( scq.size() == 10 ); // verify queue is full (default capacity is 10)
|
|
scq.blocking_enqueue( []() {} ); // add a blocking call (item 11)
|
|
REQUIRE( sw.get_elapsed_ms() > 5000 ); // verify the blocking call return on dequeue time
|
|
REQUIRE( sw.get_elapsed_ms() < 6000 ); // verify the blocking call return on dequeue time
|
|
|
|
dequeue_thread.join(); // verify clean exit with no threads alive.
|
|
}
|
|
|
|
TEST_CASE("verify mutex protection")
|
|
{
|
|
single_consumer_queue< int > scq;
|
|
stopwatch sw;
|
|
|
|
const int MAX_SIZE_FOR_THREAD = 20;
|
|
std::thread enqueue_thread1( [&]() {
|
|
for( int i = 0; i < MAX_SIZE_FOR_THREAD; ++i )
|
|
{
|
|
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
|
scq.blocking_enqueue(std::move(i));
|
|
}
|
|
} );
|
|
|
|
std::thread enqueue_thread2( [&]() {
|
|
for( int i = 0; i < MAX_SIZE_FOR_THREAD; ++i )
|
|
{
|
|
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
|
scq.blocking_enqueue(std::move(20 + i));
|
|
}
|
|
} );
|
|
|
|
std::vector<int> all_values;
|
|
for( int i = 0; i < MAX_SIZE_FOR_THREAD * 2; ++i )
|
|
{
|
|
int val;
|
|
scq.dequeue( &val, 1000 );
|
|
all_values.push_back(val);
|
|
}
|
|
|
|
REQUIRE(all_values.size() == MAX_SIZE_FOR_THREAD * 2);
|
|
|
|
std::sort(all_values.begin(), all_values.end());
|
|
|
|
for (int i = 0; i < all_values.size(); ++i)
|
|
{
|
|
REQUIRE(all_values[i] == i);
|
|
}
|
|
|
|
enqueue_thread1.join();
|
|
enqueue_thread2.join();
|
|
}
|