<commit_before>#ifndef ALGODS_LINKEDLIST_HXX
#define ALGODS_LINKEDLIST_HXX

#include <cassert>

#include <iterator>
#include <algorithm>
#include <sstream>
#include <utility>

#ifdef DEBUG
#include <iostream>
#endif

namespace algods {
    namespace linkedlist {

        using namespace std;

        template<typename T>
        struct slnode {
            slnode(const T& d, slnode* n): data(d), next(n) {
            }
            T data;
            slnode* next;
        };

        template<typename T>
        class sliterator : public iterator<forward_iterator_tag, T> {

        public:
            sliterator(): current(nullptr) {
            }

            sliterator(slnode<T>* head): current(head) {
            }

            sliterator(const sliterator& right) {
                current = right.current;
            }

            sliterator(sliterator&& right) {
                current = right.current;
                right.current = nullptr;
            }

            sliterator& operator=(const sliterator& right) {
                current = right.current;
                return *this;
            }

            sliterator& operator=(sliterator&& right) {
                current = right.current;
                right.current = nullptr;
                return *this;
            }

            sliterator& operator++() {
                if(nullptr != current) {
                    current = current->next;
                }
                return *this;
            }

            sliterator operator++(int) {
                sliterator ret(*this);
                ++(*this);
                return ret;
            }

            T& operator*() {
                assert(nullptr != current);
                return current->data;
            }

            const T& operator*() const {
                return this->operator*();
            }

            T* operator->() {
                assert(nullptr != current);
                return &(current->data);
            }

            bool operator==(const sliterator& right) const {
                return current == right.current;
            }

            bool operator!=(const sliterator& right) const {
                return !(*this == right);
            }

        private:
            slnode<T>* current;
        };

        template<typename T>
        sliterator<T> linkedlist_begin(slnode<T>* head) {
            return sliterator<T>(head);
        }

        template<typename T>
        sliterator<T> linkedlist_end(slnode<T>* head) {
            return sliterator<T>();
        }

        template<typename T>
        struct dlnode {
            dlnode(const T& d, dlnode* p, dlnode* n) : data(d), prev(p), next(n) {
            }
            T data;
            dlnode* prev;
            dlnode* next;
        };

        template<typename input_iterator>
        void build_linkedlist(input_iterator begin, input_iterator end,
                              slnode<typename iterator_traits<input_iterator>::value_type>*& head) {
            typedef typename iterator_traits<input_iterator>::value_type value_t;
            typedef slnode<value_t> node_t;
            node_t **current = &head;
            while(begin != end) {
                *current = new node_t(*begin, nullptr);
                current = &((*current)->next);
                ++begin;
            }
        }

        template<typename input_iterator>
        void build_linkedlist(input_iterator begin, input_iterator end,
                              dlnode<typename iterator_traits<input_iterator>::value_type>*& head) {
            typedef typename iterator_traits<input_iterator>::value_type value_t;
            typedef dlnode<value_t> node_t;
            node_t *prev = nullptr;
            node_t **current = &head;
            while(begin != end) {
                *current = new node_t(*begin, prev, nullptr);
                prev = *current;
                current = &((*current)->next);
                ++begin;
            }
            if(head != nullptr) {
                *current = head;
                head->prev = prev;
            }
        }

        template<typename T>
        void destroy_linkedlist(slnode<T>*& head) {
            while(head != nullptr) {
                auto p = head;
                head = head->next;
                delete p;
            }
        }

        template<typename T>
        void destroy_linkedlist(dlnode<T>*& head) {
            auto pivot = head;
            while(pivot != nullptr && pivot->next != head) {
                auto p = pivot;
                pivot = pivot->next;
                delete p;
            }
            if(pivot != nullptr) {
                delete pivot;
            }
            head = nullptr;
        }

        template<typename T>
        string linkedlist2string(const slnode<T>* head) {
            if(nullptr == head) {
                return string("{}");
            }
            sliterator<T> begin(linkedlist_begin(const_cast<slnode<T>*>(head)));
            sliterator<T> end(linkedlist_end(const_cast<slnode<T>*>(head)));
            ostringstream oss;
            copy(begin, end, ostream_iterator<T>(oss, "->"));
            string s(oss.str());
            // remove last "->"
            s.pop_back();
            s.pop_back();
            return "{" + s + "}";
        }

        template<typename T>
        string linkedlist2string(const dlnode<T>* head) {
            ostringstream oss;
            auto pivot = head;
            while(pivot != nullptr && pivot->next != head) {
                oss << pivot->data << "<->";
                pivot = pivot->next;
            }
            if(pivot != nullptr) {
                oss << pivot->data;
            }
            return oss.str();
        }

        template<typename T>
        void reverse_linkedlist(slnode<T>*& head) {
            slnode<T>* prev = nullptr;
            while(head != nullptr && head->next != nullptr) {
                auto next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            if(head != nullptr) {
                head->next = prev;
            }
        }

        template<typename T>
        void append_node(slnode<T>*& head, const T& data) {
            slnode<T>** current = &head;
            while(*current != nullptr) {
                current = &((*current)->next);
            }
            *current = new slnode<T>(data, nullptr);
        }

        template<typename T>
        void remove_node(slnode<T>*& head, slnode<T>*& p) {
            if(head == nullptr || p == nullptr) {
                return;
            }
            if(head == p) {
                head = head->next;
                delete p;
                p = nullptr;
                return;
            }
            auto current = head;
            while(current != nullptr && current->next != p) {
                current = current->next;
            }
            if(current != nullptr) {
                current->next = p->next;
                delete p;
                p = nullptr;
            }
        }

        template<typename T>
        slnode<T>* find_node(slnode<T>* head, const T& value) {
            while(head != nullptr) {
                if(head->data == value) {
                    return head;
                }
                head = head->next;
            }
            return nullptr;
        }

        template<typename T>
        void difference(slnode<T>*& left, slnode<T>* right) {
            while(right != nullptr) {
                auto p = find_node(left, right->data);
                remove_node(left, p);
                right = right->next;
            }
        }

        template<typename T>
        slnode<T>* merge_linkedlist(slnode<T>*& left, slnode<T>*& right) {
#ifdef DEBUG
            std::cout << "left list: " << linkedlist2string(left) << std::endl;
            std::cout << "right list: " << linkedlist2string(right) << std::endl;
#endif
            slnode<T>* head = nullptr;
            slnode<T>** pp = &head;
            int i = 0;
            while(nullptr != left && nullptr != right) {
                if((i & 0x1) == 0) {
                    *pp = left;
                    pp = &(*pp)->next;
                    left = left->next;
                } else {
                    *pp = right;
                    pp = &(*pp)->next;
                    right = right->next;
                }
                ++i;
            }
            if(nullptr != left) {
                *pp = left;
            }
            if(nullptr != right) {
                *pp = right;
            }
            left = nullptr;
            right = nullptr;
#ifdef DEBUG
            std::cout << "merged list: " << linkedlist2string(head) << std::endl;
#endif
            return head;
        }

        /****************************************************************************************
         ** Given a singly linked list L: (L0 , L1 , L2...Ln-1 , Ln).
         ** Write a program to reorder it so that it becomes(L0 , Ln , L1 , Ln-1 , L2 , Ln-2...).
         ***************************************************************************************/
        template<typename T>
        void reorder_linkedlist(slnode<T>*& head) {
#ifdef DEBUG
            std::cout << "original list: " << linkedlist2string(head) << std::endl;
#endif
            int num = 0;
            slnode<T>* p = head;
            while(nullptr != p) {
                ++num;
                p = p->next;
            }
            int count = 0;
            p = head;
            while(count < (num >> 1)) {
                ++count;
                p = p->next;
            }
            if((num & 0x1) != 0) {
                p = p->next;
            }
            slnode<T>* left = head;
            slnode<T>* right = p;
            p = head;
            while(nullptr != p && right != p->next) {
                p = p->next;
            }
            if(nullptr != p) {
                p->next = nullptr;
            }
#ifdef DEBUG
            std::cout << "left list: " << linkedlist2string(left) << std::endl;
            std::cout << "right list: " << linkedlist2string(right) << std::endl;
#endif
            reverse_linkedlist(right);
#ifdef DEBUG
            std::cout << "reversed right list: " << linkedlist2string(right) << std::endl;
#endif
            head = merge_linkedlist(left, right);
#ifdef DEBUG
            std::cout <<"result list: " << linkedlist2string(head) << std::endl;
#endif
        }
    }
}
#endif
<commit_msg>more stuff<commit_after>#ifndef ALGODS_LINKEDLIST_HXX
#define ALGODS_LINKEDLIST_HXX

#include <cassert>

#include <iterator>
#include <algorithm>
#include <sstream>
#include <utility>

#ifdef DEBUG
#include <iostream>
#endif

namespace algods {
    namespace linkedlist {

        using namespace std;

        template<typename T>
        struct slnode {
            slnode(const T& d, slnode* n): data(d), next(n) {
            }
            T data;
            slnode* next;
        };

        template<typename T>
        class sliterator : public iterator<forward_iterator_tag, T> {

        public:
            sliterator(): current(nullptr) {
            }

            sliterator(slnode<T>* head): current(head) {
            }

            sliterator(const sliterator& right) {
                current = right.current;
            }

            sliterator(sliterator&& right) {
                current = right.current;
                right.current = nullptr;
            }

            sliterator& operator=(const sliterator& right) {
                current = right.current;
                return *this;
            }

            sliterator& operator=(sliterator&& right) {
                current = right.current;
                right.current = nullptr;
                return *this;
            }

            sliterator& operator++() {
                if(nullptr != current) {
                    current = current->next;
                }
                return *this;
            }

            sliterator operator++(int) {
                sliterator ret(*this);
                ++(*this);
                return ret;
            }

