<commit_before>#include "MockEvent.h"

#include <gtest/gtest.h>

class TimedEventEnvironment : public ::testing::Environment
{
    public:

        TimedEventEnvironment() : work_(service_) {}

        void SetUp()
        {
            thread_ = new boost::thread(&TimedEventEnvironment::run, this);
        }

        void TearDown()
        {
            service_.stop();
            thread_->join();
        }

        void run()
        {
            service_.run();
        }

        boost::asio::io_service service_;

        boost::asio::io_service::work work_;

        boost::thread *thread_;
};

TimedEventEnvironment* const env = dynamic_cast<TimedEventEnvironment*>(testing::AddGlobalTestEnvironment(new TimedEventEnvironment));

TEST(TimedEvent, EventNonAutoDestruc_SuccessEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
    {
        event.restart_timer();

        ASSERT_TRUE(event.wait(200));
    }

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 10);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 0);
}

TEST(TimedEvent, EventNonAutoDestruc_CancelEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
    {
        event.restart_timer();
        event.cancel_timer();

        ASSERT_TRUE(event.wait(200));
    }

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);
}

TEST(TimedEvent, EventNonAutoDestruc_RestartEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
        event.restart_timer();

    for(int i = 0; i < 10; ++i)
        ASSERT_TRUE(event.wait(200));

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 1);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 9);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_SuccessEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    event->restart_timer();
    ASSERT_TRUE(event->wait(200));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_CancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    // Cancel ten times.
    for(int i = 0; i < 10; ++i)
    {
        event->restart_timer();
        event->cancel_timer();

        ASSERT_TRUE(event->wait(200));

        boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

        if(MockEvent::destructed_ != 1)
            MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

        ASSERT_EQ(MockEvent::destructed_, 0);
    }

    int successed = event->successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event->cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);

    // Last event will be successful.
    event->restart_timer();
    ASSERT_TRUE(event->wait(200));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_QuickCancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    // Cancel ten times.
    for(int i = 0; i < 10; ++i)
    {
        event->restart_timer();
        event->cancel_timer();

        ASSERT_TRUE(event->wait(10));

        boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

        if(MockEvent::destructed_ != 1)
            MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

        ASSERT_EQ(MockEvent::destructed_, 0);
    }

    int successed = event->successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event->cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);

    // Last event will be successful.
    event->restart_timer();
    ASSERT_TRUE(event->wait(10));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_RestartEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    for(int i = 0; i < 10; ++i)
        event->restart_timer();

    for(int i = 0; i < 10; ++i)
        ASSERT_TRUE(event->wait(200));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_QuickRestartEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    for(int i = 0; i < 10; ++i)
        event->restart_timer();

    for(int i = 0; i < 10; ++i)
        ASSERT_TRUE(event->wait(10));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_SuccessEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();
    ASSERT_TRUE(event->wait(200));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_CancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();
    event->cancel_timer();

    ASSERT_TRUE(event->wait(200));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_QuickCancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();
    event->cancel_timer();

    ASSERT_TRUE(event->wait(10));

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

// Auxiliary functions to be run in multithread tests.
void restart(MockEvent *event, unsigned int num_loop, unsigned int sleep_time)
{
    for(unsigned int i = 0; i < num_loop; ++i)
    {
        event->restart_timer();

        if(sleep_time > 0)
            usleep(sleep_time);
    }
}

void cancel(MockEvent *event, unsigned int num_loop, unsigned int sleep_time)
{
    for(unsigned int i = 0; i < num_loop; ++i)
    {
        event->cancel_timer();

        if(sleep_time > 0)
            usleep(sleep_time);
    }
}

TEST(TimedEventMultithread, EventNonAutoDestruc_TwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 100ms between each one.
    // Thread 2 -> Cancel 100 times waiting 102ms between each one.
    // Thread 3 -> Restart 80 times waiting 110ms between each one.
    // Thread 4 -> Cancel 80 times waiting 112ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 100);
    thr2 = new boost::thread(cancel, &event, 100, 102);
    thr3 = new boost::thread(restart, &event, 80, 110);
    thr4 = new boost::thread(cancel, &event, 80, 112);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(120));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

TEST(TimedEventMultithread, EventNonAutoDestruc_QuickTwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 2ms between each one.
    // Thread 2 -> Cancel 100 times waiting 2ms between each one.
    // Thread 3 -> Restart 80 times waiting 3ms between each one.
    // Thread 4 -> Cancel 80 times waiting 3ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 2);
    thr2 = new boost::thread(cancel, &event, 100, 2);
    thr3 = new boost::thread(restart, &event, 80, 3);
    thr4 = new boost::thread(cancel, &event, 80, 3);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(10));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

TEST(TimedEventMultithread, EventNonAutoDestruc_QuickestTwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 0ms between each one.
    // Thread 2 -> Cancel 100 times waiting 0ms between each one.
    // Thread 3 -> Restart 80 times waiting 0ms between each one.
    // Thread 4 -> Cancel 80 times waiting 0ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 0);
    thr2 = new boost::thread(cancel, &event, 100, 0);
    thr3 = new boost::thread(restart, &event, 80, 0);
    thr4 = new boost::thread(cancel, &event, 80, 0);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(10));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
#if defined(WIN32) && defined(_DEBUG)
    eprosima::Log::setVerbosity(eprosima::LOG_VERBOSITY_LVL::VERB_ERROR);
#endif
    return RUN_ALL_TESTS();
}
<commit_msg>Refs 1509. Fixed invalid reads in unit tests.<commit_after>#include "MockEvent.h"

#include <gtest/gtest.h>

class TimedEventEnvironment : public ::testing::Environment
{
    public:

        TimedEventEnvironment() : work_(service_) {}

        void SetUp()
        {
            thread_ = new boost::thread(&TimedEventEnvironment::run, this);
        }

        void TearDown()
        {
            service_.stop();
            thread_->join();
            delete thread_;
        }

        void run()
        {
            service_.run();
        }

        boost::asio::io_service service_;

        boost::asio::io_service::work work_;

        boost::thread *thread_;
};

TimedEventEnvironment* const env = dynamic_cast<TimedEventEnvironment*>(testing::AddGlobalTestEnvironment(new TimedEventEnvironment));

TEST(TimedEvent, EventNonAutoDestruc_SuccessEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
    {
        event.restart_timer();

        ASSERT_TRUE(event.wait(200));
    }

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 10);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 0);
}

TEST(TimedEvent, EventNonAutoDestruc_CancelEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
    {
        event.restart_timer();
        event.cancel_timer();

        ASSERT_TRUE(event.wait(200));
    }

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);
}

TEST(TimedEvent, EventNonAutoDestruc_RestartEvents)
{
    MockEvent event(&env->service_, 100);

    for(int i = 0; i < 10; ++i)
        event.restart_timer();

    for(int i = 0; i < 10; ++i)
        ASSERT_TRUE(event.wait(200));

    int successed = event.successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 1);

    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 9);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_SuccessEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_CancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    // Cancel ten times.
    for(int i = 0; i < 10; ++i)
    {
        event->restart_timer();
        event->cancel_timer();

        ASSERT_TRUE(event->wait(200));

        boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

        if(MockEvent::destructed_ != 1)
            MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

        ASSERT_EQ(MockEvent::destructed_, 0);
    }

    int successed = event->successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event->cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);

    // Last event will be successful.
    event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_QuickCancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    // Cancel ten times.
    for(int i = 0; i < 10; ++i)
    {
        event->restart_timer();
        event->cancel_timer();

        ASSERT_TRUE(event->wait(10));

        boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

        if(MockEvent::destructed_ != 1)
            MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

        ASSERT_EQ(MockEvent::destructed_, 0);
    }

    int successed = event->successed_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed, 0);

    int cancelled = event->cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(cancelled, 10);

    // Last event will be successful.
    event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_RestartEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    for(int i = 0; i < 10; ++i)
        event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventOnSuccessAutoDestruc_QuickRestartEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ON_SUCCESS);

    for(int i = 0; i < 10; ++i)
        event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_SuccessEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::seconds(1));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_CancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 100, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();
    event->cancel_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

