SyncTests converted. One left... sync
authorKrista 'DarthMama' Bennett <krista@pep.foundation>
Fri, 30 Aug 2019 10:23:31 +0200
branchsync
changeset 40320f2b0543b90a
parent 4031 cbedd24a8359
child 4033 eefcb381b663
child 4036 9ecb9fbb5f6b
SyncTests converted. One left...
test/include/locked_queue.hh
test/src/SyncTests.cc
test/src/SyncTests.cc.FIXME
test/src/locked_queue.hh
     1.1 --- a/test/include/locked_queue.hh	Fri Aug 30 10:05:36 2019 +0200
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,61 +0,0 @@
     1.4 -#pragma once
     1.5 -
     1.6 -#include <list>
     1.7 -#include <mutex>
     1.8 -
     1.9 -namespace utility
    1.10 -{
    1.11 -    using namespace std;
    1.12 -
    1.13 -    template<class T> class locked_queue
    1.14 -    {
    1.15 -        mutex _mtx;
    1.16 -        list<T> _q;
    1.17 -
    1.18 -    public:
    1.19 -        T& back()
    1.20 -        {
    1.21 -            lock_guard<mutex> lg(_mtx);
    1.22 -            return _q.back();
    1.23 -        }
    1.24 -        T& front()
    1.25 -        {
    1.26 -            lock_guard<mutex> lg(_mtx);
    1.27 -            return _q.front();
    1.28 -        }
    1.29 -        T pop_back()
    1.30 -        {
    1.31 -            lock_guard<mutex> lg(_mtx);
    1.32 -            T r = _q.back();
    1.33 -            _q.pop_back();
    1.34 -            return r;
    1.35 -        }
    1.36 -        T pop_front()
    1.37 -        {
    1.38 -            lock_guard<mutex> lg(_mtx);
    1.39 -            T r = _q.front();
    1.40 -            _q.pop_front();
    1.41 -            return r;
    1.42 -        }
    1.43 -        void push_back(const T& data)
    1.44 -        {
    1.45 -            lock_guard<mutex> lg(_mtx);
    1.46 -            _q.push_back(data);
    1.47 -        }
    1.48 -        void push_front(const T& data)
    1.49 -        {
    1.50 -            lock_guard<mutex> lg(_mtx);
    1.51 -            _q.push_front(data);
    1.52 -        }
    1.53 -        size_t size()
    1.54 -        {
    1.55 -            lock_guard<mutex> lg(_mtx);
    1.56 -            return _q.size();
    1.57 -        }
    1.58 -        bool empty()
    1.59 -        {
    1.60 -            lock_guard<mutex> lg(_mtx);
    1.61 -            return _q.empty();
    1.62 -        }
    1.63 -    };
    1.64 -}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/src/SyncTests.cc	Fri Aug 30 10:23:31 2019 +0200
     2.3 @@ -0,0 +1,265 @@
     2.4 +// This file is under GNU General Public License 3.0
     2.5 +// see LICENSE.txt
     2.6 +
     2.7 +#include <stdlib.h>
     2.8 +#include <string>
     2.9 +#include <assert.h>
    2.10 +#include <thread>
    2.11 +
    2.12 +#include "locked_queue.hh"
    2.13 +#include "sync_api.h"
    2.14 +#include "Sync_impl.h"
    2.15 +
    2.16 +#include "test_util.h"
    2.17 +
    2.18 +#include "pEpEngine.h"
    2.19 +
    2.20 +#include "pEp_internal.h"
    2.21 +#include "KeySync_fsm.h"
    2.22 +#include "sync_codec.h"
    2.23 +
    2.24 +#include "Engine.h"
    2.25 +
    2.26 +#include <gtest/gtest.h>
    2.27 +
    2.28 +class Sync_Adapter {
    2.29 +public:
    2.30 +    utility::locked_queue< Sync_event_t * > q;
    2.31 +
    2.32 +    void processing();
    2.33 +
    2.34 +    static PEP_STATUS notifyHandshake(
    2.35 +            pEp_identity *me,
    2.36 +            pEp_identity *partner,
    2.37 +            sync_handshake_signal signal
    2.38 +        );
    2.39 +    static int inject_sync_event(SYNC_EVENT ev, void *management);
    2.40 +    static Sync_event_t *retrieve_next_sync_event(void *management, unsigned threshold);
    2.41 +    static PEP_STATUS messageToSend(struct _message *msg);
    2.42 +
    2.43 +    static void sync_thread(PEP_SESSION session, Sync_Adapter *adapter);
    2.44 +};
    2.45 +
    2.46 +
    2.47 +void Sync_Adapter::processing()
    2.48 +{
    2.49 +    output_stream << "waiting for processing\n";
    2.50 +    while (!q.empty()) {
    2.51 +        nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
    2.52 +    }
    2.53 +}
    2.54 +
    2.55 +PEP_STATUS Sync_Adapter::notifyHandshake(
    2.56 +        pEp_identity *me,
    2.57 +        pEp_identity *partner,
    2.58 +        sync_handshake_signal signal
    2.59 +    )
    2.60 +{
    2.61 +    return PEP_STATUS_OK;
    2.62 +}
    2.63 +
    2.64 +int Sync_Adapter::inject_sync_event(SYNC_EVENT ev, void *management)
    2.65 +{
    2.66 +    Sync_event_t *_ev = ev;
    2.67 +    switch (_ev->fsm) {
    2.68 +        case Sync_PR_keysync:
    2.69 +            output_stream << "injecting event " << KeySync_event_name(_ev->event) << "\n";
    2.70 +            break;
    2.71 +        default:
    2.72 +            output_stream << "unknown state machine: " << _ev->fsm << "\n";
    2.73 +            assert(0);
    2.74 +    }
    2.75 +    auto adapter = static_cast< Sync_Adapter *>(management);
    2.76 +    adapter->q.push_front(ev);
    2.77 +    return 0;
    2.78 +}
    2.79 +
    2.80 +Sync_event_t *Sync_Adapter::retrieve_next_sync_event(void *management, unsigned threshold)
    2.81 +{
    2.82 +    auto adapter = static_cast< Sync_Adapter *>(management);
    2.83 +    time_t started = time(nullptr);
    2.84 +    bool timeout = false;
    2.85 +
    2.86 +    while (adapter->q.empty()) {
    2.87 +        int i = 0;
    2.88 +        ++i;
    2.89 +        if (i > 10) {
    2.90 +            if (time(nullptr) > started + threshold) {
    2.91 +                timeout = true;
    2.92 +                break;
    2.93 +            }
    2.94 +            i = 0;
    2.95 +        }
    2.96 +        nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
    2.97 +    }
    2.98 +
    2.99 +    if (timeout)
   2.100 +        return SYNC_TIMEOUT_EVENT;
   2.101 +
   2.102 +    Sync_event_t *ev = adapter->q.pop_front();
   2.103 +    if (ev) {
   2.104 +        switch (ev->fsm) {
   2.105 +            case Sync_PR_keysync:
   2.106 +                output_stream << "sync thread: retrieving event " << KeySync_event_name(ev->event) << "\n";
   2.107 +                break;
   2.108 +            default:
   2.109 +                output_stream << "sync thread: unknown state machine: " << ev->fsm << "\n";
   2.110 +                assert(0);
   2.111 +        }
   2.112 +    }
   2.113 +    else {
   2.114 +        output_stream << "sync thread: retrieving shutdown\n";
   2.115 +    }
   2.116 +
   2.117 +    return ev;
   2.118 +}
   2.119 +
   2.120 +PEP_STATUS Sync_Adapter::messageToSend(struct _message *msg)
   2.121 +{
   2.122 +    assert(msg && msg->attachments);
   2.123 +
   2.124 +    output_stream << "sending message:\n";
   2.125 +
   2.126 +    for (bloblist_t *b = msg->attachments; b && b->value; b = b->next) {
   2.127 +        if (b->mime_type && strcasecmp(b->mime_type, "application/pEp.sync") == 0) {
   2.128 +            assert(msg->from && msg->from->address && msg->from->username);
   2.129 +            output_stream << "<!-- " << msg->from->username << " <" << msg->from->address << "> -->\n";
   2.130 +            char *text = NULL;
   2.131 +            PEP_STATUS status = PER_to_XER_Sync_msg(msg->attachments->value, msg->attachments->size, &text);
   2.132 +            assert(status == PEP_STATUS_OK);
   2.133 +            output_stream << text << "\n";
   2.134 +            free(text);
   2.135 +        }
   2.136 +    }
   2.137 +
   2.138 +    free_message(msg);
   2.139 +    return PEP_STATUS_OK;
   2.140 +}
   2.141 +
   2.142 +void Sync_Adapter::sync_thread(PEP_SESSION session, Sync_Adapter *adapter)
   2.143 +{
   2.144 +    output_stream << "sync_thread: startup\n";
   2.145 +    do_sync_protocol(session, adapter);
   2.146 +    output_stream << "sync_thread: shutdown\n";
   2.147 +}
   2.148 +
   2.149 +
   2.150 +namespace {
   2.151 +
   2.152 +	//The fixture for SyncTest
   2.153 +    class SyncTest : public ::testing::Test {
   2.154 +        public:
   2.155 +            Engine* engine;
   2.156 +            PEP_SESSION session;
   2.157 +
   2.158 +            Sync_Adapter adapter;
   2.159 +            PEP_SESSION sync = NULL;
   2.160 +            thread *sync_thread;
   2.161 +            
   2.162 +
   2.163 +        protected:
   2.164 +            // You can remove any or all of the following functions if its body
   2.165 +            // is empty.
   2.166 +            SyncTest() {
   2.167 +                // You can do set-up work for each test here.
   2.168 +                test_suite_name = ::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name();
   2.169 +                test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
   2.170 +                test_path = get_main_test_home_dir() + "/" + test_suite_name + "/" + test_name;
   2.171 +            }
   2.172 +
   2.173 +            ~SyncTest() override {
   2.174 +                // You can do clean-up work that doesn't throw exceptions here.
   2.175 +            }
   2.176 +
   2.177 +            // If the constructor and destructor are not enough for setting up
   2.178 +            // and cleaning up each test, you can define the following methods:
   2.179 +
   2.180 +            void SetUp() override {
   2.181 +                // Code here will be called immediately after the constructor (right
   2.182 +                // before each test).
   2.183 +
   2.184 +                // Leave this empty if there are no files to copy to the home directory path
   2.185 +                std::vector<std::pair<std::string, std::string>> init_files = std::vector<std::pair<std::string, std::string>>();
   2.186 +
   2.187 +                // Get a new test Engine.
   2.188 +                engine = new Engine(test_path);
   2.189 +                ASSERT_NE(engine, nullptr);
   2.190 +
   2.191 +                // Ok, let's initialize test directories etc.
   2.192 +                engine->prep(NULL, NULL, init_files);
   2.193 +
   2.194 +                // Ok, try to start this bugger. Is this totally irrelevant for this case??
   2.195 +                engine->start();
   2.196 +                ASSERT_NE(engine->session, nullptr);
   2.197 +                session = engine->session;
   2.198 +
   2.199 +                // Engine is up. Keep on truckin'
   2.200 +
   2.201 +                pEp_identity *self = new_identity("alice@synctests.pEp", nullptr, "23", "Alice Miller");
   2.202 +                assert(self);
   2.203 +                output_stream << "setting own identity for " << self->address << "\n";
   2.204 +                PEP_STATUS status = myself(session, self);
   2.205 +                assert(self->me);
   2.206 +                assert(self->fpr);
   2.207 +                output_stream << "fpr: " << self->fpr << "\n";
   2.208 +                free_identity(self);
   2.209 +
   2.210 +                status = init(&sync, Sync_Adapter::messageToSend, Sync_Adapter::inject_sync_event);
   2.211 +                if (status != PEP_STATUS_OK)
   2.212 +                    throw std::runtime_error((string("init returned ") + tl_status_string(status)).c_str());
   2.213 +
   2.214 +                output_stream << "initialize sync and start first state machine\n";
   2.215 +                status = register_sync_callbacks(
   2.216 +                    sync,
   2.217 +                    (void *) &adapter.q,
   2.218 +                    Sync_Adapter::notifyHandshake,
   2.219 +                    Sync_Adapter::retrieve_next_sync_event
   2.220 +                );
   2.221 +                if (status != PEP_STATUS_OK)
   2.222 +                    throw std::runtime_error((string("register sync status returned ") + tl_status_string(status)).c_str());
   2.223 +                if (sync->sync_state.keysync.state != Sole)
   2.224 +                    throw std::runtime_error((string("keysync.state was supposed to be ") + to_string((int)Sole) + " but was " + to_string((int)(sync->sync_state.keysync.state))).c_str());
   2.225 +
   2.226 +                output_stream << "creating thread for sync\n";
   2.227 +                sync_thread = new thread(Sync_Adapter::sync_thread, sync, &adapter);
   2.228 +
   2.229 +            }
   2.230 +
   2.231 +            void TearDown() override {
   2.232 +                // Code here will be called immediately after each test (right
   2.233 +                // before the destructor).
   2.234 +                
   2.235 +                adapter.processing();
   2.236 +
   2.237 +                output_stream << "sending shutdown to sync thread\n";
   2.238 +                adapter.q.push_front(nullptr);
   2.239 +                sync_thread->join();
   2.240 +
   2.241 +                unregister_sync_callbacks(sync);
   2.242 +                release(sync);
   2.243 +                
   2.244 +                engine->shut_down();
   2.245 +                delete engine;
   2.246 +                engine = NULL;
   2.247 +                session = NULL;
   2.248 +            }
   2.249 +
   2.250 +        private:
   2.251 +            const char* test_suite_name;
   2.252 +            const char* test_name;
   2.253 +            string test_path;
   2.254 +            // Objects declared here can be used by all tests in the SyncTest suite.
   2.255 +
   2.256 +    };
   2.257 +
   2.258 +}  // namespace
   2.259 +
   2.260 +TEST_F(SyncTest, check_sync)
   2.261 +{
   2.262 +    output_stream << "check_sync(): trigger KeyGen event\n";
   2.263 +    signal_Sync_event(sync, Sync_PR_keysync, KeyGen, NULL);
   2.264 +    adapter.processing();
   2.265 +
   2.266 +    output_stream << "check_sync(): cry for unknown key\n";
   2.267 +    signal_Sync_event(sync, Sync_PR_keysync, CannotDecrypt, NULL);
   2.268 +}
     3.1 --- a/test/src/SyncTests.cc.FIXME	Fri Aug 30 10:05:36 2019 +0200
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,185 +0,0 @@
     3.4 -// This file is under GNU General Public License 3.0
     3.5 -// see LICENSE.txt
     3.6 -
     3.7 -#include <stdlib.h>
     3.8 -#include <string>
     3.9 -#include <assert.h>
    3.10 -#include <cpptest.h>
    3.11 -#include "test_util.h"
    3.12 -
    3.13 -#include "pEpEngine.h"
    3.14 -
    3.15 -#include "pEp_internal.h"
    3.16 -#include "KeySync_fsm.h"
    3.17 -#include "sync_codec.h"
    3.18 -
    3.19 -#include "EngineTestSessionSuite.h"
    3.20 -#include "SyncTests.h"
    3.21 -
    3.22 -using namespace std;
    3.23 -
    3.24 -void Sync_Adapter::processing()
    3.25 -{
    3.26 -    output_stream << "waiting for processing\n";
    3.27 -    while (!q.empty()) {
    3.28 -        nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
    3.29 -    }
    3.30 -}
    3.31 -
    3.32 -PEP_STATUS Sync_Adapter::notifyHandshake(
    3.33 -        pEp_identity *me,
    3.34 -        pEp_identity *partner,
    3.35 -        sync_handshake_signal signal
    3.36 -    )
    3.37 -{
    3.38 -    return PEP_STATUS_OK;
    3.39 -}
    3.40 -
    3.41 -int Sync_Adapter::inject_sync_event(SYNC_EVENT ev, void *management)
    3.42 -{
    3.43 -    Sync_event_t *_ev = ev;
    3.44 -    switch (_ev->fsm) {
    3.45 -        case Sync_PR_keysync:
    3.46 -            output_stream << "injecting event " << KeySync_event_name(_ev->event) << "\n";
    3.47 -            break;
    3.48 -        default:
    3.49 -            output_stream << "unknown state machine: " << _ev->fsm << "\n";
    3.50 -            assert(0);
    3.51 -    }
    3.52 -    auto adapter = static_cast< Sync_Adapter *>(management);
    3.53 -    adapter->q.push_front(ev);
    3.54 -    return 0;
    3.55 -}
    3.56 -
    3.57 -Sync_event_t *Sync_Adapter::retrieve_next_sync_event(void *management, unsigned threshold)
    3.58 -{
    3.59 -    auto adapter = static_cast< Sync_Adapter *>(management);
    3.60 -    time_t started = time(nullptr);
    3.61 -    bool timeout = false;
    3.62 -
    3.63 -    while (adapter->q.empty()) {
    3.64 -        int i = 0;
    3.65 -        ++i;
    3.66 -        if (i > 10) {
    3.67 -            if (time(nullptr) > started + threshold) {
    3.68 -                timeout = true;
    3.69 -                break;
    3.70 -            }
    3.71 -            i = 0;
    3.72 -        }
    3.73 -        nanosleep((const struct timespec[]){{0, 100000000L}}, NULL);
    3.74 -    }
    3.75 -
    3.76 -    if (timeout)
    3.77 -        return SYNC_TIMEOUT_EVENT;
    3.78 -
    3.79 -    Sync_event_t *ev = adapter->q.pop_front();
    3.80 -    if (ev) {
    3.81 -        switch (ev->fsm) {
    3.82 -            case Sync_PR_keysync:
    3.83 -                output_stream << "sync thread: retrieving event " << KeySync_event_name(ev->event) << "\n";
    3.84 -                break;
    3.85 -            default:
    3.86 -                output_stream << "sync thread: unknown state machine: " << ev->fsm << "\n";
    3.87 -                assert(0);
    3.88 -        }
    3.89 -    }
    3.90 -    else {
    3.91 -        output_stream << "sync thread: retrieving shutdown\n";
    3.92 -    }
    3.93 -
    3.94 -    return ev;
    3.95 -}
    3.96 -
    3.97 -PEP_STATUS Sync_Adapter::messageToSend(struct _message *msg)
    3.98 -{
    3.99 -    assert(msg && msg->attachments);
   3.100 -    
   3.101 -    output_stream << "sending message:\n";
   3.102 -
   3.103 -    for (bloblist_t *b = msg->attachments; b && b->value; b = b->next) {
   3.104 -        if (b->mime_type && strcasecmp(b->mime_type, "application/pEp.sync") == 0) {
   3.105 -            assert(msg->from && msg->from->address && msg->from->username);
   3.106 -            output_stream << "<!-- " << msg->from->username << " <" << msg->from->address << "> -->\n";
   3.107 -            char *text = NULL;
   3.108 -            PEP_STATUS status = PER_to_XER_Sync_msg(msg->attachments->value, msg->attachments->size, &text);
   3.109 -            assert(status == PEP_STATUS_OK);
   3.110 -            output_stream << text << "\n";
   3.111 -            free(text);
   3.112 -        }
   3.113 -    }
   3.114 -
   3.115 -    free_message(msg);
   3.116 -    return PEP_STATUS_OK;
   3.117 -}
   3.118 -
   3.119 -void Sync_Adapter::sync_thread(PEP_SESSION session, Sync_Adapter *adapter)
   3.120 -{
   3.121 -    output_stream << "sync_thread: startup\n";
   3.122 -    do_sync_protocol(session, adapter);
   3.123 -    output_stream << "sync_thread: shutdown\n";
   3.124 -}
   3.125 -
   3.126 -SyncTests::SyncTests(string suitename, string test_home_dir) :
   3.127 -    EngineTestSessionSuite::EngineTestSessionSuite(suitename, test_home_dir) {
   3.128 -    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SyncTests::check_sync"),
   3.129 -                                                                      static_cast<Func>(&SyncTests::check_sync)));
   3.130 -}
   3.131 -
   3.132 -void SyncTests::setup()
   3.133 -{
   3.134 -    EngineTestSessionSuite::setup();
   3.135 -
   3.136 -    pEp_identity *self = new_identity("alice@synctests.pEp", nullptr, "23", "Alice Miller");
   3.137 -    assert(self);
   3.138 -    output_stream << "setting own identity for " << self->address << "\n";
   3.139 -    PEP_STATUS status = myself(session, self);
   3.140 -    assert(self->me);
   3.141 -    assert(self->fpr);
   3.142 -    output_stream << "fpr: " << self->fpr << "\n";
   3.143 -    free_identity(self);
   3.144 -
   3.145 -    status = init(&sync, Sync_Adapter::messageToSend, Sync_Adapter::inject_sync_event);
   3.146 -    if (status != PEP_STATUS_OK)
   3.147 -        throw std::runtime_error((string("init returned ") + tl_status_string(status)).c_str()); 
   3.148 -
   3.149 -    output_stream << "initialize sync and start first state machine\n";
   3.150 -    status = register_sync_callbacks(
   3.151 -            sync,
   3.152 -            (void *) &adapter.q,
   3.153 -            Sync_Adapter::notifyHandshake,
   3.154 -            Sync_Adapter::retrieve_next_sync_event
   3.155 -        );
   3.156 -    if (status != PEP_STATUS_OK)
   3.157 -        throw std::runtime_error((string("register sync status returned ") + tl_status_string(status)).c_str()); 
   3.158 -    if (sync->sync_state.keysync.state != Sole) 
   3.159 -        throw std::runtime_error((string("keysync.state was supposed to be ") + to_string((int)Sole) + " but was " + to_string((int)(sync->sync_state.keysync.state))).c_str()); 
   3.160 -      
   3.161 -
   3.162 -    output_stream << "creating thread for sync\n";
   3.163 -    sync_thread = new thread(Sync_Adapter::sync_thread, sync, &adapter);
   3.164 -}
   3.165 -
   3.166 -void SyncTests::tear_down()
   3.167 -{
   3.168 -    adapter.processing();
   3.169 -
   3.170 -    output_stream << "sending shutdown to sync thread\n";
   3.171 -    adapter.q.push_front(nullptr);
   3.172 -    sync_thread->join();
   3.173 -
   3.174 -    unregister_sync_callbacks(sync);
   3.175 -    release(sync);
   3.176 -
   3.177 -    EngineTestSessionSuite::tear_down();
   3.178 -}
   3.179 -
   3.180 -void SyncTests::check_sync()
   3.181 -{
   3.182 -    output_stream << "check_sync(): trigger KeyGen event\n";
   3.183 -    signal_Sync_event(sync, Sync_PR_keysync, KeyGen, NULL);
   3.184 -    adapter.processing();
   3.185 -
   3.186 -    output_stream << "check_sync(): cry for unknown key\n";
   3.187 -    signal_Sync_event(sync, Sync_PR_keysync, CannotDecrypt, NULL);
   3.188 -}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/src/locked_queue.hh	Fri Aug 30 10:23:31 2019 +0200
     4.3 @@ -0,0 +1,61 @@
     4.4 +#pragma once
     4.5 +
     4.6 +#include <list>
     4.7 +#include <mutex>
     4.8 +
     4.9 +namespace utility
    4.10 +{
    4.11 +    using namespace std;
    4.12 +
    4.13 +    template<class T> class locked_queue
    4.14 +    {
    4.15 +        mutex _mtx;
    4.16 +        list<T> _q;
    4.17 +
    4.18 +    public:
    4.19 +        T& back()
    4.20 +        {
    4.21 +            lock_guard<mutex> lg(_mtx);
    4.22 +            return _q.back();
    4.23 +        }
    4.24 +        T& front()
    4.25 +        {
    4.26 +            lock_guard<mutex> lg(_mtx);
    4.27 +            return _q.front();
    4.28 +        }
    4.29 +        T pop_back()
    4.30 +        {
    4.31 +            lock_guard<mutex> lg(_mtx);
    4.32 +            T r = _q.back();
    4.33 +            _q.pop_back();
    4.34 +            return r;
    4.35 +        }
    4.36 +        T pop_front()
    4.37 +        {
    4.38 +            lock_guard<mutex> lg(_mtx);
    4.39 +            T r = _q.front();
    4.40 +            _q.pop_front();
    4.41 +            return r;
    4.42 +        }
    4.43 +        void push_back(const T& data)
    4.44 +        {
    4.45 +            lock_guard<mutex> lg(_mtx);
    4.46 +            _q.push_back(data);
    4.47 +        }
    4.48 +        void push_front(const T& data)
    4.49 +        {
    4.50 +            lock_guard<mutex> lg(_mtx);
    4.51 +            _q.push_front(data);
    4.52 +        }
    4.53 +        size_t size()
    4.54 +        {
    4.55 +            lock_guard<mutex> lg(_mtx);
    4.56 +            return _q.size();
    4.57 +        }
    4.58 +        bool empty()
    4.59 +        {
    4.60 +            lock_guard<mutex> lg(_mtx);
    4.61 +            return _q.empty();
    4.62 +        }
    4.63 +    };
    4.64 +}