            T& operator*() {
                assert(nullptr != current);
                return current->data;
            }

            const T& operator*() const {
                return this->operator*();
            }

            T* operator->() {
                assert(nullptr != current);
                return &(current->data);
            }

            bool operator==(const sliterator& right) const {
                return current == right.current;
            }

            bool operator!=(const sliterator& right) const {
                return !(*this == right);
            }

        private:
            slnode<T>* current;
        };

        template<typename T>
        sliterator<T> linkedlist_begin(slnode<T>* head) {
            return sliterator<T>(head);
        }

        template<typename T>
        sliterator<T> linkedlist_end(slnode<T>* head) {
            return sliterator<T>();
        }

        template<typename T>
        struct dlnode {
            dlnode(const T& d, dlnode* p, dlnode* n) : data(d), prev(p), next(n) {
            }
            T data;
            dlnode* prev;
            dlnode* next;
        };

        template<typename input_iterator>
        void build_linkedlist(input_iterator begin, input_iterator end,
                              slnode<typename iterator_traits<input_iterator>::value_type>*& head) {
            typedef typename iterator_traits<input_iterator>::value_type value_t;
            typedef slnode<value_t> node_t;
            node_t **current = &head;
            while(begin != end) {
                *current = new node_t(*begin, nullptr);
                current = &((*current)->next);
                ++begin;
            }
        }

        template<typename input_iterator>
        void build_linkedlist(input_iterator begin, input_iterator end,
                              dlnode<typename iterator_traits<input_iterator>::value_type>*& head) {
            typedef typename iterator_traits<input_iterator>::value_type value_t;
            typedef dlnode<value_t> node_t;
            node_t *prev = nullptr;
            node_t **current = &head;
            while(begin != end) {
                *current = new node_t(*begin, prev, nullptr);
                prev = *current;
                current = &((*current)->next);
                ++begin;
            }
            if(head != nullptr) {
                *current = head;
                head->prev = prev;
            }
        }

        template<typename T>
        void destroy_linkedlist(slnode<T>*& head) {
            while(head != nullptr) {
                auto p = head;
                head = head->next;
                delete p;
            }
        }

        template<typename T>
        void destroy_linkedlist(dlnode<T>*& head) {
            auto pivot = head;
            while(pivot != nullptr && pivot->next != head) {
                auto p = pivot;
                pivot = pivot->next;
                delete p;
            }
            if(pivot != nullptr) {
                delete pivot;
            }
            head = nullptr;
        }

        template<typename T>
        string linkedlist2string(const slnode<T>* head) {
            if(nullptr == head) {
                return string("{}");
            }
            sliterator<T> begin(linkedlist_begin(const_cast<slnode<T>*>(head)));
            sliterator<T> end(linkedlist_end(const_cast<slnode<T>*>(head)));
            ostringstream oss;
            copy(begin, end, ostream_iterator<T>(oss, "->"));
            string s(oss.str());
            // remove last "->"
            s = s.substr(0, s.size() - 2);
            return "{" + s + "}";
        }

        template<typename T>
        string linkedlist2string(const dlnode<T>* head) {
            ostringstream oss;
            auto pivot = head;
            while(pivot != nullptr && pivot->next != head) {
                oss << pivot->data << "<->";
                pivot = pivot->next;
            }
            if(pivot != nullptr) {
                oss << pivot->data;
            }
            return oss.str();
        }

        template<typename T>
        void reverse_linkedlist(slnode<T>*& head) {
            slnode<T>* prev = nullptr;
            while(head != nullptr && head->next != nullptr) {
                auto next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            if(head != nullptr) {
                head->next = prev;
            }
        }

        template<typename T>
        void append_node(slnode<T>*& head, const T& data) {
            slnode<T>** current = &head;
            while(*current != nullptr) {
                current = &((*current)->next);
            }
            *current = new slnode<T>(data, nullptr);
        }

        template<typename T>
        void remove_node(slnode<T>*& head, slnode<T>*& p) {
            if(head == nullptr || p == nullptr) {
                return;
            }
            if(head == p) {
                head = head->next;
                delete p;
                p = nullptr;
                return;
            }
            auto current = head;
            while(current != nullptr && current->next != p) {
                current = current->next;
            }
            if(current != nullptr) {
                current->next = p->next;
                delete p;
                p = nullptr;
            }
        }

        template<typename T>
        slnode<T>* find_node(slnode<T>* head, const T& value) {
            while(head != nullptr) {
                if(head->data == value) {
                    return head;
                }
                head = head->next;
            }
            return nullptr;
        }

        template<typename T>
        void difference(slnode<T>*& left, slnode<T>* right) {
            while(right != nullptr) {
                auto p = find_node(left, right->data);
                remove_node(left, p);
                right = right->next;
            }
        }

        template<typename T>
        slnode<T>* merge_linkedlist(slnode<T>*& left, slnode<T>*& right) {
#ifdef DEBUG
            std::cout << "left list: " << linkedlist2string(left) << std::endl;
            std::cout << "right list: " << linkedlist2string(right) << std::endl;
#endif
            slnode<T>* head = nullptr;
            slnode<T>** pp = &head;
            int i = 0;
            while(nullptr != left && nullptr != right) {
                if((i & 0x1) == 0) {
                    *pp = left;
                    pp = &(*pp)->next;
                    left = left->next;
                } else {
                    *pp = right;
                    pp = &(*pp)->next;
                    right = right->next;
                }
                ++i;
            }
            if(nullptr != left) {
                *pp = left;
            }
            if(nullptr != right) {
                *pp = right;
            }
            left = nullptr;
            right = nullptr;
#ifdef DEBUG
            std::cout << "merged list: " << linkedlist2string(head) << std::endl;
#endif
            return head;
        }

        /****************************************************************************************
         ** Given a singly linked list L: (L0 , L1 , L2...Ln-1 , Ln).
         ** Write a program to reorder it so that it becomes(L0 , Ln , L1 , Ln-1 , L2 , Ln-2...).
         ***************************************************************************************/
        template<typename T>
        void reorder_linkedlist(slnode<T>*& head) {
#ifdef DEBUG
            std::cout << "original list: " << linkedlist2string(head) << std::endl;
#endif
            int num = 0;
            slnode<T>* p = head;
            while(nullptr != p) {
                ++num;
                p = p->next;
            }
            int count = 0;
            p = head;
            while(count < (num >> 1)) {
                ++count;
                p = p->next;
            }
            if((num & 0x1) != 0) {
                p = p->next;
            }
            slnode<T>* left = head;
            slnode<T>* right = p;
            p = head;
            while(nullptr != p && right != p->next) {
                p = p->next;
            }
            if(nullptr != p) {
                p->next = nullptr;
            }
#ifdef DEBUG
            std::cout << "left list: " << linkedlist2string(left) << std::endl;
            std::cout << "right list: " << linkedlist2string(right) << std::endl;
#endif
            reverse_linkedlist(right);
#ifdef DEBUG
            std::cout << "reversed right list: " << linkedlist2string(right) << std::endl;
#endif
            head = merge_linkedlist(left, right);
#ifdef DEBUG
            std::cout <<"result list: " << linkedlist2string(head) << std::endl;
#endif
        }
    }
}
#endif
<|endoftext|>


<commit_before>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpc_target.h"
#include "shared_rpc_resources.h"
#include <vespa/fastos/thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/fnet/transport.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>
#include <chrono>
#include <thread>

#include <vespa/log/log.h>
LOG_SETUP(".storage.shared_rpc_resources");

using namespace std::chrono_literals;

namespace storage::rpc {

namespace {

class RpcTargetImpl : public RpcTarget {
private:
    FRT_Target* _target;
    vespalib::string _spec;

public:
    RpcTargetImpl(FRT_Target* target, const vespalib::string& spec)
        : _target(target),
          _spec(spec)
    {}
    ~RpcTargetImpl() override {
        _target->SubRef();
    }
    FRT_Target* get() noexcept override { return _target; }
    bool is_valid() const noexcept override { return _target->IsValid(); }
    const vespalib::string& spec() const noexcept override { return _spec; }
};

}

class SharedRpcResources::RpcTargetFactoryImpl : public RpcTargetFactory {
private:
    FRT_Supervisor& _orb;

public:
    RpcTargetFactoryImpl(FRT_Supervisor& orb)
        : _orb(orb)
    {}
    std::unique_ptr<RpcTarget> make_target(const vespalib::string& connection_spec) const override {
        auto* raw_target = _orb.GetTarget(connection_spec.c_str());
        if (raw_target) {
            return std::make_unique<RpcTargetImpl>(raw_target, connection_spec);
        }
        return std::unique_ptr<RpcTarget>();
    }
};

SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
                                       int rpc_server_port,
                                       size_t rpc_thread_pool_size)
    : _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)),
      _transport(std::make_unique<FNET_Transport>(rpc_thread_pool_size)),
      _orb(std::make_unique<FRT_Supervisor>(_transport.get())),
      _slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _target_factory(std::make_unique<RpcTargetFactoryImpl>(*_orb)),
      _hostname(vespalib::HostName::get()),
      _rpc_server_port(rpc_server_port),
      _shutdown(false)
{
}

// TODO make sure init/shutdown is safe for aborted init in comm. mgr.

SharedRpcResources::~SharedRpcResources() {
    if (!_shutdown) {
        shutdown();
    }
}

void SharedRpcResources::start_server_and_register_slobrok(vespalib::stringref my_handle) {
    LOG(debug, "Starting main RPC supervisor on port %d with slobrok handle '%s'",
        _rpc_server_port, vespalib::string(my_handle).c_str());
    if (!_orb->Listen(_rpc_server_port)) {
        throw vespalib::IllegalStateException(vespalib::make_string("Failed to listen to RPC port %d", _rpc_server_port),
                                              VESPA_STRLOC);
    }
    _transport->Start(_thread_pool.get());
    _slobrok_register->registerName(my_handle);
    wait_until_slobrok_is_ready();
    _handle = my_handle;
}