TEST(TimedEvent, EventAlwaysAutoDestruc_QuickCancelEvents)
{
    // Restart destriction counter.
    MockEvent::destructed_ = 0;
    MockEvent *event = new MockEvent(&env->service_, 0, eprosima::fastrtps::rtps::TimedEvent::ALLWAYS);

    event->restart_timer();
    event->cancel_timer();

    boost::unique_lock<boost::mutex> lock(MockEvent::destruction_mutex_);

    if(MockEvent::destructed_ != 1)
        MockEvent::destruction_cond_.wait_for(lock, boost::chrono::milliseconds(100));

    ASSERT_EQ(MockEvent::destructed_, 1);
}

// Auxiliary functions to be run in multithread tests.
void restart(MockEvent *event, unsigned int num_loop, unsigned int sleep_time)
{
    for(unsigned int i = 0; i < num_loop; ++i)
    {
        event->restart_timer();

        if(sleep_time > 0)
            usleep(sleep_time);
    }
}

void cancel(MockEvent *event, unsigned int num_loop, unsigned int sleep_time)
{
    for(unsigned int i = 0; i < num_loop; ++i)
    {
        event->cancel_timer();

        if(sleep_time > 0)
            usleep(sleep_time);
    }
}

TEST(TimedEventMultithread, EventNonAutoDestruc_TwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 100ms between each one.
    // Thread 2 -> Cancel 100 times waiting 102ms between each one.
    // Thread 3 -> Restart 80 times waiting 110ms between each one.
    // Thread 4 -> Cancel 80 times waiting 112ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 100);
    thr2 = new boost::thread(cancel, &event, 100, 102);
    thr3 = new boost::thread(restart, &event, 80, 110);
    thr4 = new boost::thread(cancel, &event, 80, 112);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(120));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

TEST(TimedEventMultithread, EventNonAutoDestruc_QuickTwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 2ms between each one.
    // Thread 2 -> Cancel 100 times waiting 2ms between each one.
    // Thread 3 -> Restart 80 times waiting 3ms between each one.
    // Thread 4 -> Cancel 80 times waiting 3ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 2);
    thr2 = new boost::thread(cancel, &event, 100, 2);
    thr3 = new boost::thread(restart, &event, 80, 3);
    thr4 = new boost::thread(cancel, &event, 80, 3);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(10));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

TEST(TimedEventMultithread, EventNonAutoDestruc_QuickestTwoStartTwoCancel)
{
    boost::thread *thr1 = nullptr, *thr2 = nullptr,
        *thr3 = nullptr, *thr4 = nullptr;

    MockEvent event(&env->service_, 2);

    // 2 Thread restarting and two thread cancel.
    // Thread 1 -> Restart 100 times waiting 0ms between each one.
    // Thread 2 -> Cancel 100 times waiting 0ms between each one.
    // Thread 3 -> Restart 80 times waiting 0ms between each one.
    // Thread 4 -> Cancel 80 times waiting 0ms between each one.

    thr1 = new boost::thread(restart, &event, 100, 0);
    thr2 = new boost::thread(cancel, &event, 100, 0);
    thr3 = new boost::thread(restart, &event, 80, 0);
    thr4 = new boost::thread(cancel, &event, 80, 0);

    thr1->join();
    thr2->join();
    thr3->join();
    thr4->join();

    delete thr1;
    delete thr2;
    delete thr3;
    delete thr4;

    // Wait all expected times
    for(unsigned int i = 0; i < 180; ++i)
        ASSERT_TRUE(event.wait(10));

    int successed = event.successed_.load(boost::memory_order_relaxed);
    int cancelled = event.cancelled_.load(boost::memory_order_relaxed);

    ASSERT_EQ(successed + cancelled, 180);
}

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
#if defined(WIN32) && defined(_DEBUG)
    eprosima::Log::setVerbosity(eprosima::LOG_VERBOSITY_LVL::VERB_ERROR);
#endif
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2020 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "harness/propertyHelpers.h"
#include "harness/typeWrappers.h"
#include <vector>
#include <algorithm>

typedef enum
{
    image,
    buffer
} mem_obj_type;

struct test_data
{
    mem_obj_type obj_t;
    std::vector<cl_mem_properties> properties;
    std::string description;
    std::string src;
    std::string kernel_name;
};

static int create_object_and_check_properties(cl_context context,
                                              clMemWrapper& test_object,
                                              test_data test_case,
                                              cl_mem_flags flags,
                                              std::vector<cl_uint> local_data,
                                              cl_uint size_x, cl_uint size_y)
{
    cl_int error = CL_SUCCESS;

    if (test_case.obj_t == image)
    {
        cl_image_format format;
        format.image_channel_order = CL_RGBA;
        format.image_channel_data_type = CL_UNSIGNED_INT32;
        cl_image_desc desc;
        memset(&desc, 0x0, sizeof(cl_image_desc));
        desc.image_type = CL_MEM_OBJECT_IMAGE2D;
        desc.image_width = size_x;
        desc.image_height = size_y;

        if (test_case.properties.size() == 0)
        {
            test_object =
                clCreateImageWithProperties(context, NULL, flags, &format,
                                            &desc, local_data.data(), &error);
        }
        else
        {
            test_object = clCreateImageWithProperties(
                context, test_case.properties.data(), flags, &format, &desc,
                local_data.data(), &error);
        }
        test_error(error, "clCreateImageWithProperties failed");
    }
    if (test_case.obj_t == buffer)
    {
        if (test_case.properties.size() == 0)
        {
            test_object = clCreateBufferWithProperties(
                context, NULL, flags, local_data.size() * sizeof(cl_uint),
                local_data.data(), &error);
        }
        else
        {
            test_object = clCreateBufferWithProperties(
                context, test_case.properties.data(), flags,
                local_data.size() * sizeof(cl_uint), local_data.data(), &error);
        }

        test_error(error, "clCreateBufferWithProperties failed.");
    }

    std::vector<cl_mem_properties> check_properties;
    size_t set_size = 0;

    error =
        clGetMemObjectInfo(test_object, CL_MEM_PROPERTIES, 0, NULL, &set_size);
    test_error(error,
               "clGetMemObjectInfo failed asking for CL_MEM_PROPERTIES size.");

    if (set_size == 0 && test_case.properties.size() == 0)
    {
        return TEST_PASS;
    }
    if (set_size != test_case.properties.size() * sizeof(cl_mem_properties))
    {
        log_error("ERROR: CL_MEM_PROPERTIES size is %d, expected %d.\n",
                  set_size,
                  test_case.properties.size() * sizeof(cl_queue_properties));
        return TEST_FAIL;
    }

    cl_uint number_of_props = set_size / sizeof(cl_mem_properties);
    check_properties.resize(number_of_props);
    error = clGetMemObjectInfo(test_object, CL_MEM_PROPERTIES, set_size,
                               check_properties.data(), NULL);
    test_error(error,
               "clGetMemObjectInfo failed asking for CL_MEM_PROPERTIES.");

    error = compareProperties(check_properties, test_case.properties);
    return error;
}