void SharedRpcResources::wait_until_slobrok_is_ready() {
    // TODO look more closely at how mbus does its slobrok business
    while (_slobrok_register->busy() || !_slobrok_mirror->ready()) {
        // TODO some form of timeout mechanism here, and warning logging to identify SB issues
        LOG(debug, "Waiting for Slobrok to become ready");
        std::this_thread::sleep_for(50ms);
    }
}

void SharedRpcResources::shutdown() {
    assert(!_shutdown);
    _slobrok_register->unregisterName(_handle);
    _transport->ShutDown(true);
    _shutdown = true;
}

int SharedRpcResources::listen_port() const noexcept {
    return _orb->GetListenPort();
}

const RpcTargetFactory& SharedRpcResources::target_factory() const {
    return *_target_factory;
}

}
<commit_msg>avoid spurious warnings when shutdown happens before successful listen<commit_after>// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpc_target.h"
#include "shared_rpc_resources.h"
#include <vespa/fastos/thread.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/frt/target.h>
#include <vespa/fnet/transport.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>
#include <chrono>
#include <thread>

#include <vespa/log/log.h>
LOG_SETUP(".storage.shared_rpc_resources");

using namespace std::chrono_literals;

namespace storage::rpc {

namespace {

class RpcTargetImpl : public RpcTarget {
private:
    FRT_Target* _target;
    vespalib::string _spec;

public:
    RpcTargetImpl(FRT_Target* target, const vespalib::string& spec)
        : _target(target),
          _spec(spec)
    {}
    ~RpcTargetImpl() override {
        _target->SubRef();
    }
    FRT_Target* get() noexcept override { return _target; }
    bool is_valid() const noexcept override { return _target->IsValid(); }
    const vespalib::string& spec() const noexcept override { return _spec; }
};

}

class SharedRpcResources::RpcTargetFactoryImpl : public RpcTargetFactory {
private:
    FRT_Supervisor& _orb;

public:
    RpcTargetFactoryImpl(FRT_Supervisor& orb)
        : _orb(orb)
    {}
    std::unique_ptr<RpcTarget> make_target(const vespalib::string& connection_spec) const override {
        auto* raw_target = _orb.GetTarget(connection_spec.c_str());
        if (raw_target) {
            return std::make_unique<RpcTargetImpl>(raw_target, connection_spec);
        }
        return std::unique_ptr<RpcTarget>();
    }
};

SharedRpcResources::SharedRpcResources(const config::ConfigUri& config_uri,
                                       int rpc_server_port,
                                       size_t rpc_thread_pool_size)
    : _thread_pool(std::make_unique<FastOS_ThreadPool>(1024*60)),
      _transport(std::make_unique<FNET_Transport>(rpc_thread_pool_size)),
      _orb(std::make_unique<FRT_Supervisor>(_transport.get())),
      _slobrok_register(std::make_unique<slobrok::api::RegisterAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _slobrok_mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, slobrok::ConfiguratorFactory(config_uri))),
      _target_factory(std::make_unique<RpcTargetFactoryImpl>(*_orb)),
      _hostname(vespalib::HostName::get()),
      _rpc_server_port(rpc_server_port),
      _shutdown(false)
{
}

// TODO make sure init/shutdown is safe for aborted init in comm. mgr.

SharedRpcResources::~SharedRpcResources() {
    if (!_shutdown) {
        shutdown();
    }
}

void SharedRpcResources::start_server_and_register_slobrok(vespalib::stringref my_handle) {
    LOG(debug, "Starting main RPC supervisor on port %d with slobrok handle '%s'",
        _rpc_server_port, vespalib::string(my_handle).c_str());
    if (!_orb->Listen(_rpc_server_port)) {
        throw vespalib::IllegalStateException(vespalib::make_string("Failed to listen to RPC port %d", _rpc_server_port),
                                              VESPA_STRLOC);
    }
    _transport->Start(_thread_pool.get());
    _slobrok_register->registerName(my_handle);
    wait_until_slobrok_is_ready();
    _handle = my_handle;
}

void SharedRpcResources::wait_until_slobrok_is_ready() {
    // TODO look more closely at how mbus does its slobrok business
    while (_slobrok_register->busy() || !_slobrok_mirror->ready()) {
        // TODO some form of timeout mechanism here, and warning logging to identify SB issues
        LOG(debug, "Waiting for Slobrok to become ready");
        std::this_thread::sleep_for(50ms);
    }
}

void SharedRpcResources::shutdown() {
    assert(!_shutdown);
    if (listen_port() > 0) {
        _slobrok_register->unregisterName(_handle);
    }
    _transport->ShutDown(true);
    _shutdown = true;
}

int SharedRpcResources::listen_port() const noexcept {
    return _orb->GetListenPort();
}

const RpcTargetFactory& SharedRpcResources::target_factory() const {
    return *_target_factory;
}

}
<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkBuffer.h"
#include "SkMaskFilter.h"

class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
    SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
                         uint32_t flags);

    // overrides from SkMaskFilter
    virtual SkMask::Format getFormat();
    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
                            SkIPoint* margin);
    virtual BlurType asABlur(BlurInfo*);

    // overrides from SkFlattenable
    virtual Factory getFactory();
    virtual void flatten(SkFlattenableWriteBuffer&);

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);

private:
    SkScalar                    fRadius;
    SkBlurMaskFilter::BlurStyle fBlurStyle;
    uint32_t                    fBlurFlags;

    SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);

    typedef SkMaskFilter INHERITED;
};

SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
                                       SkBlurMaskFilter::BlurStyle style,
                                       uint32_t flags) {
    if (radius <= 0 || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
        return NULL;
    }

    return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
}

///////////////////////////////////////////////////////////////////////////////

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
                                           SkBlurMaskFilter::BlurStyle style,
                                           uint32_t flags)
    : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
#if 0
    fGamma = NULL;
    if (gammaScale) {
        fGamma = new U8[256];
        if (gammaScale > 0)
            SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
        else
            SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
    }
#endif
    SkASSERT(radius >= 0);
    SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}

SkMask::Format SkBlurMaskFilterImpl::getFormat() {
    return SkMask::kA8_Format;
}

bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
                                      const SkMatrix& matrix, SkIPoint* margin) {
    SkScalar radius;
    if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
        radius = fRadius;
    } else {
        radius = matrix.mapRadius(fRadius);
    }

    // To avoid unseemly allocation requests (esp. for finite platforms like
    // handset) we limit the radius so something manageable. (as opposed to
    // a request like 10,000)
    static const SkScalar MAX_RADIUS = SkIntToScalar(128);
    radius = SkMinScalar(radius, MAX_RADIUS);
    SkBlurMask::Quality blurQuality =
        (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
            SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;

    return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
}

SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer) {
    return SkNEW_ARGS(SkBlurMaskFilterImpl, (buffer));
}

SkFlattenable::Factory SkBlurMaskFilterImpl::getFactory() {
    return CreateProc;
}

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
        : SkMaskFilter(buffer) {
    fRadius = buffer.readScalar();
    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readS32();
    fBlurFlags = buffer.readU32() & SkBlurMaskFilter::kAll_BlurFlag;
    SkASSERT(fRadius >= 0);
    SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}

void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fRadius);
    buffer.write32(fBlurStyle);
    buffer.write32(fBlurFlags);
}

static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
    SkMaskFilter::kNormal_BlurType,
    SkMaskFilter::kSolid_BlurType,
    SkMaskFilter::kOuter_BlurType,
    SkMaskFilter::kInner_BlurType,
};

SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) {
    if (info) {
        info->fRadius = fRadius;
        info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
        info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
    }
    return gBlurStyle2BlurType[fBlurStyle];
}

///////////////////////////////////////////////////////////////////////////////

static SkFlattenable::Registrar gReg("SkBlurMaskFilter",
                                     SkBlurMaskFilterImpl::CreateProc);

<commit_msg>Ignore blur margin fix flag for backward bug compatibility. http://codereview.appspot.com/4981046/<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkBuffer.h"
#include "SkMaskFilter.h"

class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
    SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
                         uint32_t flags);

    // overrides from SkMaskFilter
    virtual SkMask::Format getFormat();
    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
                            SkIPoint* margin);
    virtual BlurType asABlur(BlurInfo*);

    // overrides from SkFlattenable
    virtual Factory getFactory();
    virtual void flatten(SkFlattenableWriteBuffer&);

    static SkFlattenable* CreateProc(SkFlattenableReadBuffer&);

private:
    SkScalar                    fRadius;
    SkBlurMaskFilter::BlurStyle fBlurStyle;
    uint32_t                    fBlurFlags;

    SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);

    typedef SkMaskFilter INHERITED;
};

SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
                                       SkBlurMaskFilter::BlurStyle style,
                                       uint32_t flags) {
    if (radius <= 0 || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
        return NULL;
    }

    return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
}

///////////////////////////////////////////////////////////////////////////////

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
                                           SkBlurMaskFilter::BlurStyle style,
                                           uint32_t flags)
    : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
#if 0
    fGamma = NULL;
    if (gammaScale) {
        fGamma = new U8[256];
        if (gammaScale > 0)
            SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
        else
            SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
    }
#endif
    SkASSERT(radius >= 0);
    SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}

SkMask::Format SkBlurMaskFilterImpl::getFormat() {
    return SkMask::kA8_Format;
}

bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
                                      const SkMatrix& matrix, SkIPoint* margin) {
    SkScalar radius;
    if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
        radius = fRadius;
    } else {
        radius = matrix.mapRadius(fRadius);
    }

    // To avoid unseemly allocation requests (esp. for finite platforms like
    // handset) we limit the radius so something manageable. (as opposed to
    // a request like 10,000)
    static const SkScalar MAX_RADIUS = SkIntToScalar(128);
    radius = SkMinScalar(radius, MAX_RADIUS);
    SkBlurMask::Quality blurQuality =
        (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
            SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;

#if defined(SK_BLUR_MASK_FILTER_IGNORE_MARGIN_FIX)
    if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                         blurQuality)) {
        if (margin) {
            // we need to integralize radius for our margin, so take the ceil
            // just to be safe.
            margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
        }
        return true;
    }
    return false;
#else
    return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
#endif
}

SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer) {
    return SkNEW_ARGS(SkBlurMaskFilterImpl, (buffer));
}

SkFlattenable::Factory SkBlurMaskFilterImpl::getFactory() {
    return CreateProc;
}

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
        : SkMaskFilter(buffer) {
    fRadius = buffer.readScalar();
    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readS32();
    fBlurFlags = buffer.readU32() & SkBlurMaskFilter::kAll_BlurFlag;
    SkASSERT(fRadius >= 0);
    SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}

void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fRadius);
    buffer.write32(fBlurStyle);
    buffer.write32(fBlurFlags);
}

static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
    SkMaskFilter::kNormal_BlurType,
    SkMaskFilter::kSolid_BlurType,
    SkMaskFilter::kOuter_BlurType,
    SkMaskFilter::kInner_BlurType,
};

SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) {
    if (info) {
        info->fRadius = fRadius;
        info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
        info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
    }
    return gBlurStyle2BlurType[fBlurStyle];
}

///////////////////////////////////////////////////////////////////////////////

static SkFlattenable::Registrar gReg("SkBlurMaskFilter",
                                     SkBlurMaskFilterImpl::CreateProc);

<|endoftext|>


<commit_before>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkFlattenableBuffers.h"
#include "SkMaskFilter.h"

class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
    SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
                         uint32_t flags);

    // overrides from SkMaskFilter
    virtual SkMask::Format getFormat() SK_OVERRIDE;
    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
                            SkIPoint* margin) SK_OVERRIDE;
    virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE;
    virtual void setAsABlur(const BlurInfo&) SK_OVERRIDE;
    virtual void computeFastBounds(const SkRect& src, SkRect* dst) SK_OVERRIDE;

    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)

protected:
    virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
                                           const SkIRect& clipBounds,
                                           NinePatch*) SK_OVERRIDE;

private:
    SkScalar                    fRadius;
    SkBlurMaskFilter::BlurStyle fBlurStyle;
    uint32_t                    fBlurFlags;

    SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;

    typedef SkMaskFilter INHERITED;
};

SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
                                       SkBlurMaskFilter::BlurStyle style,
                                       uint32_t flags) {
    // use !(radius > 0) instead of radius <= 0 to reject NaN values
    if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
        return NULL;
    }

    return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
}

///////////////////////////////////////////////////////////////////////////////

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
                                           SkBlurMaskFilter::BlurStyle style,
                                           uint32_t flags)
    : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
#if 0
    fGamma = NULL;
    if (gammaScale) {
        fGamma = new U8[256];
        if (gammaScale > 0)
            SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
        else
            SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
    }
#endif
    SkASSERT(radius >= 0);
    SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}

SkMask::Format SkBlurMaskFilterImpl::getFormat() {
    return SkMask::kA8_Format;
}

bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
                                      const SkMatrix& matrix, SkIPoint* margin) {
    SkScalar radius;
    if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
        radius = fRadius;
    } else {
        radius = matrix.mapRadius(fRadius);
    }

    // To avoid unseemly allocation requests (esp. for finite platforms like
    // handset) we limit the radius so something manageable. (as opposed to
    // a request like 10,000)
    static const SkScalar MAX_RADIUS = SkIntToScalar(128);
    radius = SkMinScalar(radius, MAX_RADIUS);
    SkBlurMask::Quality blurQuality =
        (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
            SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;

#ifdef SK_BLUR_MASK_SEPARABLE
    return SkBlurMask::BlurSeparable(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
#else
    return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
#endif
}

#include "SkCanvas.h"

static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
    rects[0].roundOut(&mask->fBounds);
    mask->fRowBytes = SkAlign4(mask->fBounds.width());
    mask->fFormat = SkMask::kA8_Format;
    size_t size = mask->computeImageSize();
    mask->fImage = SkMask::AllocImage(size);
    if (NULL == mask->fImage) {
        return false;
    }
    sk_bzero(mask->fImage, size);

    SkBitmap bitmap;
    bitmap.setConfig(SkBitmap::kA8_Config,
                     mask->fBounds.width(), mask->fBounds.height(),
                     mask->fRowBytes);
    bitmap.setPixels(mask->fImage);

    SkCanvas canvas(bitmap);
    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
                     -SkIntToScalar(mask->fBounds.top()));

    SkPaint paint;
    paint.setAntiAlias(true);

    if (1 == count) {
        canvas.drawRect(rects[0], paint);
    } else {
        // todo: do I need a fast way to do this?
        SkPath path;
        path.addRect(rects[0]);
        path.addRect(rects[1]);
        path.setFillType(SkPath::kEvenOdd_FillType);
        canvas.drawPath(path, paint);
    }
    return true;
}

static bool rect_exceeds(const SkRect& r, SkScalar v) {
    return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
           r.width() > v || r.height() > v;
}

SkMaskFilter::FilterReturn
SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
                                        const SkMatrix& matrix,
                                        const SkIRect& clipBounds,
                                        NinePatch* patch) {
    if (count < 1 || count > 2) {
        return kUnimplemented_FilterReturn;
    }

    // TODO: take clipBounds into account to limit our coordinates up front
    // for now, just skip too-large src rects (to take the old code path).
    if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
        return kUnimplemented_FilterReturn;
    }

    SkIPoint margin;
    SkMask  srcM, dstM;
    rects[0].roundOut(&srcM.fBounds);
    srcM.fImage = NULL;
    srcM.fFormat = SkMask::kA8_Format;
    srcM.fRowBytes = 0;
    if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
        return kFalse_FilterReturn;
    }

    /*
     *  smallR is the smallest version of 'rect' that will still guarantee that
     *  we get the same blur results on all edges, plus 1 center row/col that is
     *  representative of the extendible/stretchable edges of the ninepatch.
     *  Since our actual edge may be fractional we inset 1 more to be sure we
     *  don't miss any interior blur.
     *  x is an added pixel of blur, and { and } are the (fractional) edge
     *  pixels from the original rect.
     *
     *   x x { x x .... x x } x x
     *
     *  Thus, in this case, we inset by a total of 5 (on each side) beginning
     *  with our outer-rect (dstM.fBounds)
     */
    SkRect smallR[2];
    SkIPoint center;

    // +2 is from +1 for each edge (to account for possible fractional edges
    int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
    int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
    SkIRect innerIR;

    if (1 == count) {
        innerIR = srcM.fBounds;
        center.set(smallW, smallH);
    } else {
        SkASSERT(2 == count);
        rects[1].roundIn(&innerIR);
        center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
                   smallH + (innerIR.top() - srcM.fBounds.top()));
    }

    // +1 so we get a clean, stretchable, center row/col
    smallW += 1;
    smallH += 1;

    // we want the inset amounts to be integral, so we don't change any
    // fractional phase on the fRight or fBottom of our smallR.
    const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
    const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
    if (dx < 0 || dy < 0) {
        // we're too small, relative to our blur, to break into nine-patch,
        // so we ask to have our normal filterMask() be called.
        return kUnimplemented_FilterReturn;
    }

    smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
    SkASSERT(!smallR[0].isEmpty());
    if (2 == count) {
        smallR[1].set(rects[1].left(), rects[1].top(),
                      rects[1].right() - dx, rects[1].bottom() - dy);
        SkASSERT(!smallR[1].isEmpty());
    }

    if (!drawRectsIntoMask(smallR, count, &srcM)) {
        return kFalse_FilterReturn;
    }

    SkAutoMaskFreeImage amf(srcM.fImage);

    if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
        return kFalse_FilterReturn;
    }
    patch->fMask.fBounds.offsetTo(0, 0);
    patch->fOuterRect = dstM.fBounds;
    patch->fCenter = center;
    return kTrue_FilterReturn;
}

void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) {
    dst->set(src.fLeft - fRadius, src.fTop - fRadius,
             src.fRight + fRadius, src.fBottom + fRadius);
}

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
        : SkMaskFilter(buffer) {
    fRadius = buffer.readScalar();
    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
    fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
    SkASSERT(fRadius >= 0);
    SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}

void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fRadius);
    buffer.writeInt(fBlurStyle);
    buffer.writeUInt(fBlurFlags);
}

static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
    SkMaskFilter::kNormal_BlurType,
    SkMaskFilter::kSolid_BlurType,
    SkMaskFilter::kOuter_BlurType,
    SkMaskFilter::kInner_BlurType,
};

SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) const {
    if (info) {
        info->fRadius = fRadius;
        info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
        info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
    }
    return gBlurStyle2BlurType[fBlurStyle];
}

void SkBlurMaskFilterImpl::setAsABlur(const BlurInfo& info) {
    fRadius = info.fRadius;
    fBlurFlags = (fBlurFlags & ~(SkBlurMaskFilter::kIgnoreTransform_BlurFlag
                                 | SkBlurMaskFilter::kHighQuality_BlurFlag))
            | (info.fIgnoreTransform ? SkBlurMaskFilter::kIgnoreTransform_BlurFlag : 0)
            | (info.fHighQuality ? SkBlurMaskFilter::kHighQuality_BlurFlag : 0);
}

SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
<commit_msg>Turn on the separable blur (release the hounds!).  This will require rebaselines of the following Skia tests:  tilemodes, texteffects, shadows, drawlooper, drawbitmaprect, circles, blurrect_grad, blurrect, blurs, drawbitmapmatrix (max. pixel change in 8888 is 5).<commit_after>
/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
#include "SkFlattenableBuffers.h"
#include "SkMaskFilter.h"

class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
    SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
                         uint32_t flags);

    // overrides from SkMaskFilter
    virtual SkMask::Format getFormat() SK_OVERRIDE;
    virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
                            SkIPoint* margin) SK_OVERRIDE;
    virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE;
    virtual void setAsABlur(const BlurInfo&) SK_OVERRIDE;
    virtual void computeFastBounds(const SkRect& src, SkRect* dst) SK_OVERRIDE;

    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)

protected:
    virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
                                           const SkIRect& clipBounds,
                                           NinePatch*) SK_OVERRIDE;

private:
    SkScalar                    fRadius;
    SkBlurMaskFilter::BlurStyle fBlurStyle;
    uint32_t                    fBlurFlags;

    SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;

    typedef SkMaskFilter INHERITED;
};

SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
                                       SkBlurMaskFilter::BlurStyle style,
                                       uint32_t flags) {
    // use !(radius > 0) instead of radius <= 0 to reject NaN values
    if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
        || flags > SkBlurMaskFilter::kAll_BlurFlag) {
        return NULL;
    }

    return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
}

///////////////////////////////////////////////////////////////////////////////

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
                                           SkBlurMaskFilter::BlurStyle style,
                                           uint32_t flags)
    : fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
#if 0
    fGamma = NULL;
    if (gammaScale) {
        fGamma = new U8[256];
        if (gammaScale > 0)
            SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
        else
            SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
    }
#endif
    SkASSERT(radius >= 0);
    SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
    SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}

SkMask::Format SkBlurMaskFilterImpl::getFormat() {
    return SkMask::kA8_Format;
}

bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
                                      const SkMatrix& matrix, SkIPoint* margin) {
    SkScalar radius;
    if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
        radius = fRadius;
    } else {
        radius = matrix.mapRadius(fRadius);
    }

    // To avoid unseemly allocation requests (esp. for finite platforms like
    // handset) we limit the radius so something manageable. (as opposed to
    // a request like 10,000)
    static const SkScalar MAX_RADIUS = SkIntToScalar(128);
    radius = SkMinScalar(radius, MAX_RADIUS);
    SkBlurMask::Quality blurQuality =
        (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
            SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;

#ifndef SK_DISABLE_SEPARABLE_MASK_BLUR
    return SkBlurMask::BlurSeparable(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
#else
    return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
                            blurQuality, margin);
#endif
}

#include "SkCanvas.h"

static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
    rects[0].roundOut(&mask->fBounds);
    mask->fRowBytes = SkAlign4(mask->fBounds.width());
    mask->fFormat = SkMask::kA8_Format;
    size_t size = mask->computeImageSize();
    mask->fImage = SkMask::AllocImage(size);
    if (NULL == mask->fImage) {
        return false;
    }
    sk_bzero(mask->fImage, size);

    SkBitmap bitmap;
    bitmap.setConfig(SkBitmap::kA8_Config,
                     mask->fBounds.width(), mask->fBounds.height(),
                     mask->fRowBytes);
    bitmap.setPixels(mask->fImage);

    SkCanvas canvas(bitmap);
    canvas.translate(-SkIntToScalar(mask->fBounds.left()),
                     -SkIntToScalar(mask->fBounds.top()));

    SkPaint paint;
    paint.setAntiAlias(true);

    if (1 == count) {
        canvas.drawRect(rects[0], paint);
    } else {
        // todo: do I need a fast way to do this?
        SkPath path;
        path.addRect(rects[0]);
        path.addRect(rects[1]);
        path.setFillType(SkPath::kEvenOdd_FillType);
        canvas.drawPath(path, paint);
    }
    return true;
}

static bool rect_exceeds(const SkRect& r, SkScalar v) {
    return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
           r.width() > v || r.height() > v;
}

SkMaskFilter::FilterReturn
SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
                                        const SkMatrix& matrix,
                                        const SkIRect& clipBounds,
                                        NinePatch* patch) {
    if (count < 1 || count > 2) {
        return kUnimplemented_FilterReturn;
    }

    // TODO: take clipBounds into account to limit our coordinates up front
    // for now, just skip too-large src rects (to take the old code path).
    if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
        return kUnimplemented_FilterReturn;
    }

    SkIPoint margin;
    SkMask  srcM, dstM;
    rects[0].roundOut(&srcM.fBounds);
    srcM.fImage = NULL;
    srcM.fFormat = SkMask::kA8_Format;
    srcM.fRowBytes = 0;
    if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
        return kFalse_FilterReturn;
    }

    /*
     *  smallR is the smallest version of 'rect' that will still guarantee that
     *  we get the same blur results on all edges, plus 1 center row/col that is
     *  representative of the extendible/stretchable edges of the ninepatch.
     *  Since our actual edge may be fractional we inset 1 more to be sure we
     *  don't miss any interior blur.
     *  x is an added pixel of blur, and { and } are the (fractional) edge
     *  pixels from the original rect.
     *
     *   x x { x x .... x x } x x
     *
     *  Thus, in this case, we inset by a total of 5 (on each side) beginning
     *  with our outer-rect (dstM.fBounds)
     */
    SkRect smallR[2];
    SkIPoint center;

    // +2 is from +1 for each edge (to account for possible fractional edges
    int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
    int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
    SkIRect innerIR;

    if (1 == count) {
        innerIR = srcM.fBounds;
        center.set(smallW, smallH);
    } else {
        SkASSERT(2 == count);
        rects[1].roundIn(&innerIR);
        center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
                   smallH + (innerIR.top() - srcM.fBounds.top()));
    }

    // +1 so we get a clean, stretchable, center row/col
    smallW += 1;
    smallH += 1;

    // we want the inset amounts to be integral, so we don't change any
    // fractional phase on the fRight or fBottom of our smallR.
    const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
    const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
    if (dx < 0 || dy < 0) {
        // we're too small, relative to our blur, to break into nine-patch,
        // so we ask to have our normal filterMask() be called.
        return kUnimplemented_FilterReturn;
    }

    smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
    SkASSERT(!smallR[0].isEmpty());
    if (2 == count) {
        smallR[1].set(rects[1].left(), rects[1].top(),
                      rects[1].right() - dx, rects[1].bottom() - dy);
        SkASSERT(!smallR[1].isEmpty());
    }

    if (!drawRectsIntoMask(smallR, count, &srcM)) {
        return kFalse_FilterReturn;
    }

    SkAutoMaskFreeImage amf(srcM.fImage);

    if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
        return kFalse_FilterReturn;
    }
    patch->fMask.fBounds.offsetTo(0, 0);
    patch->fOuterRect = dstM.fBounds;
    patch->fCenter = center;
    return kTrue_FilterReturn;
}

void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) {
    dst->set(src.fLeft - fRadius, src.fTop - fRadius,
             src.fRight + fRadius, src.fBottom + fRadius);
}

SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
        : SkMaskFilter(buffer) {
    fRadius = buffer.readScalar();
    fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
    fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
    SkASSERT(fRadius >= 0);
    SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}

void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
    this->INHERITED::flatten(buffer);
    buffer.writeScalar(fRadius);
    buffer.writeInt(fBlurStyle);
    buffer.writeUInt(fBlurFlags);
}

static const SkMaskFilter::BlurType gBlurStyle2BlurType[] = {
    SkMaskFilter::kNormal_BlurType,
    SkMaskFilter::kSolid_BlurType,
    SkMaskFilter::kOuter_BlurType,
    SkMaskFilter::kInner_BlurType,
};

SkMaskFilter::BlurType SkBlurMaskFilterImpl::asABlur(BlurInfo* info) const {
    if (info) {
        info->fRadius = fRadius;
        info->fIgnoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
        info->fHighQuality = SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag);
    }
    return gBlurStyle2BlurType[fBlurStyle];
}

void SkBlurMaskFilterImpl::setAsABlur(const BlurInfo& info) {
    fRadius = info.fRadius;
    fBlurFlags = (fBlurFlags & ~(SkBlurMaskFilter::kIgnoreTransform_BlurFlag
                                 | SkBlurMaskFilter::kHighQuality_BlurFlag))
            | (info.fIgnoreTransform ? SkBlurMaskFilter::kIgnoreTransform_BlurFlag : 0)
            | (info.fHighQuality ? SkBlurMaskFilter::kHighQuality_BlurFlag : 0);
}

SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
<|endoftext|>


<commit_before>#include <xzero/executor/NativeScheduler.h>
#include <xzero/RuntimeError.h>
#include <xzero/WallClock.h>
#include <xzero/sysconfig.h>
#include <algorithm>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>

namespace xzero {

#define PIPE_READ_END  0
#define PIPE_WRITE_END 1

/**
 * XXX
 * - registering a key should be *ONESHOT* and *Edge Triggered*
 * - rename NativeScheduler to SimpleScheduler
 *
 * XXX LinuxScheduler
 * - epoll fuer i/o notification
 * - eventfd for wakeup implementation
 * - timerfd_* for timer impl
 */

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock,
    std::function<void()> preInvoke,
    std::function<void()> postInvoke)
    : Scheduler(std::move(errorLogger)),
      clock_(clock ? clock : WallClock::system()),
      lock_(),
      wakeupPipe_(),
      onPreInvokePending_(preInvoke),
      onPostInvokePending_(postInvoke) {
  if (pipe(wakeupPipe_) < 0) {
    throw SYSTEM_ERROR(errno);
  }
  fcntl(wakeupPipe_[0], F_SETFL, O_NONBLOCK);
  fcntl(wakeupPipe_[1], F_SETFL, O_NONBLOCK);
}

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock)
    : NativeScheduler(errorLogger, clock, nullptr, nullptr) {
}