static int run_test_query_properties(cl_context context, cl_command_queue queue,
                                     test_data test_case)
{
    int error = CL_SUCCESS;
    log_info("\nTC description: %s\n", test_case.description.c_str());

    clProgramWrapper program;
    clKernelWrapper kernel;
    clMemWrapper obj_src;
    clMemWrapper obj_dst;
    clEventWrapper event;
    MTdata init_generator = init_genrand(gRandomSeed);
    cl_mem_flags flags;
    cl_uint size_x = 4;
    cl_uint size_y = 4;
    size_t size = size_x * size_y * 4;
    size_t global_dim[2] = { size_x, size_y };
    const size_t origin[3] = { 0, 0, 0 };
    const size_t region[3] = { size_x, size_y, 1 };

    std::vector<cl_uint> src_data(size);
    std::vector<cl_uint> dst_data(size);

    generate_random_data(kUInt, size, init_generator, src_data.data());
    generate_random_data(kUInt, size, init_generator, dst_data.data());
    free_mtdata(init_generator);
    init_generator = NULL;
    const char* kernel_src = test_case.src.c_str();
    error =
        create_single_kernel_helper(context, &program, &kernel, 1, &kernel_src,
                                    test_case.kernel_name.c_str());

    test_error(error, "create_single_kernel_helper failed");

    flags = (cl_mem_flags)(CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR);
    error = create_object_and_check_properties(context, obj_src, test_case,
                                               flags, src_data, size_x, size_y);
    test_error(error, "create_object_and_check_properties obj_src failed.");

    flags = (cl_mem_flags)(CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR);
    error = create_object_and_check_properties(context, obj_dst, test_case,
                                               flags, dst_data, size_x, size_y);
    test_error(error, "create_object_and_check_properties obj_dst failed.");

    error = clSetKernelArg(kernel, 0, sizeof(obj_src), &obj_src);
    test_error(error, "clSetKernelArg 0 failed.");

    error = clSetKernelArg(kernel, 1, sizeof(obj_dst), &obj_dst);
    test_error(error, "clSetKernelArg 1 failed.");
    if (test_case.obj_t == image)
    {
        error = clEnqueueNDRangeKernel(queue, kernel, 2, NULL, global_dim, NULL,
                                       0, NULL, &event);
        test_error(error, "clEnqueueNDRangeKernel failed.");

        error = clWaitForEvents(1, &event);
        test_error(error, "clWaitForEvents failed.");

        error = clEnqueueReadImage(queue, obj_dst, CL_TRUE, origin, region, 0,
                                   0, dst_data.data(), 0, NULL, NULL);
        test_error(error, "clEnqueueReadImage failed.");
    }
    if (test_case.obj_t == buffer)
    {
        error = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &size, NULL, 0,
                                       NULL, &event);
        test_error(error, "clEnqueueNDRangeKernel failed.");

        error = clWaitForEvents(1, &event);
        test_error(error, "clWaitForEvents failed.");

        error = clEnqueueReadBuffer(queue, obj_dst, CL_TRUE, 0,
                                    dst_data.size() * sizeof(cl_uint),
                                    dst_data.data(), 0, NULL, NULL);
        test_error(error, "clEnqueueReadBuffer failed.");
    }

    for (size_t i = 0; i < size; ++i)
    {
        if (dst_data[i] != src_data[i])
        {
            log_error("ERROR: Output results mismatch.");
            return TEST_FAIL;
        }
    }

    log_info("TC result: passed\n");
    return TEST_PASS;
}

int test_image_properties_queries(cl_device_id deviceID, cl_context context,
                                  cl_command_queue queue, int num_elements)
{
    int error = CL_SUCCESS;
    cl_bool supports_images = CL_TRUE;

    error = clGetDeviceInfo(deviceID, CL_DEVICE_IMAGE_SUPPORT,
                            sizeof(supports_images), &supports_images, NULL);
    test_error(error, "clGetDeviceInfo for CL_DEVICE_IMAGE_SUPPORT failed");

    if (supports_images == CL_FALSE)
    {
        log_info("No image support on current device - skipped\n");
        return TEST_SKIPPED_ITSELF;
    }

    std::vector<test_data> test_cases;
    std::string test_kernel = { "__kernel void data_copy(read_only image2d_t "
                                "src, write_only image2d_t dst)\n"
                                "{\n"
                                "    int tid_x = get_global_id(0);\n"
                                "    int tid_y = get_global_id(1);\n"
                                "    int2 coords = (int2)(tid_x, tid_y);\n"
                                "    uint4 val = read_imageui(src, coords);\n"
                                "    write_imageui(dst, coords, val);\n"
                                "\n"
                                "}\n" };
    test_cases.push_back(
        { image, { 0 }, "image, 0 properties", test_kernel, "data_copy" });
    test_cases.push_back(
        { image, {}, "image, NULL properties", test_kernel, "data_copy" });

    for (auto test_case : test_cases)
    {
        error |= run_test_query_properties(context, queue, test_case);
    }

    return error;
}

int test_buffer_properties_queries(cl_device_id deviceID, cl_context context,
                                   cl_command_queue queue, int num_elements)
{
    int error = CL_SUCCESS;
    std::vector<test_data> test_cases;
    std::string test_kernel = {
        "__kernel void data_copy(__global int *src, __global int *dst)\n"
        "{\n"
        "    int  tid = get_global_id(0);\n"
        "\n"
        "    dst[tid] = src[tid];\n"
        "\n"
        "}\n"
    };
    test_cases.push_back(
        { buffer, { 0 }, "buffer, 0 properties", test_kernel, "data_copy" });
    test_cases.push_back(
        { buffer, {}, "buffer, NULL properties", test_kernel, "data_copy" });

    for (auto test_case : test_cases)
    {
        error |= run_test_query_properties(context, queue, test_case);
    }

    return error;
}
<commit_msg>add a test case for subbuffer property queries (#961)<commit_after>//
// Copyright (c) 2020 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "testBase.h"
#include "harness/propertyHelpers.h"
#include "harness/typeWrappers.h"
#include <vector>
#include <algorithm>

typedef enum
{
    image,
    image_with_properties,
    buffer,
    buffer_with_properties,
    subbuffer,
} test_type;

struct test_data
{
    test_type type;
    std::vector<cl_mem_properties> properties;
    std::string description;
    cl_kernel kernel;
};

static int create_object_and_check_properties(cl_context context,
                                              clMemWrapper& test_object,
                                              test_data test_case,
                                              cl_mem_flags flags,
                                              std::vector<cl_uint> local_data,
                                              cl_uint size_x, cl_uint size_y)
{
    cl_int error = CL_SUCCESS;

    switch (test_case.type)
    {
        case image: {
            cl_image_format format = { 0 };
            format.image_channel_order = CL_RGBA;
            format.image_channel_data_type = CL_UNSIGNED_INT32;
            test_object = clCreateImage2D(context, flags, &format, size_x,
                                          size_y, 0, local_data.data(), &error);
            test_error(error, "clCreateImage2D failed");
        }
        break;
        case image_with_properties: {
            cl_image_format format = { 0 };
            format.image_channel_order = CL_RGBA;
            format.image_channel_data_type = CL_UNSIGNED_INT32;
            cl_image_desc desc = { 0 };
            desc.image_type = CL_MEM_OBJECT_IMAGE2D;
            desc.image_width = size_x;
            desc.image_height = size_y;

            if (test_case.properties.size() == 0)
            {
                test_object = clCreateImageWithProperties(
                    context, NULL, flags, &format, &desc, local_data.data(),
                    &error);
            }
            else
            {
                test_object = clCreateImageWithProperties(
                    context, test_case.properties.data(), flags, &format, &desc,
                    local_data.data(), &error);
            }
            test_error(error, "clCreateImageWithProperties failed");
        }
        break;
        case buffer: {
            test_object = clCreateBuffer(context, flags,
                                         local_data.size() * sizeof(cl_uint),
                                         local_data.data(), &error);
            test_error(error, "clCreateBuffer failed");
        }
        case buffer_with_properties: {
            if (test_case.properties.size() == 0)
            {
                test_object = clCreateBufferWithProperties(
                    context, NULL, flags, local_data.size() * sizeof(cl_uint),
                    local_data.data(), &error);
            }
            else
            {
                test_object = clCreateBufferWithProperties(
                    context, test_case.properties.data(), flags,
                    local_data.size() * sizeof(cl_uint), local_data.data(),
                    &error);
            }
            test_error(error, "clCreateBufferWithProperties failed.");
        }
        break;
        case subbuffer: {
            clMemWrapper parent_object;
            if (test_case.properties.size() == 0)
            {
                parent_object = clCreateBufferWithProperties(
                    context, NULL, flags, local_data.size() * sizeof(cl_uint),
                    local_data.data(), &error);
            }
            else
            {
                parent_object = clCreateBufferWithProperties(
                    context, test_case.properties.data(), flags,
                    local_data.size() * sizeof(cl_uint), local_data.data(),
                    &error);
            }
            test_error(error, "clCreateBufferWithProperties failed.");

            cl_mem_flags subbuffer_flags = flags
                & (CL_MEM_READ_WRITE | CL_MEM_READ_ONLY | CL_MEM_WRITE_ONLY);

            cl_buffer_region region = { 0 };
            region.origin = 0;
            region.size = local_data.size() * sizeof(cl_uint);
            test_object = clCreateSubBuffer(parent_object, subbuffer_flags,
                                            CL_BUFFER_CREATE_TYPE_REGION,
                                            &region, &error);
            test_error(error, "clCreateSubBuffer failed.");
        }
        break;
        default: log_error("Unknown test type!"); return TEST_FAIL;
    }

    std::vector<cl_mem_properties> check_properties;
    size_t set_size = 0;

    error =
        clGetMemObjectInfo(test_object, CL_MEM_PROPERTIES, 0, NULL, &set_size);
    test_error(error,
               "clGetMemObjectInfo failed asking for CL_MEM_PROPERTIES size.");

    // Buffers, subbuffers, and images must return no properties.
    if (test_case.type == buffer || test_case.type == subbuffer
        || test_case.type == image)
    {
        if (set_size == 0)
        {
            return TEST_PASS;
        }
        else
        {
            log_error("Queried properties must have size equal to zero for "
                      "buffers, subbuffers, and images.");
            return TEST_FAIL;
        }
    }

    if (set_size == 0 && test_case.properties.size() == 0)
    {
        return TEST_PASS;
    }
    if (set_size != test_case.properties.size() * sizeof(cl_mem_properties))
    {
        log_error("ERROR: CL_MEM_PROPERTIES size is %d, expected %d.\n",
                  set_size,
                  test_case.properties.size() * sizeof(cl_queue_properties));
        return TEST_FAIL;
    }

    cl_uint number_of_props = set_size / sizeof(cl_mem_properties);
    check_properties.resize(number_of_props);
    error = clGetMemObjectInfo(test_object, CL_MEM_PROPERTIES, set_size,
                               check_properties.data(), NULL);
    test_error(error,
               "clGetMemObjectInfo failed asking for CL_MEM_PROPERTIES.");

    error = compareProperties(check_properties, test_case.properties);
    return error;
}

static int run_test_query_properties(cl_context context, cl_command_queue queue,
                                     test_data test_case)
{
    int error = CL_SUCCESS;
    log_info("\nTC description: %s\n", test_case.description.c_str());

    clMemWrapper obj_src;
    clMemWrapper obj_dst;
    clEventWrapper event;
    MTdata init_generator = init_genrand(gRandomSeed);
    cl_mem_flags flags;
    cl_uint size_x = 4;
    cl_uint size_y = 4;
    size_t size = size_x * size_y * 4;
    size_t global_dim[2] = { size_x, size_y };
    const size_t origin[3] = { 0, 0, 0 };
    const size_t region[3] = { size_x, size_y, 1 };

    std::vector<cl_uint> src_data(size);
    std::vector<cl_uint> dst_data(size);

    generate_random_data(kUInt, size, init_generator, src_data.data());
    generate_random_data(kUInt, size, init_generator, dst_data.data());
    free_mtdata(init_generator);
    init_generator = NULL;

    flags = (cl_mem_flags)(CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR);
    error = create_object_and_check_properties(context, obj_src, test_case,
                                               flags, src_data, size_x, size_y);
    test_error(error, "create_object_and_check_properties obj_src failed.");

    flags = (cl_mem_flags)(CL_MEM_WRITE_ONLY | CL_MEM_COPY_HOST_PTR);
    error = create_object_and_check_properties(context, obj_dst, test_case,
                                               flags, dst_data, size_x, size_y);
    test_error(error, "create_object_and_check_properties obj_dst failed.");

    error = clSetKernelArg(test_case.kernel, 0, sizeof(obj_src), &obj_src);
    test_error(error, "clSetKernelArg 0 failed.");

    error = clSetKernelArg(test_case.kernel, 1, sizeof(obj_dst), &obj_dst);
    test_error(error, "clSetKernelArg 1 failed.");
    switch (test_case.type)
    {
        case image:
        case image_with_properties: {
            error = clEnqueueNDRangeKernel(queue, test_case.kernel, 2, NULL,
                                           global_dim, NULL, 0, NULL, &event);
            test_error(error, "clEnqueueNDRangeKernel failed.");

            error = clWaitForEvents(1, &event);
            test_error(error, "clWaitForEvents failed.");

            error = clEnqueueReadImage(queue, obj_dst, CL_TRUE, origin, region,
                                       0, 0, dst_data.data(), 0, NULL, NULL);
            test_error(error, "clEnqueueReadImage failed.");
        }
        break;
        case buffer:
        case buffer_with_properties:
        case subbuffer: {
            error = clEnqueueNDRangeKernel(queue, test_case.kernel, 1, NULL,
                                           &size, NULL, 0, NULL, &event);
            test_error(error, "clEnqueueNDRangeKernel failed.");

            error = clWaitForEvents(1, &event);
            test_error(error, "clWaitForEvents failed.");

            error = clEnqueueReadBuffer(queue, obj_dst, CL_TRUE, 0,
                                        dst_data.size() * sizeof(cl_uint),
                                        dst_data.data(), 0, NULL, NULL);
            test_error(error, "clEnqueueReadBuffer failed.");
        }
        break;
        default: log_error("Unknown test type!"); return TEST_FAIL;
    }

    for (size_t i = 0; i < size; ++i)
    {
        if (dst_data[i] != src_data[i])
        {
            log_error("ERROR: Output results mismatch.");
            return TEST_FAIL;
        }
    }

    log_info("TC result: passed\n");
    return TEST_PASS;
}

int test_image_properties_queries(cl_device_id deviceID, cl_context context,
                                  cl_command_queue queue, int num_elements)
{
    int error = CL_SUCCESS;
    cl_bool supports_images = CL_TRUE;

    error = clGetDeviceInfo(deviceID, CL_DEVICE_IMAGE_SUPPORT,
                            sizeof(supports_images), &supports_images, NULL);
    test_error(error, "clGetDeviceInfo for CL_DEVICE_IMAGE_SUPPORT failed");

    if (supports_images == CL_FALSE)
    {
        log_info("No image support on current device - skipped\n");
        return TEST_SKIPPED_ITSELF;
    }

    clProgramWrapper program;
    clKernelWrapper kernel;

    const char* kernel_src = R"CLC(
        __kernel void data_copy(read_only image2d_t src, write_only image2d_t dst)
        {
            int tid_x = get_global_id(0);
            int tid_y = get_global_id(1);
            int2 coords = (int2)(tid_x, tid_y);
            uint4 val = read_imageui(src, coords);
            write_imageui(dst, coords, val);

        }
        )CLC";

    error = create_single_kernel_helper(context, &program, &kernel, 1,
                                        &kernel_src, "data_copy");
    test_error(error, "create_single_kernel_helper failed");

    std::vector<test_data> test_cases;
    test_cases.push_back({ image, {}, "regular image", kernel });
    test_cases.push_back(
        { image_with_properties, { 0 }, "image, 0 properties", kernel });
    test_cases.push_back(
        { image_with_properties, {}, "image, NULL properties", kernel });

    for (auto test_case : test_cases)
    {
        error |= run_test_query_properties(context, queue, test_case);
    }

    return error;
}

int test_buffer_properties_queries(cl_device_id deviceID, cl_context context,
                                   cl_command_queue queue, int num_elements)
{
    int error = CL_SUCCESS;

    clProgramWrapper program;
    clKernelWrapper kernel;

    const char* kernel_src = R"CLC(
        __kernel void data_copy(__global int *src, __global int *dst)
        {
            int  tid = get_global_id(0);

            dst[tid] = src[tid];

        }
        )CLC";
    error = create_single_kernel_helper(context, &program, &kernel, 1,
                                        &kernel_src, "data_copy");
    test_error(error, "create_single_kernel_helper failed");

    std::vector<test_data> test_cases;
    test_cases.push_back({ buffer, {}, "regular buffer", kernel });
    test_cases.push_back(
        { buffer_with_properties, { 0 }, "buffer with 0 properties", kernel });
    test_cases.push_back(
        { buffer_with_properties, {}, "buffer with NULL properties", kernel });
    test_cases.push_back(
        { subbuffer, { 0 }, "subbuffer with 0 properties", kernel });
    test_cases.push_back(
        { subbuffer, {}, "subbuffer with NULL properties", kernel });

    for (auto test_case : test_cases)
    {
        error |= run_test_query_properties(context, queue, test_case);
    }

    return error;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2021, The Bifrost Authors. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of The Bifrost Authors nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <bifrost/config.h>
#include <bifrost/proclog.h>
#include "trace.hpp"
#include "proclog.hpp"

#include <fstream>
#include <cstdlib>     // For system
#include <cstdarg>     // For va_start, va_list, va_end
#include <sys/file.h>  // For flock
#include <sys/stat.h>  // For fstat
#include <sys/types.h> // For getpid
#include <dirent.h>    // For opendir, readdir, closedir
#include <unistd.h>    // For getpid
#include <system_error>
#include <set>
#include <mutex>