NativeScheduler::NativeScheduler()
    : NativeScheduler(nullptr, nullptr, nullptr, nullptr) {
}

NativeScheduler::~NativeScheduler() {
  ::close(wakeupPipe_[PIPE_READ_END]);
  ::close(wakeupPipe_[PIPE_WRITE_END]);
}

void NativeScheduler::execute(Task&& task) {
  {
    std::lock_guard<std::mutex> lk(lock_);
    tasks_.push_back(task);
  }
  breakLoop();
}

std::string NativeScheduler::toString() const {
  return "NativeScheduler";
}

Scheduler::HandleRef NativeScheduler::executeAfter(TimeSpan delay, Task task) {
  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  return insertIntoTimersList(clock_->get() + delay,
                              std::make_shared<Handle>(task, onCancel));
}

Scheduler::HandleRef NativeScheduler::executeAt(DateTime when, Task task) {
  return insertIntoTimersList(
      when,
      std::make_shared<Handle>(task,
                               std::bind(&NativeScheduler::removeFromTimersList,
                                         this,
                                         std::placeholders::_1)));
}

Scheduler::HandleRef NativeScheduler::insertIntoTimersList(DateTime dt,
                                                           HandleRef handle) {
  Timer t = { dt, handle };

  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.end();
  auto e = timers_.begin();

  while (i != e) {
    i--;
    const Timer& current = *i;
    if (current.when >= t.when) {
      timers_.insert(i, t);
      return handle;
    }
  }

  timers_.push_front(t);
  return handle;
}

void NativeScheduler::removeFromTimersList(Handle* handle) {
  std::lock_guard<std::mutex> lk(lock_);

  for (auto i = timers_.begin(), e = timers_.end(); i != e; ++i) {
    if (i->handle.get() == handle) {
      timers_.erase(i);
      break;
    }
  }
}

void NativeScheduler::collectTimeouts() {
  const DateTime now = clock_->get();

  std::lock_guard<std::mutex> lk(lock_);

  for (;;) {
    if (timers_.empty())
      break;

    const Timer& job = timers_.front();

    if (job.when > now)
      break;

    tasks_.push_back(job.handle->getAction());
    timers_.pop_front();
  }
}

inline Scheduler::HandleRef registerInterest(
    std::mutex* registryLock,
    std::list<std::pair<int, Scheduler::HandleRef>>* registry,
    int fd,
    Executor::Task task) {

  auto onCancel = [=](Scheduler::Handle* h) {
    std::lock_guard<std::mutex> lk(*registryLock);
    for (auto i: *registry) {
      if (i.second.get() == h) {
        return registry->remove(i);
      }
    }
  };

  std::lock_guard<std::mutex> lk(*registryLock);
  auto handle = std::make_shared<Scheduler::Handle>(task, onCancel);
  registry->push_back(std::make_pair(fd, handle));

  return handle;
}

Scheduler::HandleRef NativeScheduler::executeOnReadable(int fd, Task task) {
  return registerInterest(&lock_, &readers_, fd, task);
}

Scheduler::HandleRef NativeScheduler::executeOnWritable(int fd, Task task) {
  return registerInterest(&lock_, &writers_, fd, task);
}

inline void collectActiveHandles(
    std::list<std::pair<int, Scheduler::HandleRef>>* interests,
    fd_set* fdset,
    std::vector<Scheduler::HandleRef>* result) {

  auto i = interests->begin();
  auto e = interests->end();

  while (i != e) {
    if (FD_ISSET(i->first, fdset)) {
      result->push_back(i->second);
      i = interests->erase(i);
    } else {
      i++;
    }
  }
}

size_t NativeScheduler::timerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return timers_.size();
}

size_t NativeScheduler::readerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return readers_.size();
}

size_t NativeScheduler::writerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return writers_.size();
}

void NativeScheduler::runLoopOnce() {
  fd_set input, output, error;
  FD_ZERO(&input);
  FD_ZERO(&output);
  FD_ZERO(&error);

  int wmark = 0;
  timeval tv;

  {
    std::lock_guard<std::mutex> lk(lock_);

    for (auto i: readers_) {
      FD_SET(i.first, &input);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    for (auto i: writers_) {
      FD_SET(i.first, &output);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    const TimeSpan nextTimeout = !tasks_.empty()
                               ? TimeSpan::Zero
                               : !timers_.empty()
                                 ? timers_.front().when - clock_->get()
                                 : TimeSpan::fromSeconds(4);

    tv.tv_sec = static_cast<time_t>(nextTimeout.totalSeconds()),
    tv.tv_usec = nextTimeout.microseconds();
  }

  FD_SET(wakeupPipe_[PIPE_READ_END], &input);

  int rv = ::select(wmark + 1, &input, &output, &error, &tv);
  if (rv < 0 && errno != EINTR)
    throw SYSTEM_ERROR(errno);

  if (FD_ISSET(wakeupPipe_[PIPE_READ_END], &input)) {
    bool consumeMore = true;
    while (consumeMore) {
      char buf[sizeof(int) * 128];
      consumeMore = ::read(wakeupPipe_[PIPE_READ_END], buf, sizeof(buf)) > 0;
    }
  }

  collectTimeouts();

  std::vector<HandleRef> activeHandles;
  activeHandles.reserve(rv);

  std::deque<Task> activeTasks;
  {
    std::lock_guard<std::mutex> lk(lock_);

    collectActiveHandles(&readers_, &input, &activeHandles);
    collectActiveHandles(&writers_, &output, &activeHandles);
    activeTasks = std::move(tasks_);
  }

  safeCall(onPreInvokePending_);
  safeCallEach(activeHandles);
  safeCallEach(activeTasks);
  safeCall(onPostInvokePending_);
}

void NativeScheduler::breakLoop() {
  int dummy = 42;
  ::write(wakeupPipe_[PIPE_WRITE_END], &dummy, sizeof(dummy));
}

} // namespace xzero
<commit_msg>select() better EINTR safety<commit_after>#include <xzero/executor/NativeScheduler.h>
#include <xzero/RuntimeError.h>
#include <xzero/WallClock.h>
#include <xzero/sysconfig.h>
#include <algorithm>
#include <vector>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>

namespace xzero {

#define PIPE_READ_END  0
#define PIPE_WRITE_END 1

/**
 * XXX
 * - registering a key should be *ONESHOT* and *Edge Triggered*
 * - rename NativeScheduler to SimpleScheduler
 *
 * XXX LinuxScheduler
 * - epoll fuer i/o notification
 * - eventfd for wakeup implementation
 * - timerfd_* for timer impl
 */

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock,
    std::function<void()> preInvoke,
    std::function<void()> postInvoke)
    : Scheduler(std::move(errorLogger)),
      clock_(clock ? clock : WallClock::system()),
      lock_(),
      wakeupPipe_(),
      onPreInvokePending_(preInvoke),
      onPostInvokePending_(postInvoke) {
  if (pipe(wakeupPipe_) < 0) {
    throw SYSTEM_ERROR(errno);
  }
  fcntl(wakeupPipe_[0], F_SETFL, O_NONBLOCK);
  fcntl(wakeupPipe_[1], F_SETFL, O_NONBLOCK);
}

NativeScheduler::NativeScheduler(
    std::function<void(const std::exception&)> errorLogger,
    WallClock* clock)
    : NativeScheduler(errorLogger, clock, nullptr, nullptr) {
}

NativeScheduler::NativeScheduler()
    : NativeScheduler(nullptr, nullptr, nullptr, nullptr) {
}

NativeScheduler::~NativeScheduler() {
  ::close(wakeupPipe_[PIPE_READ_END]);
  ::close(wakeupPipe_[PIPE_WRITE_END]);
}

void NativeScheduler::execute(Task&& task) {
  {
    std::lock_guard<std::mutex> lk(lock_);
    tasks_.push_back(task);
  }
  breakLoop();
}

std::string NativeScheduler::toString() const {
  return "NativeScheduler";
}

Scheduler::HandleRef NativeScheduler::executeAfter(TimeSpan delay, Task task) {
  auto onCancel = [this](Handle* handle) {
    removeFromTimersList(handle);
  };

  return insertIntoTimersList(clock_->get() + delay,
                              std::make_shared<Handle>(task, onCancel));
}

Scheduler::HandleRef NativeScheduler::executeAt(DateTime when, Task task) {
  return insertIntoTimersList(
      when,
      std::make_shared<Handle>(task,
                               std::bind(&NativeScheduler::removeFromTimersList,
                                         this,
                                         std::placeholders::_1)));
}

Scheduler::HandleRef NativeScheduler::insertIntoTimersList(DateTime dt,
                                                           HandleRef handle) {
  Timer t = { dt, handle };

  std::lock_guard<std::mutex> lk(lock_);

  auto i = timers_.end();
  auto e = timers_.begin();

  while (i != e) {
    i--;
    const Timer& current = *i;
    if (current.when >= t.when) {
      timers_.insert(i, t);
      return handle;
    }
  }

  timers_.push_front(t);
  return handle;
}

void NativeScheduler::removeFromTimersList(Handle* handle) {
  std::lock_guard<std::mutex> lk(lock_);

  for (auto i = timers_.begin(), e = timers_.end(); i != e; ++i) {
    if (i->handle.get() == handle) {
      timers_.erase(i);
      break;
    }
  }
}

void NativeScheduler::collectTimeouts() {
  const DateTime now = clock_->get();

  std::lock_guard<std::mutex> lk(lock_);

  for (;;) {
    if (timers_.empty())
      break;

    const Timer& job = timers_.front();

    if (job.when > now)
      break;

    tasks_.push_back(job.handle->getAction());
    timers_.pop_front();
  }
}

inline Scheduler::HandleRef registerInterest(
    std::mutex* registryLock,
    std::list<std::pair<int, Scheduler::HandleRef>>* registry,
    int fd,
    Executor::Task task) {

  auto onCancel = [=](Scheduler::Handle* h) {
    std::lock_guard<std::mutex> lk(*registryLock);
    for (auto i: *registry) {
      if (i.second.get() == h) {
        return registry->remove(i);
      }
    }
  };

  std::lock_guard<std::mutex> lk(*registryLock);
  auto handle = std::make_shared<Scheduler::Handle>(task, onCancel);
  registry->push_back(std::make_pair(fd, handle));

  return handle;
}

Scheduler::HandleRef NativeScheduler::executeOnReadable(int fd, Task task) {
  return registerInterest(&lock_, &readers_, fd, task);
}

Scheduler::HandleRef NativeScheduler::executeOnWritable(int fd, Task task) {
  return registerInterest(&lock_, &writers_, fd, task);
}

inline void collectActiveHandles(
    std::list<std::pair<int, Scheduler::HandleRef>>* interests,
    fd_set* fdset,
    std::vector<Scheduler::HandleRef>* result) {

  auto i = interests->begin();
  auto e = interests->end();

  while (i != e) {
    if (FD_ISSET(i->first, fdset)) {
      result->push_back(i->second);
      i = interests->erase(i);
    } else {
      i++;
    }
  }
}

size_t NativeScheduler::timerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return timers_.size();
}