void make_dir(std::string path, int perms=775) {
	if( std::system(("mkdir -p "+path+" -m "+std::to_string(perms)).c_str()) ) {
		throw std::runtime_error("Failed to create path: "+path);
	}
}
void remove_all(std::string path) {
	if( std::system(("rm -rf "+path).c_str()) ) {
		throw std::runtime_error("Failed to remove all: "+path);
	}
}
void remove_dir(std::string path) {
	if( std::system(("rmdir "+path+" 2> /dev/null").c_str()) ) {
		throw std::runtime_error("Failed to remove dir: "+path);
	}
}
void remove_file(std::string path) {
	if( std::system(("rm -f "+path).c_str()) ) {
		throw std::runtime_error("Failed to remove file: "+path);
	}
}
bool process_exists(pid_t pid) {
	struct stat s;
	return !(stat(("/proc/"+std::to_string(pid)).c_str(), &s) == -1
	         && errno == ENOENT);
}

std::string get_dirname(std::string filename) {
	// TODO: This is crude, but works for our proclog use-case
	return filename.substr(0, filename.find_last_of("/"));
}

class LockFile {
	std::string _lockfile;
	int         _fd;
public:
	LockFile(LockFile const& ) = delete;
	LockFile& operator=(LockFile const& ) = delete;
	LockFile(std::string lockfile) : _lockfile(lockfile) {
		while( true ) {
			_fd = open(_lockfile.c_str(), O_CREAT, 600);
			flock(_fd, LOCK_EX);
			struct stat fd_stat, lockfile_stat;
			fstat(_fd, &fd_stat);
			stat(_lockfile.c_str(), &lockfile_stat);
			// Compare inodes
			if( fd_stat.st_ino == lockfile_stat.st_ino ) {
				// Got the lock
				break;
			}
			close(_fd);
		}
	}
	~LockFile() {
		unlink(_lockfile.c_str());
		flock(_fd, LOCK_UN);
	}
};

class ProcLogMgr {
	static constexpr const char* base_logdir = BF_PROCLOG_DIR;
	std::string            _logdir;
	std::set<std::string>  _logs;
	std::set<std::string>  _created_dirs;
	mutable std::mutex     _mutex;
	void try_base_logdir_cleanup() {
		// Do this with a file lock to avoid interference from other processes
		LockFile lock(std::string(base_logdir) + ".lock");
		DIR* dp;
		// Remove pid dirs for which a corresponding process does not exist
		if( (dp = opendir(base_logdir)) ) {
			struct dirent* ep;
			while( (ep = readdir(dp)) ) {
				pid_t pid = atoi(ep->d_name);
				if( pid && !process_exists(pid) ) {
					try {
						remove_all(std::string(base_logdir) + "/" +
							   std::to_string(pid));
					} catch( std::exception& ) {}
				}
			}
			closedir(dp);
		}
		// Remove the base_logdir if it's empty
		try { remove_dir(base_logdir); }
		catch( std::exception& ) {}
	}
	ProcLogMgr()
		: _logdir(std::string(base_logdir) + "/" + std::to_string(getpid())) {
		this->try_base_logdir_cleanup();
		make_dir(base_logdir, 777);
		make_dir(_logdir);
	}
	~ProcLogMgr() {
		try {
			remove_all(_logdir);
			this->try_base_logdir_cleanup();
		} catch( std::exception& ) {}
	}
	FILE* open_file(std::string filename) {
		// Note: Individual log dirs and files are only created if they are
		//         actually updated with data.
		// Note: name may contain subdirs, so we must ensure they exist first
		this->ensure_dir_exists(filename);
		FILE* logfile = (FILE*)fopen(filename.c_str(), "w");
		if( !logfile ) {
			throw std::runtime_error("fopen(\""+filename+"\", \"w\") failed");
		}
		return logfile;
	}
public:
	ProcLogMgr(ProcLogMgr& ) = delete;
	ProcLogMgr& operator=(ProcLogMgr& ) = delete;
	static ProcLogMgr& get() {
		static ProcLogMgr proclog;
		return proclog;
	}
	void ensure_dir_exists(std::string filename) {
		std::string dirname = get_dirname(filename);
		if( !_created_dirs.count(dirname) ) {
			// Note: make_dir is really slow, so we ensure we call it only once
			make_dir(dirname);
			_created_dirs.insert(dirname);
		}
	}
	std::string create_log(std::string name) {
		std::lock_guard<std::mutex> lock(_mutex);
		std::string origname = name;
		std::string modname = name.substr(0, name.find("/"));
		std::string logname = name.substr(name.find("/"), name.length());
		std::string filename = _logdir + "/" + name;

		int i = 1;
		while( _logs.count(filename) ) {
			// Disambiguate by adding suffix to name
			name = modname + "_" + std::to_string(++i);
			if( logname.length() > 0 ) {
				name = name + "/" + logname;
			}
			filename = _logdir + "/" + name;
		}
		_logs.insert(filename);
		return filename;
	}
	void destroy_log(std::string filename) {
		std::lock_guard<std::mutex> lock(_mutex);
		remove_file(filename);
		_logs.erase(filename);
	}
	void update_log_s(std::string filename, const char* str) {
		std::lock_guard<std::mutex> lock(_mutex);
		FILE* logfile = this->open_file(filename);
		fputs(str, logfile);
		fclose(logfile);
	}
	void update_log_v(std::string filename, const char* fmt, va_list args) {
		std::lock_guard<std::mutex> lock(_mutex);
		FILE* logfile = this->open_file(filename);
		vfprintf(logfile, fmt, args);
		fclose(logfile);
	}
};

BFproclog_impl::BFproclog_impl(std::string name)
	: _filename(ProcLogMgr::get().create_log(name)) {}
BFproclog_impl::~BFproclog_impl() {
	ProcLogMgr::get().destroy_log(_filename);
}
void BFproclog_impl::update_s(const char* str) {
	ProcLogMgr::get().update_log_s(_filename, str);
}
void BFproclog_impl::update_v(const char* fmt, va_list args) {
	ProcLogMgr::get().update_log_v(_filename, fmt, args);
}
void BFproclog_impl::update(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);
	this->update_v(fmt, args);
	va_end(args);
}
movable_ofstream_WAR BFproclog_impl::update() {
	ProcLogMgr::get().ensure_dir_exists(_filename);
	// TODO: gcc < 5 has a bug where std streams are not movable
	//return std::ofstream(_filename);
	return movable_ofstream_WAR(_filename);
}

BFstatus bfProcLogCreate(BFproclog* log_ptr, const char* name) {
	BF_ASSERT(log_ptr, BF_STATUS_INVALID_POINTER);
	BF_ASSERT(name,    BF_STATUS_INVALID_POINTER);
	BF_TRY_RETURN_ELSE(*log_ptr = new BFproclog_impl(name),
	                   *log_ptr = 0);
}
BFstatus bfProcLogDestroy(BFproclog log) {
	BF_ASSERT(log, BF_STATUS_INVALID_HANDLE);
	delete log;
	return BF_STATUS_SUCCESS;
}
BFstatus bfProcLogUpdate(BFproclog log, const char* str) {
	BF_ASSERT(log, BF_STATUS_INVALID_HANDLE);
	BF_ASSERT(str, BF_STATUS_INVALID_POINTER);
	BF_TRY_RETURN(log->update_s(str));
}
<commit_msg>OSX doesn't have a procfs to look at for active processes.<commit_after>/*
 * Copyright (c) 2016-2021, The Bifrost Authors. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of The Bifrost Authors nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <bifrost/config.h>
#include <bifrost/proclog.h>
#include "trace.hpp"
#include "proclog.hpp"

#include <fstream>
#include <cstdlib>     // For system
#include <cstdarg>     // For va_start, va_list, va_end
#include <sys/file.h>  // For flock
#include <sys/stat.h>  // For fstat
#include <sys/types.h> // For getpid
#include <dirent.h>    // For opendir, readdir, closedir
#include <unistd.h>    // For getpid
#include <system_error>
#include <set>
#include <mutex>

#if defined __APPLE__ && __APPLE__
#include <sys/sysctl.h>
#endif

void make_dir(std::string path, int perms=775) {
	if( std::system(("mkdir -p "+path+" -m "+std::to_string(perms)).c_str()) ) {
		throw std::runtime_error("Failed to create path: "+path);
	}
}
void remove_all(std::string path) {
	if( std::system(("rm -rf "+path).c_str()) ) {
		throw std::runtime_error("Failed to remove all: "+path);
	}
}
void remove_dir(std::string path) {
	if( std::system(("rmdir "+path+" 2> /dev/null").c_str()) ) {
		throw std::runtime_error("Failed to remove dir: "+path);
	}
}
void remove_file(std::string path) {
	if( std::system(("rm -f "+path).c_str()) ) {
		throw std::runtime_error("Failed to remove file: "+path);
	}
}
bool process_exists(pid_t pid) {
#if defined __APPLE__ && __APPLE__

  // Based on information from:
	//   https://developer.apple.com/library/archive/qa/qa2001/qa1123.html

  static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
	kinfo_proc *proclist = NULL;
	int err, found = 0;
	size_t len, count;
	len = 0;
	err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
               NULL, &len, NULL, 0);
	if( err == 0 ) {
		proclist = (kinfo_proc*) ::malloc(len);
		err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
                 proclist, &len, NULL, 0);
		if( err == 0 ) {
			count = len / sizeof(kinfo_proc);
			for(int i=0; i<count; i++) {
				pid_t c_pid = proclist[i].kp_proc.p_pid;
				if( c_pid == pid ) {
					found = 1;
					break;
				}
			}
		}
		::free(proclist);
	}
	return (bool) found;
#else
	struct stat s;
	return !(stat(("/proc/"+std::to_string(pid)).c_str(), &s) == -1
	         && errno == ENOENT);
#endif
}

std::string get_dirname(std::string filename) {
	// TODO: This is crude, but works for our proclog use-case
	return filename.substr(0, filename.find_last_of("/"));
}

class LockFile {
	std::string _lockfile;
	int         _fd;
public:
	LockFile(LockFile const& ) = delete;
	LockFile& operator=(LockFile const& ) = delete;
	LockFile(std::string lockfile) : _lockfile(lockfile) {
		while( true ) {
			_fd = open(_lockfile.c_str(), O_CREAT, 600);
			flock(_fd, LOCK_EX);
			struct stat fd_stat, lockfile_stat;
			fstat(_fd, &fd_stat);
			stat(_lockfile.c_str(), &lockfile_stat);
			// Compare inodes
			if( fd_stat.st_ino == lockfile_stat.st_ino ) {
				// Got the lock
				break;
			}
			close(_fd);
		}
	}
	~LockFile() {
		unlink(_lockfile.c_str());
		flock(_fd, LOCK_UN);
	}
};

class ProcLogMgr {
	static constexpr const char* base_logdir = BF_PROCLOG_DIR;
	std::string            _logdir;
	std::set<std::string>  _logs;
	std::set<std::string>  _created_dirs;
	mutable std::mutex     _mutex;
	void try_base_logdir_cleanup() {
		// Do this with a file lock to avoid interference from other processes
		LockFile lock(std::string(base_logdir) + ".lock");
		DIR* dp;
		// Remove pid dirs for which a corresponding process does not exist
		if( (dp = opendir(base_logdir)) ) {
			struct dirent* ep;
			while( (ep = readdir(dp)) ) {
				pid_t pid = atoi(ep->d_name);
				if( pid && !process_exists(pid) ) {
					try {
						remove_all(std::string(base_logdir) + "/" +
							         std::to_string(pid));
					} catch( std::exception& ) {}
				}
			}
			closedir(dp);
		}
		// Remove the base_logdir if it's empty
		try { remove_dir(base_logdir); }
		catch( std::exception& ) {}
	}
	ProcLogMgr()
		: _logdir(std::string(base_logdir) + "/" + std::to_string(getpid())) {
		this->try_base_logdir_cleanup();
		make_dir(base_logdir, 777);
		make_dir(_logdir);
	}
	~ProcLogMgr() {
		try {
			remove_all(_logdir);
			this->try_base_logdir_cleanup();
		} catch( std::exception& ) {}
	}
	FILE* open_file(std::string filename) {
		// Note: Individual log dirs and files are only created if they are
		//         actually updated with data.
		// Note: name may contain subdirs, so we must ensure they exist first
		this->ensure_dir_exists(filename);
		FILE* logfile = (FILE*)fopen(filename.c_str(), "w");
		if( !logfile ) {
			throw std::runtime_error("fopen(\""+filename+"\", \"w\") failed");
		}
		return logfile;
	}
public:
	ProcLogMgr(ProcLogMgr& ) = delete;
	ProcLogMgr& operator=(ProcLogMgr& ) = delete;
	static ProcLogMgr& get() {
		static ProcLogMgr proclog;
		return proclog;
	}
	void ensure_dir_exists(std::string filename) {
		std::string dirname = get_dirname(filename);
		if( !_created_dirs.count(dirname) ) {
			// Note: make_dir is really slow, so we ensure we call it only once
			make_dir(dirname);
			_created_dirs.insert(dirname);
		}
	}
	std::string create_log(std::string name) {
		std::lock_guard<std::mutex> lock(_mutex);
		std::string origname = name;
		std::string modname = name.substr(0, name.find("/"));
		std::string logname = name.substr(name.find("/"), name.length());
		std::string filename = _logdir + "/" + name;

		int i = 1;
		while( _logs.count(filename) ) {
			// Disambiguate by adding suffix to name
			name = modname + "_" + std::to_string(++i);
			if( logname.length() > 0 ) {
				name = name + "/" + logname;
			}
			filename = _logdir + "/" + name;
		}
		_logs.insert(filename);
		return filename;
	}
	void destroy_log(std::string filename) {
		std::lock_guard<std::mutex> lock(_mutex);
		remove_file(filename);
		_logs.erase(filename);
	}
	void update_log_s(std::string filename, const char* str) {
		std::lock_guard<std::mutex> lock(_mutex);
		FILE* logfile = this->open_file(filename);
		fputs(str, logfile);
		fclose(logfile);
	}
	void update_log_v(std::string filename, const char* fmt, va_list args) {
		std::lock_guard<std::mutex> lock(_mutex);
		FILE* logfile = this->open_file(filename);
		vfprintf(logfile, fmt, args);
		fclose(logfile);
	}
};

BFproclog_impl::BFproclog_impl(std::string name)
	: _filename(ProcLogMgr::get().create_log(name)) {}
BFproclog_impl::~BFproclog_impl() {
	ProcLogMgr::get().destroy_log(_filename);
}
void BFproclog_impl::update_s(const char* str) {
	ProcLogMgr::get().update_log_s(_filename, str);
}
void BFproclog_impl::update_v(const char* fmt, va_list args) {
	ProcLogMgr::get().update_log_v(_filename, fmt, args);
}
void BFproclog_impl::update(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);
	this->update_v(fmt, args);
	va_end(args);
}
movable_ofstream_WAR BFproclog_impl::update() {
	ProcLogMgr::get().ensure_dir_exists(_filename);
	// TODO: gcc < 5 has a bug where std streams are not movable
	//return std::ofstream(_filename);
	return movable_ofstream_WAR(_filename);
}