size_t NativeScheduler::readerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return readers_.size();
}

size_t NativeScheduler::writerCount() {
  std::lock_guard<std::mutex> lk(lock_);
  return writers_.size();
}

void NativeScheduler::runLoopOnce() {
  fd_set input, output, error;
  FD_ZERO(&input);
  FD_ZERO(&output);
  FD_ZERO(&error);

  int wmark = 0;
  timeval tv;

  {
    std::lock_guard<std::mutex> lk(lock_);

    for (auto i: readers_) {
      FD_SET(i.first, &input);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    for (auto i: writers_) {
      FD_SET(i.first, &output);
      if (i.first > wmark) {
        wmark = i.first;
      }
    }

    const TimeSpan nextTimeout = !tasks_.empty()
                               ? TimeSpan::Zero
                               : !timers_.empty()
                                 ? timers_.front().when - clock_->get()
                                 : TimeSpan::fromSeconds(4);

    tv.tv_sec = static_cast<time_t>(nextTimeout.totalSeconds()),
    tv.tv_usec = nextTimeout.microseconds();
  }

  FD_SET(wakeupPipe_[PIPE_READ_END], &input);

  int rv;
  do rv = ::select(wmark + 1, &input, &output, &error, &tv);
  while (rv < 0 && errno == EINTR);

  if (rv < 0)
    throw SYSTEM_ERROR(errno);

  if (FD_ISSET(wakeupPipe_[PIPE_READ_END], &input)) {
    bool consumeMore = true;
    while (consumeMore) {
      char buf[sizeof(int) * 128];
      consumeMore = ::read(wakeupPipe_[PIPE_READ_END], buf, sizeof(buf)) > 0;
    }
  }

  collectTimeouts();

  std::vector<HandleRef> activeHandles;
  activeHandles.reserve(rv);

  std::deque<Task> activeTasks;
  {
    std::lock_guard<std::mutex> lk(lock_);

    collectActiveHandles(&readers_, &input, &activeHandles);
    collectActiveHandles(&writers_, &output, &activeHandles);
    activeTasks = std::move(tasks_);
  }

  safeCall(onPreInvokePending_);
  safeCallEach(activeHandles);
  safeCallEach(activeTasks);
  safeCall(onPostInvokePending_);
}

void NativeScheduler::breakLoop() {
  int dummy = 42;
  ::write(wakeupPipe_[PIPE_WRITE_END], &dummy, sizeof(dummy));
}

} // namespace xzero
<|endoftext|>


<commit_before>/************************************************************************************
 *   Copyright (C) 2014-2016 by Savoir-faire Linux                                  *
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
 *                                                                                *
 *   This library is free software; you can redistribute it and/or                  *
 *   modify it under the terms of the GNU Lesser General Public                     *
 *   License as published by the Free Software Foundation; either                   *
 *   version 2.1 of the License, or (at your option) any later version.             *
 *                                                                                *
 *   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
 ***********************************************************************************/
#include "fallbackpersoncollection.h"

//Qt
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QHash>
#include <QtCore/QTimer>
#include <QtCore/QUrl>
#include <QtCore/QCryptographicHash>
#include <QtCore/QStandardPaths>

//Ring
#include "person.h"
#include "personmodel.h"
#include "private/vcardutils.h"
#include "contactmethod.h"
#include "collectioneditor.h"
#include "globalinstances.h"
#include "interfaces/pixmapmanipulatori.h"
#include "interfaces/actionextenderi.h"
#include "interfaces/itemmodelstateserializeri.h"
#include "private/threadworker.h"

class FallbackPersonBackendEditor final : public CollectionEditor<Person>
{
public:
   FallbackPersonBackendEditor(CollectionMediator<Person>* m, const QString& path) : CollectionEditor<Person>(m),m_Path(path) {}
   virtual bool save       ( const Person* item ) override;
   virtual bool remove     ( const Person* item ) override;
   virtual bool edit       ( Person*       item ) override;
   virtual bool addNew     ( Person*       item ) override;
   virtual bool addExisting( const Person* item ) override;

   QVector<Person*>             m_lItems;
   QString                      m_Path  ;
   QHash<const Person*,QString> m_hPaths;

private:
   virtual QVector<Person*> items() const override;
};

class FallbackPersonCollectionPrivate final : public QObject
{
   Q_OBJECT
public:
   FallbackPersonCollectionPrivate(FallbackPersonCollection* parent, CollectionMediator<Person>* mediator, const QString& path);
   CollectionMediator<Person>*  m_pMediator;
   QString                      m_Path     ;
   QString                      m_Name     ;

   FallbackPersonCollection* q_ptr;

public Q_SLOTS:
   void loadAsync();
};

FallbackPersonCollectionPrivate::FallbackPersonCollectionPrivate(FallbackPersonCollection* parent, CollectionMediator<Person>* mediator, const QString& path) : q_ptr(parent), m_pMediator(mediator), m_Path(path)
{
   //Default to somewhere ~/.local/share
   if (m_Path.isEmpty()) {
      m_Path = (QStandardPaths::writableLocation(QStandardPaths::DataLocation)) + "/vCard/";
      static_cast<FallbackPersonBackendEditor*>(q_ptr->editor<Person>())->m_Path = m_Path;
   }
   //Make sure the directory exists so that saving new contacts there doesn't fail
   if (!QDir().mkpath(m_Path))
      qWarning() << "cannot create path for fallbackcollection: " << m_Path;

   m_Name = path.split('/').last();
   if (m_Name.size())
      m_Name[0] = m_Name[0].toUpper();
   else
      m_Name = "vCard";
}

FallbackPersonCollection::FallbackPersonCollection(CollectionMediator<Person>* mediator, const QString& path, FallbackPersonCollection* parent) :
CollectionInterface(new FallbackPersonBackendEditor(mediator,path),parent),d_ptr(new FallbackPersonCollectionPrivate(this,mediator,path))
{
}

FallbackPersonCollection::~FallbackPersonCollection()
{
   delete d_ptr;
}

bool FallbackPersonBackendEditor::save(const Person* item)
{
   if (!item)
      return false;

   //An UID is required
   if (item->uid().isEmpty()) {
      QCryptographicHash hash(QCryptographicHash::Sha1);
      for (ContactMethod* n : item->phoneNumbers())
         hash.addData(n->uri().toLatin1());
      hash.addData(item->formattedName().toLatin1());
      QByteArray random;

      for (int i=0;i<5;i++)
         random.append(QChar((char)(rand()%255)));

      hash.addData(random);

      const_cast<Person*>(item)->setUid(hash.result().toHex());
   }

   QFile file(m_Path+'/'+item->uid()+".vcf");
   file.open(QIODevice::WriteOnly);
   file.write(item->toVCard({}));
   file.close();
   return true;
}

bool FallbackPersonBackendEditor::remove(const Person* item)
{
   if (!item)
      return false;

   QString path = m_hPaths[item];

   if (path.isEmpty())
      path = m_Path+'/'+item->uid()+".vcf";

   bool ret = QFile::remove(path);

   if (ret) {
      ret &= mediator()->removeItem(item);
   }

   return ret;
}

bool FallbackPersonBackendEditor::edit( Person* item)
{
   GlobalInstances::actionExtender().editPerson(item);
   return true;
}

bool FallbackPersonBackendEditor::addNew( Person* item)
{
   item->ensureUid();
   bool ret = save(item);

   if (ret) {
      addExisting(item);
   }

   return ret;
}

bool FallbackPersonBackendEditor::addExisting(const Person* item)
{
   m_lItems << const_cast<Person*>(item);
   mediator()->addItem(item);
   return true;
}

QVector<Person*> FallbackPersonBackendEditor::items() const
{
   return m_lItems;
}

QString FallbackPersonCollection::name () const
{
   return d_ptr->m_Name;
}

QString FallbackPersonCollection::category () const
{
   return QObject::tr("Contact");
}

QVariant FallbackPersonCollection::icon() const
{
   return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::CONTACT);
}

bool FallbackPersonCollection::isEnabled() const
{
    /* if ItemModelStateSerializer exists, check if collectin is enabled, else assume it is */
    try {
        return GlobalInstances::itemModelStateSerializer().isChecked(this);
    } catch (...) {
        return true;
     }
}

bool FallbackPersonCollection::load()
{
   new ThreadWorker([this]() {
      bool ok;
      Q_UNUSED(ok)
      QList< Person* > ret =  VCardUtils::loadDir(QUrl(d_ptr->m_Path),ok,static_cast<FallbackPersonBackendEditor*>(editor<Person>())->m_hPaths);
      for(Person* p : ret) {
         p->setCollection(this);
         editor<Person>()->addExisting(p);
      }
   });

   //Add all sub directories as new backends
   QTimer::singleShot(0,d_ptr,SLOT(loadAsync()));

   return true;
}

bool FallbackPersonCollection::reload()
{
   return false;
}

FlagPack<CollectionInterface::SupportedFeatures> FallbackPersonCollection::supportedFeatures() const
{
   return
      CollectionInterface::SupportedFeatures::NONE       |
      CollectionInterface::SupportedFeatures::LOAD       |
      CollectionInterface::SupportedFeatures::CLEAR      |
      CollectionInterface::SupportedFeatures::MANAGEABLE |
      CollectionInterface::SupportedFeatures::REMOVE     |
      CollectionInterface::SupportedFeatures::ADD        ;
}

bool FallbackPersonCollection::clear()
{
   QDir dir(d_ptr->m_Path);
   for (const QString& file : dir.entryList({"*.vcf"},QDir::Files))
      dir.remove(file);
   return true;
}

QByteArray FallbackPersonCollection::id() const
{
   return "fpc2"+d_ptr->m_Path.toLatin1();
}

void FallbackPersonCollectionPrivate::loadAsync()
{
   QDir d(m_Path);
   for (const QString& dir : d.entryList(QDir::AllDirs)) {
      if (dir != QString('.') && dir != "..") {
         CollectionInterface* col = PersonModel::instance().addCollection<FallbackPersonCollection,QString,FallbackPersonCollection*>(m_Path+'/'+dir,q_ptr);
         if (col->isEnabled()) {
            col->load();
         }
      }
   }
}

#include "fallbackpersoncollection.moc"
<commit_msg>vcardstore: Check `open()` return value<commit_after>/************************************************************************************
 *   Copyright (C) 2014-2016 by Savoir-faire Linux                                  *
 *   Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>         *
 *                                                                                *
 *   This library is free software; you can redistribute it and/or                  *
 *   modify it under the terms of the GNU Lesser General Public                     *
 *   License as published by the Free Software Foundation; either                   *
 *   version 2.1 of the License, or (at your option) any later version.             *
 *                                                                                *
 *   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA *
 ***********************************************************************************/
#include "fallbackpersoncollection.h"

//Qt
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QHash>
#include <QtCore/QTimer>
#include <QtCore/QUrl>
#include <QtCore/QCryptographicHash>
#include <QtCore/QStandardPaths>

//Ring
#include "person.h"
#include "personmodel.h"
#include "private/vcardutils.h"
#include "contactmethod.h"
#include "collectioneditor.h"
#include "globalinstances.h"
#include "interfaces/pixmapmanipulatori.h"
#include "interfaces/actionextenderi.h"
#include "interfaces/itemmodelstateserializeri.h"
#include "private/threadworker.h"

class FallbackPersonBackendEditor final : public CollectionEditor<Person>
{
public:
   FallbackPersonBackendEditor(CollectionMediator<Person>* m, const QString& path) : CollectionEditor<Person>(m),m_Path(path) {}
   virtual bool save       ( const Person* item ) override;
   virtual bool remove     ( const Person* item ) override;
   virtual bool edit       ( Person*       item ) override;
   virtual bool addNew     ( Person*       item ) override;
   virtual bool addExisting( const Person* item ) override;

   QVector<Person*>             m_lItems;
   QString                      m_Path  ;
   QHash<const Person*,QString> m_hPaths;

private:
   virtual QVector<Person*> items() const override;
};

class FallbackPersonCollectionPrivate final : public QObject
{
   Q_OBJECT
public:
   FallbackPersonCollectionPrivate(FallbackPersonCollection* parent, CollectionMediator<Person>* mediator, const QString& path);
   CollectionMediator<Person>*  m_pMediator;
   QString                      m_Path     ;
   QString                      m_Name     ;

   FallbackPersonCollection* q_ptr;

public Q_SLOTS:
   void loadAsync();
};

FallbackPersonCollectionPrivate::FallbackPersonCollectionPrivate(FallbackPersonCollection* parent, CollectionMediator<Person>* mediator, const QString& path) : q_ptr(parent), m_pMediator(mediator), m_Path(path)
{
   //Default to somewhere ~/.local/share
   if (m_Path.isEmpty()) {
      m_Path = (QStandardPaths::writableLocation(QStandardPaths::DataLocation)) + "/vCard/";
      static_cast<FallbackPersonBackendEditor*>(q_ptr->editor<Person>())->m_Path = m_Path;
   }
   //Make sure the directory exists so that saving new contacts there doesn't fail
   if (!QDir().mkpath(m_Path))
      qWarning() << "cannot create path for fallbackcollection: " << m_Path;

   m_Name = path.split('/').last();
   if (m_Name.size())
      m_Name[0] = m_Name[0].toUpper();
   else
      m_Name = "vCard";
}

FallbackPersonCollection::FallbackPersonCollection(CollectionMediator<Person>* mediator, const QString& path, FallbackPersonCollection* parent) :
CollectionInterface(new FallbackPersonBackendEditor(mediator,path),parent),d_ptr(new FallbackPersonCollectionPrivate(this,mediator,path))
{
}

FallbackPersonCollection::~FallbackPersonCollection()
{
   delete d_ptr;
}

bool FallbackPersonBackendEditor::save(const Person* item)
{
   if (!item)
      return false;

   //An UID is required
   if (item->uid().isEmpty()) {
      QCryptographicHash hash(QCryptographicHash::Sha1);
      for (ContactMethod* n : item->phoneNumbers())
         hash.addData(n->uri().toLatin1());
      hash.addData(item->formattedName().toLatin1());
      QByteArray random;

      for (int i=0;i<5;i++)
         random.append(QChar((char)(rand()%255)));

      hash.addData(random);

      const_cast<Person*>(item)->setUid(hash.result().toHex());
   }

   const QString path = m_Path+'/'+item->uid()+".vcf";

   QFile file(path);

   if (Q_UNLIKELY(!file.open(QIODevice::WriteOnly))) {
      qWarning() << "Can't write to" << path;
      return false;
   }

   file.write(item->toVCard({}));
   file.close();
   return true;
}

bool FallbackPersonBackendEditor::remove(const Person* item)
{
   if (!item)
      return false;

   QString path = m_hPaths[item];

   if (path.isEmpty())
      path = m_Path+'/'+item->uid()+".vcf";

   bool ret = QFile::remove(path);

   if (ret) {
      ret &= mediator()->removeItem(item);
   }

   return ret;
}

bool FallbackPersonBackendEditor::edit( Person* item)
{
   GlobalInstances::actionExtender().editPerson(item);
   return true;
}

bool FallbackPersonBackendEditor::addNew( Person* item)
{
   item->ensureUid();
   bool ret = save(item);

   if (ret) {
      addExisting(item);
   }

   return ret;
}

bool FallbackPersonBackendEditor::addExisting(const Person* item)
{
   m_lItems << const_cast<Person*>(item);
   mediator()->addItem(item);
   return true;
}

QVector<Person*> FallbackPersonBackendEditor::items() const
{
   return m_lItems;
}

QString FallbackPersonCollection::name () const
{
   return d_ptr->m_Name;
}

QString FallbackPersonCollection::category () const
{
   return QObject::tr("Contact");
}

QVariant FallbackPersonCollection::icon() const
{
   return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::CONTACT);
}

bool FallbackPersonCollection::isEnabled() const
{
    /* if ItemModelStateSerializer exists, check if collectin is enabled, else assume it is */
    try {
        return GlobalInstances::itemModelStateSerializer().isChecked(this);
    } catch (...) {
        return true;
     }
}

bool FallbackPersonCollection::load()
{
   new ThreadWorker([this]() {
      bool ok;
      Q_UNUSED(ok)
      QList< Person* > ret =  VCardUtils::loadDir(QUrl(d_ptr->m_Path),ok,static_cast<FallbackPersonBackendEditor*>(editor<Person>())->m_hPaths);
      for(Person* p : ret) {
         p->setCollection(this);
         editor<Person>()->addExisting(p);
      }
   });

   //Add all sub directories as new backends
   QTimer::singleShot(0,d_ptr,SLOT(loadAsync()));

   return true;
}

bool FallbackPersonCollection::reload()
{
   return false;
}

FlagPack<CollectionInterface::SupportedFeatures> FallbackPersonCollection::supportedFeatures() const
{
   return
      CollectionInterface::SupportedFeatures::NONE       |
      CollectionInterface::SupportedFeatures::LOAD       |
      CollectionInterface::SupportedFeatures::CLEAR      |
      CollectionInterface::SupportedFeatures::MANAGEABLE |
      CollectionInterface::SupportedFeatures::REMOVE     |
      CollectionInterface::SupportedFeatures::ADD        ;
}

bool FallbackPersonCollection::clear()
{
   QDir dir(d_ptr->m_Path);
   for (const QString& file : dir.entryList({"*.vcf"},QDir::Files))
      dir.remove(file);
   return true;
}

QByteArray FallbackPersonCollection::id() const
{
   return "fpc2"+d_ptr->m_Path.toLatin1();
}

void FallbackPersonCollectionPrivate::loadAsync()
{
   QDir d(m_Path);
   for (const QString& dir : d.entryList(QDir::AllDirs)) {
      if (dir != QString('.') && dir != "..") {
         CollectionInterface* col = PersonModel::instance().addCollection<FallbackPersonCollection,QString,FallbackPersonCollection*>(m_Path+'/'+dir,q_ptr);
         if (col->isEnabled()) {
            col->load();
         }
      }
   }
}

#include "fallbackpersoncollection.moc"
<|endoftext|>