BFstatus bfProcLogCreate(BFproclog* log_ptr, const char* name) {
	BF_ASSERT(log_ptr, BF_STATUS_INVALID_POINTER);
	BF_ASSERT(name,    BF_STATUS_INVALID_POINTER);
	BF_TRY_RETURN_ELSE(*log_ptr = new BFproclog_impl(name),
	                   *log_ptr = 0);
}
BFstatus bfProcLogDestroy(BFproclog log) {
	BF_ASSERT(log, BF_STATUS_INVALID_HANDLE);
	delete log;
	return BF_STATUS_SUCCESS;
}
BFstatus bfProcLogUpdate(BFproclog log, const char* str) {
	BF_ASSERT(log, BF_STATUS_INVALID_HANDLE);
	BF_ASSERT(str, BF_STATUS_INVALID_POINTER);
	BF_TRY_RETURN(log->update_s(str));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: store.inl,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:40:01 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#define _STORE_STORE_INL_ "$Revision: 1.3 $"

/*========================================================================
 *
 * OStoreStream implementation.
 *
 *======================================================================*/
inline OStoreStream::OStoreStream (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreStream::~OStoreStream (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreStream::OStoreStream (
    const OStoreStream& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreStream& OStoreStream::operator= (
    const OStoreStream& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreStream::OStoreStream (
    storeStreamHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreStream::operator storeStreamHandle (void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreStream::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreStream::create (
    storeFileHandle      hFile,
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    storeAccessMode      eMode) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openStream (
        hFile, rPath.pData, rName.pData, eMode, &m_hImpl);
}

inline void OStoreStream::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeStream (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreStream::readAt (
    sal_uInt32  nOffset,
    void       *pBuffer,
    sal_uInt32  nBytes,
    sal_uInt32 &rnDone) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_readStream (
        m_hImpl, nOffset, pBuffer, nBytes, &rnDone);
}

inline storeError OStoreStream::writeAt (
    sal_uInt32  nOffset,
    const void *pBuffer,
    sal_uInt32  nBytes,
    sal_uInt32 &rnDone) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_writeStream (
        m_hImpl, nOffset, pBuffer, nBytes, &rnDone);
}

inline storeError OStoreStream::flush (void) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_flushStream (m_hImpl);
}

inline storeError OStoreStream::getSize (
    sal_uInt32 &rnSize) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getStreamSize (m_hImpl, &rnSize);
}

inline storeError OStoreStream::setSize (
    sal_uInt32 nSize) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_setStreamSize (m_hImpl, nSize);
}

/*========================================================================
 *
 * OStoreDirectory implementation.
 *
 *======================================================================*/
inline OStoreDirectory::OStoreDirectory (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreDirectory::~OStoreDirectory (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreDirectory::OStoreDirectory (
    const OStoreDirectory& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreDirectory& OStoreDirectory::operator= (
    const OStoreDirectory& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreDirectory::OStoreDirectory (
    storeDirectoryHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreDirectory::operator storeDirectoryHandle(void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreDirectory::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreDirectory::create (
    storeFileHandle      hFile,
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    storeAccessMode      eMode) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openDirectory (
        hFile, rPath.pData, rName.pData, eMode, &m_hImpl);
}

inline void OStoreDirectory::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeDirectory (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreDirectory::first (iterator& it) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_findFirst (m_hImpl, &it);
}

inline storeError OStoreDirectory::next (iterator& it) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_findNext (m_hImpl, &it);
}

inline storeError OStoreDirectory::travel (traveller& rTraveller) const
{
    storeError eErrCode = store_E_InvalidHandle;
    if (m_hImpl)
    {
        iterator it;
        eErrCode = store_findFirst (m_hImpl, &it);
        while ((eErrCode == store_E_None) && rTraveller.visit(it))
            eErrCode = store_findNext (m_hImpl, &it);
    }
    return eErrCode;
}

/*========================================================================
 *
 * OStoreFile implementation.
 *
 *======================================================================*/
inline OStoreFile::OStoreFile (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreFile::~OStoreFile (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreFile::OStoreFile (
    const OStoreFile& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreFile& OStoreFile::operator= (
    const OStoreFile& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreFile::OStoreFile (
    storeFileHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreFile::operator storeFileHandle (void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreFile::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreFile::create (
    const rtl::OUString &rFilename,
    storeAccessMode      eAccessMode,
    sal_uInt16           nPageSize) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openFile (rFilename.pData, eAccessMode, nPageSize, &m_hImpl);
}

inline storeError OStoreFile::createInMemory (
    sal_uInt16 nPageSize) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_createMemoryFile (nPageSize, &m_hImpl);
}

inline void OStoreFile::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeFile (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreFile::flush (void) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_flushFile (m_hImpl);
}

inline storeError OStoreFile::getRefererCount (
    sal_uInt32 &rnRefCount) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getFileRefererCount (m_hImpl, &rnRefCount);
}

inline storeError OStoreFile::getSize (
    sal_uInt32 &rnSize) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getFileSize (m_hImpl, &rnSize);
}

inline storeError OStoreFile::attrib (
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    sal_uInt32           nMask1,
    sal_uInt32           nMask2,
    sal_uInt32          &rnAttrib) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_attrib (
        m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, &rnAttrib);
}

inline storeError OStoreFile::attrib (
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    sal_uInt32           nMask1,
    sal_uInt32           nMask2) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_attrib (
        m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, NULL);
}

inline storeError OStoreFile::link (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_link (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::symlink (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_symlink (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::rename (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_rename (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::remove (
    const rtl::OUString &rPath, const rtl::OUString &rName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_remove (m_hImpl, rPath.pData, rName.pData);
}

<commit_msg>INTEGRATION: CWS changefileheader (1.3.66); FILE MERGED 2008/03/31 15:27:46 rt 1.3.66.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: store.inl,v $
 * $Revision: 1.4 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#define _STORE_STORE_INL_ "$Revision: 1.4 $"

/*========================================================================
 *
 * OStoreStream implementation.
 *
 *======================================================================*/
inline OStoreStream::OStoreStream (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreStream::~OStoreStream (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreStream::OStoreStream (
    const OStoreStream& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreStream& OStoreStream::operator= (
    const OStoreStream& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreStream::OStoreStream (
    storeStreamHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreStream::operator storeStreamHandle (void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreStream::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreStream::create (
    storeFileHandle      hFile,
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    storeAccessMode      eMode) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openStream (
        hFile, rPath.pData, rName.pData, eMode, &m_hImpl);
}

inline void OStoreStream::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeStream (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreStream::readAt (
    sal_uInt32  nOffset,
    void       *pBuffer,
    sal_uInt32  nBytes,
    sal_uInt32 &rnDone) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_readStream (
        m_hImpl, nOffset, pBuffer, nBytes, &rnDone);
}

inline storeError OStoreStream::writeAt (
    sal_uInt32  nOffset,
    const void *pBuffer,
    sal_uInt32  nBytes,
    sal_uInt32 &rnDone) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_writeStream (
        m_hImpl, nOffset, pBuffer, nBytes, &rnDone);
}

inline storeError OStoreStream::flush (void) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_flushStream (m_hImpl);
}

inline storeError OStoreStream::getSize (
    sal_uInt32 &rnSize) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getStreamSize (m_hImpl, &rnSize);
}

inline storeError OStoreStream::setSize (
    sal_uInt32 nSize) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_setStreamSize (m_hImpl, nSize);
}

/*========================================================================
 *
 * OStoreDirectory implementation.
 *
 *======================================================================*/
inline OStoreDirectory::OStoreDirectory (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreDirectory::~OStoreDirectory (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreDirectory::OStoreDirectory (
    const OStoreDirectory& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreDirectory& OStoreDirectory::operator= (
    const OStoreDirectory& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreDirectory::OStoreDirectory (
    storeDirectoryHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreDirectory::operator storeDirectoryHandle(void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreDirectory::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreDirectory::create (
    storeFileHandle      hFile,
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    storeAccessMode      eMode) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openDirectory (
        hFile, rPath.pData, rName.pData, eMode, &m_hImpl);
}

inline void OStoreDirectory::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeDirectory (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreDirectory::first (iterator& it) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_findFirst (m_hImpl, &it);
}

inline storeError OStoreDirectory::next (iterator& it) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_findNext (m_hImpl, &it);
}

inline storeError OStoreDirectory::travel (traveller& rTraveller) const
{
    storeError eErrCode = store_E_InvalidHandle;
    if (m_hImpl)
    {
        iterator it;
        eErrCode = store_findFirst (m_hImpl, &it);
        while ((eErrCode == store_E_None) && rTraveller.visit(it))
            eErrCode = store_findNext (m_hImpl, &it);
    }
    return eErrCode;
}

/*========================================================================
 *
 * OStoreFile implementation.
 *
 *======================================================================*/
inline OStoreFile::OStoreFile (void) SAL_THROW(())
    : m_hImpl (0)
{
}

inline OStoreFile::~OStoreFile (void) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
}

inline OStoreFile::OStoreFile (
    const OStoreFile& rOther) SAL_THROW(())
    : m_hImpl (rOther.m_hImpl)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreFile& OStoreFile::operator= (
    const OStoreFile& rOther) SAL_THROW(())
{
    if (m_hImpl)
        store_releaseHandle (m_hImpl);
    m_hImpl = rOther.m_hImpl;
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
    return *this;
}

inline OStoreFile::OStoreFile (
    storeFileHandle Handle) SAL_THROW(())
    : m_hImpl (Handle)
{
    if (m_hImpl)
        store_acquireHandle (m_hImpl);
}

inline OStoreFile::operator storeFileHandle (void) const SAL_THROW(())
{
    return m_hImpl;
}

inline sal_Bool OStoreFile::isValid (void) const SAL_THROW(())
{
    return (!!m_hImpl);
}

inline storeError OStoreFile::create (
    const rtl::OUString &rFilename,
    storeAccessMode      eAccessMode,
    sal_uInt16           nPageSize) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_openFile (rFilename.pData, eAccessMode, nPageSize, &m_hImpl);
}

inline storeError OStoreFile::createInMemory (
    sal_uInt16 nPageSize) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_releaseHandle (m_hImpl);
        m_hImpl = 0;
    }
    return store_createMemoryFile (nPageSize, &m_hImpl);
}

inline void OStoreFile::close (void) SAL_THROW(())
{
    if (m_hImpl)
    {
        store_closeFile (m_hImpl);
        m_hImpl = 0;
    }
}

inline storeError OStoreFile::flush (void) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_flushFile (m_hImpl);
}

inline storeError OStoreFile::getRefererCount (
    sal_uInt32 &rnRefCount) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getFileRefererCount (m_hImpl, &rnRefCount);
}

inline storeError OStoreFile::getSize (
    sal_uInt32 &rnSize) const SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_getFileSize (m_hImpl, &rnSize);
}

inline storeError OStoreFile::attrib (
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    sal_uInt32           nMask1,
    sal_uInt32           nMask2,
    sal_uInt32          &rnAttrib) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_attrib (
        m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, &rnAttrib);
}

inline storeError OStoreFile::attrib (
    const rtl::OUString &rPath,
    const rtl::OUString &rName,
    sal_uInt32           nMask1,
    sal_uInt32           nMask2) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_attrib (
        m_hImpl, rPath.pData, rName.pData, nMask1, nMask2, NULL);
}

inline storeError OStoreFile::link (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_link (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::symlink (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_symlink (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::rename (
    const rtl::OUString &rSrcPath, const rtl::OUString &rSrcName,
    const rtl::OUString &rDstPath, const rtl::OUString &rDstName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_rename (
        m_hImpl,
        rSrcPath.pData, rSrcName.pData,
        rDstPath.pData, rDstName.pData);
}

inline storeError OStoreFile::remove (
    const rtl::OUString &rPath, const rtl::OUString &rName) SAL_THROW(())
{
    if (!m_hImpl)
        return store_E_InvalidHandle;

    return store_remove (m_hImpl, rPath.pData, rName.pData);
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "../../src/systemcmds/tests/tests.h"
#include <drivers/drv_hrt.h>
#include <rc/sbus.h>
#include <systemlib/err.h>
#include <systemlib/mixer/mixer.h>

#include "gtest/gtest.h"

TEST(SBUS2Test, SBUS2)
{
	const char *filepath = "testdata/sbus2_r7008SB.txt";

	FILE *fp;
	fp = fopen(filepath, "rt");

	ASSERT_TRUE(fp);
	warnx("loading data from: %s", filepath);

	// if (argc < 2)
	// 	errx(1, "Need a filename for the input file");

	int byte_offset = 7;

	// if (argc > 2) {
	// 	char* end;
	// 	byte_offset = strtol(argv[2],&end,10);
	// }

	warnx("RUNNING TEST WITH BYTE OFFSET OF: %d", byte_offset);

	float f;
	unsigned x;
	int ret;

	// Trash the first 20 lines
	for (unsigned i = 0; i < 20; i++) {
		char buf[200];
		(void)fgets(buf, sizeof(buf), fp);
	}

	// Init the parser
	uint8_t frame[SBUS_BUFFER_SIZE];
	unsigned partial_frame_count = 0;
	uint16_t rc_values[18];
	uint16_t num_values;
	unsigned sbus_frame_drops = 0;
	unsigned sbus_frame_resets = 0;
	bool sbus_failsafe;
	bool sbus_frame_drop;
	uint16_t max_channels = sizeof(rc_values) / sizeof(rc_values[0]);

	float last_time = 0;

	int rate_limiter = 0;

	while (EOF != (ret = fscanf(fp, "%f,%x,,", &f, &x))) {

		ASSERT_GT(ret, 0);

		unsigned last_drop = sbus_frame_drops + sbus_frame_resets;

		unsigned interval_us = ((f - last_time) * 1000 * 1000);

		if (interval_us > SBUS_INTER_FRAME_TIMEOUT) {
			if (partial_frame_count != 0) {
				warnx("[ %08.4fs ] INTERVAL: %f - FRAME RESET, DROPPED %d bytes",
					interval_us / 1e6, f, partial_frame_count);

				printf("\t\tdropped: ");
				for (int i = 0; i < partial_frame_count; i++) {
					printf("%02X ", frame[i]);
				}
				printf("\n");

				sbus_frame_resets++;
			}

			partial_frame_count = 0;
		}

		last_time = f;

		frame[partial_frame_count] = x;
		partial_frame_count++;

		//warnx("%f: 0x%02x, first: 0x%02x, last: 0x%02x, pcount: %u", (double)f, x, frame[0], frame[24], partial_frame_count);

		if (partial_frame_count == sizeof(frame)) {
			partial_frame_count = 0;
			warnx("FRAME SIZE OVERFLOW!\n\n\n");
		}

		// Pipe the data into the parser
		hrt_abstime now = hrt_absolute_time();

		if (rate_limiter % byte_offset == 0) {
			bool result = sbus_parse(now, frame, &partial_frame_count, rc_values, &num_values,
				&sbus_failsafe, &sbus_frame_drop, &sbus_frame_drops, max_channels);

			if (result)
				warnx("decoded packet");
		}

		if (last_drop != (sbus_frame_drops + sbus_frame_resets))
			warnx("frame dropped, now #%d", (sbus_frame_drops + sbus_frame_resets));

		rate_limiter++;
	}

	ASSERT_EQ(ret, EOF);
}
<commit_msg>Update S.BUS2 test<commit_after>#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "../../src/systemcmds/tests/tests.h"
#include <drivers/drv_hrt.h>
#include <rc/sbus.h>
#include <systemlib/err.h>
#include <systemlib/mixer/mixer.h>

#include "gtest/gtest.h"

TEST(SBUS2Test, SBUS2)
{
	const char *filepath = "testdata/sbus2_r7008SB.txt";

	FILE *fp;
	fp = fopen(filepath, "rt");

	ASSERT_TRUE(fp);
	warnx("loading data from: %s", filepath);

	// if (argc < 2)
	// 	errx(1, "Need a filename for the input file");

	int byte_offset = 7;

	// if (argc > 2) {
	// 	char* end;
	// 	byte_offset = strtol(argv[2],&end,10);
	// }

	warnx("RUNNING TEST WITH BYTE OFFSET OF: %d", byte_offset);

	float f;
	unsigned x;
	int ret;

	// Trash the first 20 lines
	for (unsigned i = 0; i < 20; i++) {
		char buf[200];
		(void)fgets(buf, sizeof(buf), fp);
	}

	// Init the parser
	uint8_t frame[SBUS_BUFFER_SIZE];
	uint16_t rc_values[18];
	uint16_t num_values;
	unsigned sbus_frame_drops = 0;
	unsigned sbus_frame_resets = 0;
	bool sbus_failsafe;
	bool sbus_frame_drop;
	uint16_t max_channels = sizeof(rc_values) / sizeof(rc_values[0]);

	int rate_limiter = 0;
	unsigned last_drop = 0;

	while (EOF != (ret = fscanf(fp, "%f,%x,,", &f, &x))) {

		ASSERT_GT(ret, 0);

		frame[0] = x;
		unsigned len = 1;

		// Pipe the data into the parser
		hrt_abstime now = hrt_absolute_time();

		// if (rate_limiter % byte_offset == 0) {
			bool result = sbus_parse(now, &frame[0], len, rc_values, &num_values,
				&sbus_failsafe, &sbus_frame_drop, &sbus_frame_drops, max_channels);

			if (result) {
				//warnx("decoded packet");
			}
		// }

		if (last_drop != (sbus_frame_drops + sbus_frame_resets)) {
			warnx("frame dropped, now #%d", (sbus_frame_drops + sbus_frame_resets));
			last_drop = sbus_frame_drops + sbus_frame_resets;
		}

		rate_limiter++;
	}

	ASSERT_EQ(ret, EOF);
}
<|endoftext|>