<commit_before>#ifndef ARCH_IO_DISK_HPP_
#define ARCH_IO_DISK_HPP_

#include "utils.hpp"
#include <boost/scoped_ptr.hpp>

#include "config/args.hpp"
#include "arch/io/io_utils.hpp"
#include "arch/runtime/event_queue.hpp"
#include "arch/runtime/thread_pool.hpp"
#include "arch/types.hpp"

#include "perfmon/core.hpp"

class linux_iocallback_t;
struct linux_disk_manager_t;

//class perfmon_collection_t;

/* Disk manager object takes care of queueing operations, collecting statistics, preventing
   conflicts, and actually sending them to the disk. */

struct linux_disk_manager_t : public home_thread_mixin_t {
    linux_disk_manager_t() { }

    virtual ~linux_disk_manager_t() { }

    virtual void *create_account(int priority, int outstanding_requests_limit) = 0;
    virtual void destroy_account(void *account) = 0;

    virtual void submit_write(fd_t fd, const void *buf, size_t count, size_t offset,
        void *account, linux_iocallback_t *cb) = 0;
    virtual void submit_read(fd_t fd, void *buf, size_t count, size_t offset,
        void *account, linux_iocallback_t *cb) = 0;

private:
    DISABLE_COPYING(linux_disk_manager_t);
};

class io_backender_t : public home_thread_mixin_t {
public:
    virtual void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                                   perfmon_collection_t *stats,
                                   boost::scoped_ptr<linux_disk_manager_t> *out) = 0;

    virtual ~io_backender_t() { }
    linux_disk_manager_t *get_diskmgr_ptr() {return diskmgr.get();}

protected:
    io_backender_t() : queue(&linux_thread_pool_t::thread->queue), batch_factor(DEFAULT_IO_BATCH_FACTOR) {
        //        printf("tst\n");
    }
    linux_event_queue_t *queue;
    int batch_factor;
    perfmon_collection_t stats;
    boost::scoped_ptr<linux_disk_manager_t> diskmgr;

private:
    DISABLE_COPYING(io_backender_t);
};

class native_io_backender_t : public io_backender_t {
public:
    native_io_backender_t() { make_disk_manager(queue, batch_factor, &stats, &diskmgr); }
    void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                           perfmon_collection_t *stats,
                           boost::scoped_ptr<linux_disk_manager_t> *out);
};

class pool_io_backender_t : public io_backender_t {
public:
    pool_io_backender_t() { make_disk_manager(queue, batch_factor, &stats, &diskmgr); }
    void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                           perfmon_collection_t *stats,
                           boost::scoped_ptr<linux_disk_manager_t> *out);
};

void make_io_backender(io_backend_t backend, boost::scoped_ptr<io_backender_t> *out);

class linux_file_account_t {
public:
    linux_file_account_t(linux_file_t *f, int p, int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS);
    ~linux_file_account_t();
    void *get_account() { return account; };

private:
    friend class linux_file_t;
    linux_file_t *parent;
    /* account is internally a pointer to a accounting_diskmgr_t::account_t object. It has to be
       a void* because accounting_diskmgr_t is a template, so its actual type depends on what
       IO backend is chosen. */
    // Maybe accounting_diskmgr_t shouldn't be a templated class then.

    void *account;
};

class linux_file_t {
public:
    friend class linux_file_account_t;

    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    linux_file_t(const char *path, int mode, bool is_really_direct, io_backender_t *io_backender);

    bool exists();
    bool is_block_device();
    uint64_t get_size();
    void set_size(size_t size);
    void set_size_at_least(size_t size);

    void read_async(size_t offset, size_t length, void *buf, linux_file_account_t *account, linux_iocallback_t *cb);
    void write_async(size_t offset, size_t length, const void *buf, linux_file_account_t *account, linux_iocallback_t *cb);

    void read_blocking(size_t offset, size_t length, void *buf);
    void write_blocking(size_t offset, size_t length, const void *buf);

    ~linux_file_t();

private:
    scoped_fd_t fd;
    bool is_block;
    bool file_exists;
    uint64_t file_size;
    void verify(size_t offset, size_t length, const void *buf);

    /* In a scoped pointer because it's polymorphic */
    linux_disk_manager_t *diskmgr;

    /* In a scoped_ptr so we can initialize it after "diskmgr" */
    boost::scoped_ptr<linux_file_account_t> default_account;

    DISABLE_COPYING(linux_file_t);
};

/* The "direct" in linux_direct_file_t refers to the fact that the
file is opened in O_DIRECT mode, and there are restrictions on the
alignment of the chunks being written and read to and from the file. */
class linux_direct_file_t : public linux_file_t {
public:
    linux_direct_file_t(const char *path, int mode, io_backender_t *io_backender) :
        linux_file_t(path, mode, true, io_backender) { }

private:
    DISABLE_COPYING(linux_direct_file_t);
};

class linux_nondirect_file_t : public linux_file_t {
public:
    linux_nondirect_file_t(const char *path, int mode, io_backender_t *io_backender) :
        linux_file_t(path, mode, false, io_backender) { }

private:
    DISABLE_COPYING(linux_nondirect_file_t);
};

#endif // ARCH_IO_DISK_HPP_

<commit_msg>Removed more extraneous comments.<commit_after>#ifndef ARCH_IO_DISK_HPP_
#define ARCH_IO_DISK_HPP_

#include "utils.hpp"
#include <boost/scoped_ptr.hpp>

#include "config/args.hpp"
#include "arch/io/io_utils.hpp"
#include "arch/runtime/event_queue.hpp"
#include "arch/runtime/thread_pool.hpp"
#include "arch/types.hpp"

#include "perfmon/core.hpp"

class linux_iocallback_t;
struct linux_disk_manager_t;

/* Disk manager object takes care of queueing operations, collecting statistics, preventing
   conflicts, and actually sending them to the disk. */

struct linux_disk_manager_t : public home_thread_mixin_t {
    linux_disk_manager_t() { }

    virtual ~linux_disk_manager_t() { }

    virtual void *create_account(int priority, int outstanding_requests_limit) = 0;
    virtual void destroy_account(void *account) = 0;

    virtual void submit_write(fd_t fd, const void *buf, size_t count, size_t offset,
        void *account, linux_iocallback_t *cb) = 0;
    virtual void submit_read(fd_t fd, void *buf, size_t count, size_t offset,
        void *account, linux_iocallback_t *cb) = 0;

private:
    DISABLE_COPYING(linux_disk_manager_t);
};

class io_backender_t : public home_thread_mixin_t {
public:
    virtual void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                                   perfmon_collection_t *stats,
                                   boost::scoped_ptr<linux_disk_manager_t> *out) = 0;

    virtual ~io_backender_t() { }
    linux_disk_manager_t *get_diskmgr_ptr() {return diskmgr.get();}

protected:
    io_backender_t() : queue(&linux_thread_pool_t::thread->queue), batch_factor(DEFAULT_IO_BATCH_FACTOR) {
        //        printf("tst\n");
    }
    linux_event_queue_t *queue;
    int batch_factor;
    perfmon_collection_t stats;
    boost::scoped_ptr<linux_disk_manager_t> diskmgr;

private:
    DISABLE_COPYING(io_backender_t);
};

class native_io_backender_t : public io_backender_t {
public:
    native_io_backender_t() { make_disk_manager(queue, batch_factor, &stats, &diskmgr); }
    void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                           perfmon_collection_t *stats,
                           boost::scoped_ptr<linux_disk_manager_t> *out);
};

class pool_io_backender_t : public io_backender_t {
public:
    pool_io_backender_t() { make_disk_manager(queue, batch_factor, &stats, &diskmgr); }
    void make_disk_manager(linux_event_queue_t *queue, const int batch_factor,
                           perfmon_collection_t *stats,
                           boost::scoped_ptr<linux_disk_manager_t> *out);
};

void make_io_backender(io_backend_t backend, boost::scoped_ptr<io_backender_t> *out);

class linux_file_account_t {
public:
    linux_file_account_t(linux_file_t *f, int p, int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS);
    ~linux_file_account_t();
    void *get_account() { return account; };

private:
    friend class linux_file_t;
    linux_file_t *parent;
    /* account is internally a pointer to a accounting_diskmgr_t::account_t object. It has to be
       a void* because accounting_diskmgr_t is a template, so its actual type depends on what
       IO backend is chosen. */
    // Maybe accounting_diskmgr_t shouldn't be a templated class then.

    void *account;
};

class linux_file_t {
public:
    friend class linux_file_account_t;

    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    linux_file_t(const char *path, int mode, bool is_really_direct, io_backender_t *io_backender);

    bool exists();
    bool is_block_device();
    uint64_t get_size();
    void set_size(size_t size);
    void set_size_at_least(size_t size);

    void read_async(size_t offset, size_t length, void *buf, linux_file_account_t *account, linux_iocallback_t *cb);
    void write_async(size_t offset, size_t length, const void *buf, linux_file_account_t *account, linux_iocallback_t *cb);

    void read_blocking(size_t offset, size_t length, void *buf);
    void write_blocking(size_t offset, size_t length, const void *buf);

    ~linux_file_t();

private:
    scoped_fd_t fd;
    bool is_block;
    bool file_exists;
    uint64_t file_size;
    void verify(size_t offset, size_t length, const void *buf);

    /* In a scoped pointer because it's polymorphic */
    linux_disk_manager_t *diskmgr;

    /* In a scoped_ptr so we can initialize it after "diskmgr" */
    boost::scoped_ptr<linux_file_account_t> default_account;

    DISABLE_COPYING(linux_file_t);
};

/* The "direct" in linux_direct_file_t refers to the fact that the
file is opened in O_DIRECT mode, and there are restrictions on the
alignment of the chunks being written and read to and from the file. */
class linux_direct_file_t : public linux_file_t {
public:
    linux_direct_file_t(const char *path, int mode, io_backender_t *io_backender) :
        linux_file_t(path, mode, true, io_backender) { }

private:
    DISABLE_COPYING(linux_direct_file_t);
};

class linux_nondirect_file_t : public linux_file_t {
public:
    linux_nondirect_file_t(const char *path, int mode, io_backender_t *io_backender) :
        linux_file_t(path, mode, false, io_backender) { }

private:
    DISABLE_COPYING(linux_nondirect_file_t);
};

#endif // ARCH_IO_DISK_HPP_

<|endoftext|>


<commit_before>#include "FitsObject.h"
#include <iostream>
#include <UnitTest++/UnitTest++.h>
#include <stdexcept>

using namespace std;

struct DefaultFixture
{
    DefaultFixture()
    {
        f = new Fits("../test.fits");
    }

    ~DefaultFixture()
    {
        delete f;
    }

    Fits *f;
};

/* Check for a bad filename */
TEST(BadFilename)
{
    CHECK_THROW(Fits test("badfilename"), runtime_error);
}

TEST_FIXTURE(DefaultFixture, BadMoveCheck)
{
    CHECK_THROW(f->moveHDU(-100), runtime_error);

}

TEST_FIXTURE(DefaultFixture, PastFileMoveCheck)
{
    CHECK_THROW(f->moveHDU(100), runtime_error);

}

TEST_FIXTURE(DefaultFixture, BadHDUName)
{
    CHECK_THROW(f->moveHDU("BADHDUNAME"), runtime_error);
}

TEST_FIXTURE(DefaultFixture, HDUName)
{
    f->moveHDU(2);
    CHECK_EQUAL("TABLE", f->hduname());
}

int main(int argc, const char *argv[])
{
    return UnitTest::RunAllTests();
}
<commit_msg>added tests for new function<commit_after>#include "FitsObject.h"
#include <iostream>
#include <UnitTest++/UnitTest++.h>
#include <stdexcept>

using namespace std;

struct DefaultFixture
{
    DefaultFixture()
    {
        f = new Fits("../test.fits");
    }

    ~DefaultFixture()
    {
        delete f;
    }

    Fits *f;
};

struct TableFixture : public DefaultFixture
{
    TableFixture() :
        DefaultFixture()
    {
        f->moveHDU(2);
    }
};

/* Check for a bad filename */
TEST(BadFilename)
{
    CHECK_THROW(Fits test("badfilename"), runtime_error);
}

TEST_FIXTURE(DefaultFixture, BadMoveCheck)
{
    CHECK_THROW(f->moveHDU(-100), runtime_error);

}

TEST_FIXTURE(DefaultFixture, PastFileMoveCheck)
{
    CHECK_THROW(f->moveHDU(100), runtime_error);

}

TEST_FIXTURE(DefaultFixture, BadHDUName)
{
    CHECK_THROW(f->moveHDU("BADHDUNAME"), runtime_error);
}

TEST_FIXTURE(TableFixture, HDUName)
{
    CHECK_EQUAL("TABLE", f->hduname());
}

TEST_FIXTURE(DefaultFixture, BadHDURows)
{
    f->moveHDU(1);
    CHECK_THROW(f->nrows(), runtime_error);
}

TEST_FIXTURE(TableFixture, NRowsTest)
{
    CHECK_EQUAL(3, f->nrows());
}

int main(int argc, const char *argv[])
{
    return UnitTest::RunAllTests();
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include <ObjectXML.h>
#include <stdexcept>
#include <cstring>
#include <iostream>
#include <sstream>
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::ObjectXML(const string &xml_doc):paths(0),num_paths(0),xml(0),ctx(0)
{
    try
    {
        xml_parse(xml_doc);
    }
    catch(runtime_error& re)
    {
        throw;
    }
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::ObjectXML(const xmlNodePtr node):paths(0),num_paths(0),xml(0),ctx(0)
{
    xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));

    if (xml == 0)
    {
        throw("Error allocating XML Document");
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        throw("Unable to create new XPath context");
    }

    xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);

    if (root_node == 0)
    {
        xmlXPathFreeContext(ctx);
        xmlFreeDoc(xml);
        throw("Unable to allocate node");
    }

    xmlDocSetRootElement(xml, root_node);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::~ObjectXML()
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

vector<string> ObjectXML::operator[] (const char * xpath_expr)
{
    xmlXPathObjectPtr obj;
    vector<string>    content;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return content;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    xmlNodePtr    cur;
    xmlChar *     str_ptr;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        str_ptr = xmlNodeGetContent(cur);

        if (str_ptr != 0)
        {
            string element_content = reinterpret_cast<char *>(str_ptr);

            content.push_back(element_content);

            xmlFree(str_ptr);
        }
    }

    xmlXPathFreeObject(obj);

    return content;
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(string& value, const char * xpath_expr, const char * def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if ( values.empty() == true )
    {
        value = def;
        rc    = -1;
    }
    else
    {
        value = values[0];
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(int& value, const char * xpath_expr, const int& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(unsigned int& value, const char * xpath_expr,
                     const unsigned int& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(long long& value, const char * xpath_expr,
                     const long long& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(unsigned long long& value, const char * xpath_expr,
                     const unsigned long long& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(time_t& value, const char * xpath_expr, const time_t& def)
{
    int int_val;
    int int_def = static_cast<time_t>(def);
    int rc;

    rc = xpath(int_val, xpath_expr, int_def);
    value = static_cast<time_t>(int_val);

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath_value(string& value,const char *doc,const char *the_xpath)
{
    int rc = 0;

    try
    {
        ObjectXML      obj(doc);
        vector<string> values;

        values = obj[the_xpath];

        if (values.empty() == true)
        {
            rc = -1;
        }
        else
        {
            value = values[0];
        }
    }
    catch(runtime_error& re)
    {
        rc = -1;
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::get_nodes (const char * xpath_expr, vector<xmlNodePtr>& content)
{
    xmlXPathObjectPtr obj;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return 0;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    int           num_nodes = 0;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = xmlCopyNode(ns->nodeTab[i],1);

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            xmlFreeNode(cur);
            continue;
        }

        content.push_back(cur);
        num_nodes++;
    }

    xmlXPathFreeObject(obj);

    return num_nodes;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::add_node(
        const char *    xpath_expr,
        xmlNodePtr      node,
        const char *    new_name)
{
    xmlXPathObjectPtr obj;
    vector<string>    content;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return -1;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        xmlNodePtr node_cpy = xmlCopyNode(node, 1);

        if (node_cpy == 0)
        {
            xmlXPathFreeObject(obj);

            return -1;
        }

        xmlNodeSetName(node_cpy, reinterpret_cast<const xmlChar *>(new_name));

        xmlNodePtr res = xmlAddChild(cur, node_cpy);

        if (res == 0)
        {
            xmlXPathFreeObject(obj);
            xmlFreeNode(node_cpy);

            return -1;
        }
    }

    xmlXPathFreeObject(obj);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::update_from_str(const string &xml_doc)
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }

    try
    {
        xml_parse(xml_doc);
    }
    catch(runtime_error& re)
    {
        return -1;
    }

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::update_from_node(const xmlNodePtr node)
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }

    xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));

    if (xml == 0)
    {
        return -1;
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        return -1;
    }

    xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);

    if (root_node == 0)
    {
        xmlXPathFreeContext(ctx);
        xmlFreeDoc(xml);
        return -1;
    }

    xmlDocSetRootElement(xml, root_node);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::validate_xml(const string &xml_doc)
{
    xmlDocPtr tmp_xml = 0;
    tmp_xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());

    if (tmp_xml == 0)
    {
        return -1;
    }

    xmlFreeDoc(tmp_xml);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void ObjectXML::xml_parse(const string &xml_doc)
{
    xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());

    if (xml == 0)
    {
        throw runtime_error("Error parsing XML Document");
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        throw runtime_error("Unable to create new XPath context");
    }
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::rename_nodes(const char * xpath_expr, const char * new_name)
{
    xmlXPathObjectPtr obj;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return 0;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    int           renamed = 0;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        xmlNodeSetName(cur, reinterpret_cast<const xmlChar *>(new_name));
        renamed++;
    }

    xmlXPathFreeObject(obj);

    return renamed;
}

/* ************************************************************************ */
/* Host :: Parse functions to compute rank and evaluate requirements        */
/* ************************************************************************ */

extern "C"
{
    typedef struct yy_buffer_state * YY_BUFFER_STATE;

    int expr_bool_parse(ObjectXML * oxml, bool& result, char ** errmsg);

    int expr_arith_parse(ObjectXML * oxml, int& result, char ** errmsg);

    int expr_lex_destroy();

    YY_BUFFER_STATE expr__scan_string(const char * str);

    void expr__delete_buffer(YY_BUFFER_STATE);
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::eval_bool(const string& expr, bool& result, char **errmsg)
{
    YY_BUFFER_STATE     str_buffer = 0;
    const char *        str;
    int                 rc;

    *errmsg = 0;

    str = expr.c_str();

    str_buffer = expr__scan_string(str);

    if (str_buffer == 0)
    {
        goto error_yy;
    }

    rc = expr_bool_parse(this,result,errmsg);

    expr__delete_buffer(str_buffer);

    expr_lex_destroy();

    return rc;

error_yy:

    *errmsg=strdup("Error setting scan buffer");

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::eval_arith(const string& expr, int& result, char **errmsg)
{
    YY_BUFFER_STATE     str_buffer = 0;
    const char *        str;
    int                 rc;

    *errmsg = 0;

    str = expr.c_str();

    str_buffer = expr__scan_string(str);

    if (str_buffer == 0)
    {
        goto error_yy;
    }

    rc = expr_arith_parse(this,result,errmsg);

    expr__delete_buffer(str_buffer);

    expr_lex_destroy();

    return rc;

error_yy:

    *errmsg=strdup("Error setting scan buffer");

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void ObjectXML::search(const char* name, vector<string>& results)
{

    if (name[0] == '/')
    {
        results = (*this)[name];
    }
    else if (num_paths == 0)
    {
        results.clear();
    }
    else
    {
        ostringstream  xpath;

        xpath << paths[0] << name;

        for (int i = 1; i < num_paths ; i++)
        {
            xpath << '|' << paths[i] << name;
        }

        results = (*this)[xpath.str().c_str()];
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, string& value)
{
    vector<string> results;

    value = "";

    search(name, results);

    if (results.size() != 0)
    {
        value = results[0];

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, int& value)
{
    vector<string> results;

    value = 0;

    search(name, results);

    if (results.size() != 0)
    {
        istringstream iss(results[0]);
        iss >> value;

        if (iss.fail())
        {
            value = 0;

            return -1;
        }

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, float& value)
{
    vector<string> results;

    value = 0.0;

    search(name, results);

    if (results.size() != 0)
    {
        istringstream iss(results[0]);
        iss >> value;

        if (iss.fail())
        {
            value = 0;

            return -1;
        }

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
<commit_msg>feature #1712: Fix memory leak<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2013, OpenNebula Project (OpenNebula.org), C12G Labs        */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

#include <ObjectXML.h>
#include <stdexcept>
#include <cstring>
#include <iostream>
#include <sstream>
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::ObjectXML(const string &xml_doc):paths(0),num_paths(0),xml(0),ctx(0)
{
    try
    {
        xml_parse(xml_doc);
    }
    catch(runtime_error& re)
    {
        throw;
    }
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::ObjectXML(const xmlNodePtr node):paths(0),num_paths(0),xml(0),ctx(0)
{
    xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));

    if (xml == 0)
    {
        throw("Error allocating XML Document");
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        throw("Unable to create new XPath context");
    }

    xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);

    if (root_node == 0)
    {
        xmlXPathFreeContext(ctx);
        xmlFreeDoc(xml);
        throw("Unable to allocate node");
    }

    xmlDocSetRootElement(xml, root_node);
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

ObjectXML::~ObjectXML()
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

vector<string> ObjectXML::operator[] (const char * xpath_expr)
{
    xmlXPathObjectPtr obj;
    vector<string>    content;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return content;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    xmlNodePtr    cur;
    xmlChar *     str_ptr;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        str_ptr = xmlNodeGetContent(cur);

        if (str_ptr != 0)
        {
            string element_content = reinterpret_cast<char *>(str_ptr);

            content.push_back(element_content);

            xmlFree(str_ptr);
        }
    }

    xmlXPathFreeObject(obj);

    return content;
};

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(string& value, const char * xpath_expr, const char * def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if ( values.empty() == true )
    {
        value = def;
        rc    = -1;
    }
    else
    {
        value = values[0];
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(int& value, const char * xpath_expr, const int& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(unsigned int& value, const char * xpath_expr,
                     const unsigned int& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(long long& value, const char * xpath_expr,
                     const long long& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(unsigned long long& value, const char * xpath_expr,
                     const unsigned long long& def)
{
    vector<string> values;
    int rc = 0;

    values = (*this)[xpath_expr];

    if (values.empty() == true)
    {
        value = def;
        rc = -1;
    }
    else
    {
        istringstream iss;

        iss.str(values[0]);

        iss >> dec >> value;

        if (iss.fail() == true)
        {
            value = def;
            rc    = -1;
        }
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath(time_t& value, const char * xpath_expr, const time_t& def)
{
    int int_val;
    int int_def = static_cast<time_t>(def);
    int rc;

    rc = xpath(int_val, xpath_expr, int_def);
    value = static_cast<time_t>(int_val);

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::xpath_value(string& value,const char *doc,const char *the_xpath)
{
    int rc = 0;

    try
    {
        ObjectXML      obj(doc);
        vector<string> values;

        values = obj[the_xpath];

        if (values.empty() == true)
        {
            rc = -1;
        }
        else
        {
            value = values[0];
        }
    }
    catch(runtime_error& re)
    {
        rc = -1;
    }

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::get_nodes (const char * xpath_expr, vector<xmlNodePtr>& content)
{
    xmlXPathObjectPtr obj;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0)
    {
        return 0;
    }

    if (obj->nodesetval == 0)
    {
        xmlXPathFreeObject(obj);
        return 0;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    int           num_nodes = 0;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = xmlCopyNode(ns->nodeTab[i],1);

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            xmlFreeNode(cur);
            continue;
        }

        content.push_back(cur);
        num_nodes++;
    }

    xmlXPathFreeObject(obj);

    return num_nodes;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::add_node(
        const char *    xpath_expr,
        xmlNodePtr      node,
        const char *    new_name)
{
    xmlXPathObjectPtr obj;
    vector<string>    content;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return -1;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        xmlNodePtr node_cpy = xmlCopyNode(node, 1);

        if (node_cpy == 0)
        {
            xmlXPathFreeObject(obj);

            return -1;
        }

        xmlNodeSetName(node_cpy, reinterpret_cast<const xmlChar *>(new_name));

        xmlNodePtr res = xmlAddChild(cur, node_cpy);

        if (res == 0)
        {
            xmlXPathFreeObject(obj);
            xmlFreeNode(node_cpy);

            return -1;
        }
    }

    xmlXPathFreeObject(obj);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::update_from_str(const string &xml_doc)
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }

    try
    {
        xml_parse(xml_doc);
    }
    catch(runtime_error& re)
    {
        return -1;
    }

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::update_from_node(const xmlNodePtr node)
{
    if (xml != 0)
    {
        xmlFreeDoc(xml);
    }

    if ( ctx != 0)
    {
        xmlXPathFreeContext(ctx);
    }

    xml = xmlNewDoc(reinterpret_cast<const xmlChar *>("1.0"));

    if (xml == 0)
    {
        return -1;
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        return -1;
    }

    xmlNodePtr root_node = xmlDocCopyNode(node,xml,1);

    if (root_node == 0)
    {
        xmlXPathFreeContext(ctx);
        xmlFreeDoc(xml);
        return -1;
    }

    xmlDocSetRootElement(xml, root_node);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::validate_xml(const string &xml_doc)
{
    xmlDocPtr tmp_xml = 0;
    tmp_xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());

    if (tmp_xml == 0)
    {
        return -1;
    }

    xmlFreeDoc(tmp_xml);

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

void ObjectXML::xml_parse(const string &xml_doc)
{
    xml = xmlParseMemory (xml_doc.c_str(),xml_doc.length());

    if (xml == 0)
    {
        throw runtime_error("Error parsing XML Document");
    }

    ctx = xmlXPathNewContext(xml);

    if (ctx == 0)
    {
        xmlFreeDoc(xml);
        throw runtime_error("Unable to create new XPath context");
    }
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int ObjectXML::rename_nodes(const char * xpath_expr, const char * new_name)
{
    xmlXPathObjectPtr obj;

    obj = xmlXPathEvalExpression(
        reinterpret_cast<const xmlChar *>(xpath_expr), ctx);

    if (obj == 0 || obj->nodesetval == 0)
    {
        return 0;
    }

    xmlNodeSetPtr ns = obj->nodesetval;
    int           size = ns->nodeNr;
    int           renamed = 0;
    xmlNodePtr    cur;

    for(int i = 0; i < size; ++i)
    {
        cur = ns->nodeTab[i];

        if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
        {
            continue;
        }

        xmlNodeSetName(cur, reinterpret_cast<const xmlChar *>(new_name));
        renamed++;
    }

    xmlXPathFreeObject(obj);

    return renamed;
}

/* ************************************************************************ */
/* Host :: Parse functions to compute rank and evaluate requirements        */
/* ************************************************************************ */

extern "C"
{
    typedef struct yy_buffer_state * YY_BUFFER_STATE;

    int expr_bool_parse(ObjectXML * oxml, bool& result, char ** errmsg);

    int expr_arith_parse(ObjectXML * oxml, int& result, char ** errmsg);

    int expr_lex_destroy();

    YY_BUFFER_STATE expr__scan_string(const char * str);

    void expr__delete_buffer(YY_BUFFER_STATE);
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::eval_bool(const string& expr, bool& result, char **errmsg)
{
    YY_BUFFER_STATE     str_buffer = 0;
    const char *        str;
    int                 rc;

    *errmsg = 0;

    str = expr.c_str();

    str_buffer = expr__scan_string(str);

    if (str_buffer == 0)
    {
        goto error_yy;
    }

    rc = expr_bool_parse(this,result,errmsg);

    expr__delete_buffer(str_buffer);

    expr_lex_destroy();

    return rc;

error_yy:

    *errmsg=strdup("Error setting scan buffer");

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::eval_arith(const string& expr, int& result, char **errmsg)
{
    YY_BUFFER_STATE     str_buffer = 0;
    const char *        str;
    int                 rc;

    *errmsg = 0;

    str = expr.c_str();

    str_buffer = expr__scan_string(str);

    if (str_buffer == 0)
    {
        goto error_yy;
    }

    rc = expr_arith_parse(this,result,errmsg);

    expr__delete_buffer(str_buffer);

    expr_lex_destroy();

    return rc;

error_yy:

    *errmsg=strdup("Error setting scan buffer");

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void ObjectXML::search(const char* name, vector<string>& results)
{

    if (name[0] == '/')
    {
        results = (*this)[name];
    }
    else if (num_paths == 0)
    {
        results.clear();
    }
    else
    {
        ostringstream  xpath;

        xpath << paths[0] << name;

        for (int i = 1; i < num_paths ; i++)
        {
            xpath << '|' << paths[i] << name;
        }

        results = (*this)[xpath.str().c_str()];
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, string& value)
{
    vector<string> results;

    value = "";

    search(name, results);

    if (results.size() != 0)
    {
        value = results[0];

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, int& value)
{
    vector<string> results;

    value = 0;

    search(name, results);

    if (results.size() != 0)
    {
        istringstream iss(results[0]);
        iss >> value;

        if (iss.fail())
        {
            value = 0;

            return -1;
        }

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int ObjectXML::search(const char *name, float& value)
{
    vector<string> results;

    value = 0.0;

    search(name, results);

    if (results.size() != 0)
    {
        istringstream iss(results[0]);
        iss >> value;

        if (iss.fail())
        {
            value = 0;

            return -1;
        }

        return 0;
    }

    return -1;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <time.h>
#include "util.h"

#if defined _POSIX_SOURCE
#include <unistd.h> // Microsoft Visual C++ do not has this header
#endif

#if defined WIN32
#include <windows.h> // POSIX-only environment do not has this header
#endif

namespace util{

#if defined _POSIX_SOURCE
	void milliSleep(int ms) {
		timespec ts;
		ts.tv_sec = ms / 1000;
		ts.tv_nsec = (ms % 1000) * 1000000L;
		nanosleep(&ts, NULL);
	}
#endif

#if defined WIN32
	void milliSleep(int ms) {
		sleep(ms);
	}
#endif

	int random(int range) {
		return rand() % range;
	}

	bool operator == (const point a, const point b) {
		return a.x == b.x && a.y == b.y;
	}

	bool operator != (const point a, const point b) {
		return !(a == b);
	}

	point operator - (const point a) {
		return point(-a.x, -a.y);
	}

	point operator + (const point a, const point b) {
		return point(a.x + b.x, a.y + b.y);
	}

	point &operator += (point &a, const point b) {
		a.x += b.x;
		a.y += b.y;
		return a;
	}

	point operator - (const point a, const point b) {
		return a + (-b);
	}

}
<commit_msg>lib: remove unused sleep code<commit_after>#include <stdlib.h>
#include <time.h>
#include "util.h"

#if defined _POSIX_SOURCE
#include <unistd.h> // Microsoft Visual C++ do not has this header
#endif

#if defined WIN32
#include <windows.h> // POSIX-only environment do not has this header
#endif

namespace util{

	int random(int range) {
		return rand() % range;
	}

	bool operator == (const point a, const point b) {
		return a.x == b.x && a.y == b.y;
	}

	bool operator != (const point a, const point b) {
		return !(a == b);
	}

	point operator - (const point a) {
		return point(-a.x, -a.y);
	}

	point operator + (const point a, const point b) {
		return point(a.x + b.x, a.y + b.y);
	}

	point &operator += (point &a, const point b) {
		a.x += b.x;
		a.y += b.y;
		return a;
	}

	point operator - (const point a, const point b) {
		return a + (-b);
	}

}
<|endoftext|>


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

 #include <assert.h>
 #include <stddef.h>

/*
 * The algorithm below is based on paper
 * Cache-Oblivious Peeling of Random Hypergraphs by Djamal Belazzougui,
 * Paolo Boldi, Giuseppe Ottaviano, Rossano Venturini, and Sebastiano
 * Vigna.
 * http://zola.di.unipi.it/rossano/wp-content/papercite-data/pdf/dcc14.pdf
 */
namespace {

template<class T, int R>
struct edge {
	T verts[R];
	T idx; // XXX
};

/*
 * Data type for a valid oriented edge (v0, v1, v2), v1 < v2.
 * The first vertex v0 is implicit and is determined by an index
 * of the corresponding element in the state->oedges array.
 * If the degree of v0 is greater than 1, other members don't make
 * sense because they're a result of XORing multiple random values.
 */
template<class T, int R>
struct oedge {
	T verts[R-1]; // v1 (and v2, if R==3).
	T degree;     // Degree of v0.
	T edge;
};

template<class T>
inline void
add_remove_edge(oedge<T,2> *oedges, int delta, T e, const T *verts)
{
	const T v0 = verts[0];
	const T v1 = verts[1];

	oedges[v0].verts[0] ^= v1;
	oedges[v0].degree += delta;
	oedges[v0].edge ^= e;
}

template<class T>
inline void
remove_edge(oedge<T,2> *oedges, T e, T v0, T v1)
{
	const T verts[2] = { v0, v1 };

	return add_remove_edge(oedges, -1, e, verts);
}

template<class T>
inline void
add_remove_edge(oedge<T,3> *oedges, int delta, T e, const T *verts)
{
	const T v0 = verts[0];
	const T v1 = verts[1];
	const T v2 = verts[2];

	oedges[v0].verts[v1 < v2 ? 0 : 1] ^= v1;
	oedges[v0].verts[v1 < v2 ? 1 : 0] ^= v2;
	oedges[v0].degree += delta;
	oedges[v0].edge ^= e;
}

template<class T>
inline void
remove_edge(oedge<T,3> *oedges, T e, T v0, T v1, T v2)
{
	const T verts[3] = { v0, v1, v2 };

	return add_remove_edge(oedges, -1, e, verts);
}

template<class T, int R>
inline void
add_edge(oedge<T,R> *oedges, T e, const T *verts)
{

	return add_remove_edge(oedges, 1, e, verts);
}

template<class T>
inline size_t
remove_vertex(oedge<T,2> *oedges, T v0, T *order, size_t end)
{

	if (oedges[v0].degree == 1) {
		const T e = oedges[v0].edge;
		const T v1 = oedges[v0].verts[0];
		oedges[v0].degree = 0;
		remove_edge(oedges, e, v1, v0);
		order[--end] = e;
	}

	return end;
}

template<class T>
inline size_t
remove_vertex(oedge<T,3> *oedges, T v0, T *order, size_t end)
{

	if (oedges[v0].degree == 1) {
		const T e = oedges[v0].edge;
		const T v1 = oedges[v0].verts[0];
		const T v2 = oedges[v0].verts[1];
		oedges[v0].degree = 0;
		remove_edge(oedges, e, v1, v0, v2);
		remove_edge(oedges, e, v2, v0, v1);
		order[--end] = e;
	}

	return end;
}

template<class Iter, class Hash, class T, int R>
void
build_graph(Iter keys, size_t nkeys, Hash hash, size_t nverts,
    edge<T,R> *edges, oedge<T,R> *oedges)
{
	// Partition size of an R-partite R-graph.
	const T partsz = nverts / R;
	assert(partsz > 1 && (nverts % R) == 0);

	for (size_t i = 0; i < nkeys; ++i, ++keys) {
		const T *verts = hash(keys->key, keys->keylen);
		for (size_t r = 0; r < R; ++r)
			edges[i].verts[r] = (verts[r] % partsz) + r * partsz;
		for (size_t r = 0; r < R; ++r)
			add_edge(oedges, i, edges[i].verts);
	}
}

template<class T, int R>
size_t
peel_graph(edge<T,R> *edges, size_t nkeys,
    oedge<T,R> *oedges, size_t nverts, T *order)
{
	size_t end = nkeys;

	for (size_t i = 0; i < nkeys; ++i)
		end = remove_vertex(oedges, i, order, end);

	for (size_t i = nkeys; i > 0 && i > end; --i) {
		const edge<T,R> *e = edges[order[i-1]];
		for (size_t r = 0; r < R; ++r)
			end = remove_vertex(oedges, e->verts[r], order, end);
	}

	return end;
}

} // namespace
<commit_msg>Don't say anything about unknown "state" object.<commit_after>/*-
 * Copyright (c) 2015 Alexander Nasonov.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

 #include <assert.h>
 #include <stddef.h>

/*
 * The algorithm below is based on paper
 * Cache-Oblivious Peeling of Random Hypergraphs by Djamal Belazzougui,
 * Paolo Boldi, Giuseppe Ottaviano, Rossano Venturini, and Sebastiano
 * Vigna.
 * http://zola.di.unipi.it/rossano/wp-content/papercite-data/pdf/dcc14.pdf
 */
namespace {

template<class T, int R>
struct edge {
	T verts[R];
	T idx; // XXX
};

/*
 * Data type for a valid oriented edge (v0, v1, v2), v1 < v2.
 * The first vertex v0 is implicit and is determined by an index
 * of the corresponding element in the oedges array.
 * If the degree of v0 is greater than 1, other members don't make
 * sense because they're a result of XORing multiple random values.
 */
template<class T, int R>
struct oedge {
	T verts[R-1]; // v1 (and v2, if R==3).
	T degree;     // Degree of v0.
	T edge;
};

template<class T>
inline void
add_remove_edge(oedge<T,2> *oedges, int delta, T e, const T *verts)
{
	const T v0 = verts[0];
	const T v1 = verts[1];

	oedges[v0].verts[0] ^= v1;
	oedges[v0].degree += delta;
	oedges[v0].edge ^= e;
}

template<class T>
inline void
remove_edge(oedge<T,2> *oedges, T e, T v0, T v1)
{
	const T verts[2] = { v0, v1 };

	return add_remove_edge(oedges, -1, e, verts);
}

template<class T>
inline void
add_remove_edge(oedge<T,3> *oedges, int delta, T e, const T *verts)
{
	const T v0 = verts[0];
	const T v1 = verts[1];
	const T v2 = verts[2];

	oedges[v0].verts[v1 < v2 ? 0 : 1] ^= v1;
	oedges[v0].verts[v1 < v2 ? 1 : 0] ^= v2;
	oedges[v0].degree += delta;
	oedges[v0].edge ^= e;
}

template<class T>
inline void
remove_edge(oedge<T,3> *oedges, T e, T v0, T v1, T v2)
{
	const T verts[3] = { v0, v1, v2 };

	return add_remove_edge(oedges, -1, e, verts);
}

template<class T, int R>
inline void
add_edge(oedge<T,R> *oedges, T e, const T *verts)
{

	return add_remove_edge(oedges, 1, e, verts);
}

template<class T>
inline size_t
remove_vertex(oedge<T,2> *oedges, T v0, T *order, size_t end)
{

	if (oedges[v0].degree == 1) {
		const T e = oedges[v0].edge;
		const T v1 = oedges[v0].verts[0];
		oedges[v0].degree = 0;
		remove_edge(oedges, e, v1, v0);
		order[--end] = e;
	}

	return end;
}

template<class T>
inline size_t
remove_vertex(oedge<T,3> *oedges, T v0, T *order, size_t end)
{

	if (oedges[v0].degree == 1) {
		const T e = oedges[v0].edge;
		const T v1 = oedges[v0].verts[0];
		const T v2 = oedges[v0].verts[1];
		oedges[v0].degree = 0;
		remove_edge(oedges, e, v1, v0, v2);
		remove_edge(oedges, e, v2, v0, v1);
		order[--end] = e;
	}

	return end;
}

template<class Iter, class Hash, class T, int R>
void
build_graph(Iter keys, size_t nkeys, Hash hash, size_t nverts,
    edge<T,R> *edges, oedge<T,R> *oedges)
{
	// Partition size of an R-partite R-graph.
	const T partsz = nverts / R;
	assert(partsz > 1 && (nverts % R) == 0);

	for (size_t i = 0; i < nkeys; ++i, ++keys) {
		const T *verts = hash(keys->key, keys->keylen);
		for (size_t r = 0; r < R; ++r)
			edges[i].verts[r] = (verts[r] % partsz) + r * partsz;
		for (size_t r = 0; r < R; ++r)
			add_edge(oedges, i, edges[i].verts);
	}
}

template<class T, int R>
size_t
peel_graph(edge<T,R> *edges, size_t nkeys,
    oedge<T,R> *oedges, size_t nverts, T *order)
{
	size_t end = nkeys;

	for (size_t i = 0; i < nkeys; ++i)
		end = remove_vertex(oedges, i, order, end);

	for (size_t i = nkeys; i > 0 && i > end; --i) {
		const edge<T,R> *e = edges[order[i-1]];
		for (size_t r = 0; r < R; ++r)
			end = remove_vertex(oedges, e->verts[r], order, end);
	}

	return end;
}

} // namespace
<|endoftext|>


<commit_before>// -*- mode: c++ -*-

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

// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>

// Implementation of google_breakpad::DwarfCFIToModule.
// See dwarf_cfi_to_module.h for details.

#include <sstream>

#include "common/dwarf_cfi_to_module.h"

namespace google_breakpad {

using std::ostringstream;

vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
    const char * const *strings,
    size_t size) {
  vector<string> names(strings, strings + size);
  return names;
}

vector<string> DwarfCFIToModule::RegisterNames::I386() {
  static const char *const names[] = {
    "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
    "$eip", "$eflags", "$unused1",
    "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
    "$unused2", "$unused3",
    "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
    "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
    "$fcw", "$fsw", "$mxcsr",
    "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
    "$tr", "$ldtr"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
  static const char *const names[] = {
    "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
    "$r8",  "$r9",  "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
    "$rip",
    "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
    "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
    "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
    "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
    "$rflags",
    "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
    "$fs.base", "$gs.base", "$unused3", "$unused4",
    "$tr", "$ldtr",
    "$mxcsr", "$fcw", "$fsw"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

vector<string> DwarfCFIToModule::RegisterNames::ARM() {
  static const char *const names[] = {
    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
    "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
    "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
    "fps", "cpsr"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
                             uint8 version, const string &augmentation,
                             unsigned return_address) {
  assert(!entry_);

  // If dwarf2reader::CallFrameInfo can handle this version and
  // augmentation, then we should be okay with that, so there's no
  // need to check them here.

  // Get ready to collect entries.
  entry_ = new Module::StackFrameEntry;
  entry_->address = address;
  entry_->size = length;
  entry_offset_ = offset;
  return_address_ = return_address;

  // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
  // may not establish any rule for .ra if the return address column
  // is an ordinary register, and that register holds the return
  // address on entry to the function. So establish an initial .ra
  // rule citing the return address register.
  if (return_address_ < register_names_.size())
    entry_->initial_rules[ra_name_] = register_names_[return_address_];

  return true;
}

string DwarfCFIToModule::RegisterName(int i) {
  assert(entry_);
  if (i < 0) {
    assert(i == kCFARegister);
    return cfa_name_;
  }
  unsigned reg = i;
  if (reg == return_address_)
    return ra_name_;

  if (0 <= reg && reg < register_names_.size())
    return register_names_[reg];

  reporter_->UnnamedRegister(entry_offset_, reg);
  char buf[30];
  sprintf(buf, "unnamed_register%u", reg);
  return buf;
}

void DwarfCFIToModule::Record(Module::Address address, int reg,
                              const string &rule) {
  assert(entry_);

  // Place the name in our global set of strings, and then use the string
  // from the set. Even though the assignment looks like a copy, all the
  // major std::string implementations use reference counting internally,
  // so the effect is to have all our data structures share copies of rules
  // whenever possible. Since register names are drawn from a
  // vector<string>, register names are already shared.
  string shared_rule = *common_strings_.insert(rule).first;

  // Is this one of this entry's initial rules?
  if (address == entry_->address)
    entry_->initial_rules[RegisterName(reg)] = shared_rule;
  // File it under the appropriate address.
  else
    entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
}

bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
  reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
  ostringstream s;
  s << RegisterName(reg);
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
                                  int base_register, long offset) {
  ostringstream s;
  s << RegisterName(base_register) << " " << offset << " + ^";
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
                                     int base_register, long offset) {
  ostringstream s;
  s << RegisterName(base_register) << " " << offset << " +";
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
                                    int base_register) {
  ostringstream s;
  s << RegisterName(base_register);
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
                                      const string &expression) {
  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
                                         const string &expression) {
  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::End() {
  module_->AddStackFrameEntry(entry_);
  entry_ = NULL;
  return true;
}

void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx refers to register %d,"
          " whose name we don't know\n",
          file_.c_str(), section_.c_str(), offset, reg);
}

void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
                                                       const string &reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx sets the rule for "
          "register '%s' to 'undefined', but the Breakpad symbol file format"
          " cannot express this\n",
          file_.c_str(), section_.c_str(), offset, reg.c_str());
}

void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
                                                         const string &reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx uses a DWARF expression to"
          " describe how to recover register '%s', "
          " but this translator cannot yet translate DWARF expressions to"
          " Breakpad postfix expressions\n",
          file_.c_str(), section_.c_str(), offset, reg.c_str());
}

} // namespace google_breakpad
<commit_msg>Fix harmless warning in dwarf_cfi_to_module.cc.<commit_after>// -*- mode: c++ -*-

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

// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>

// Implementation of google_breakpad::DwarfCFIToModule.
// See dwarf_cfi_to_module.h for details.

#include <sstream>

#include "common/dwarf_cfi_to_module.h"

namespace google_breakpad {

using std::ostringstream;

vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
    const char * const *strings,
    size_t size) {
  vector<string> names(strings, strings + size);
  return names;
}

vector<string> DwarfCFIToModule::RegisterNames::I386() {
  static const char *const names[] = {
    "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
    "$eip", "$eflags", "$unused1",
    "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
    "$unused2", "$unused3",
    "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
    "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
    "$fcw", "$fsw", "$mxcsr",
    "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
    "$tr", "$ldtr"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
  static const char *const names[] = {
    "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
    "$r8",  "$r9",  "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
    "$rip",
    "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
    "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
    "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
    "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
    "$rflags",
    "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
    "$fs.base", "$gs.base", "$unused3", "$unused4",
    "$tr", "$ldtr",
    "$mxcsr", "$fcw", "$fsw"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

vector<string> DwarfCFIToModule::RegisterNames::ARM() {
  static const char *const names[] = {
    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
    "r8",  "r9",  "r10", "r11", "r12", "sp",  "lr",  "pc",
    "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
    "fps", "cpsr"
  };

  return MakeVector(names, sizeof(names) / sizeof(names[0]));
}

bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length,
                             uint8 version, const string &augmentation,
                             unsigned return_address) {
  assert(!entry_);

  // If dwarf2reader::CallFrameInfo can handle this version and
  // augmentation, then we should be okay with that, so there's no
  // need to check them here.

  // Get ready to collect entries.
  entry_ = new Module::StackFrameEntry;
  entry_->address = address;
  entry_->size = length;
  entry_offset_ = offset;
  return_address_ = return_address;

  // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
  // may not establish any rule for .ra if the return address column
  // is an ordinary register, and that register holds the return
  // address on entry to the function. So establish an initial .ra
  // rule citing the return address register.
  if (return_address_ < register_names_.size())
    entry_->initial_rules[ra_name_] = register_names_[return_address_];

  return true;
}

string DwarfCFIToModule::RegisterName(int i) {
  assert(entry_);
  if (i < 0) {
    assert(i == kCFARegister);
    return cfa_name_;
  }
  unsigned reg = i;
  if (reg == return_address_)
    return ra_name_;

  if (reg < register_names_.size())
    return register_names_[reg];

  reporter_->UnnamedRegister(entry_offset_, reg);
  char buf[30];
  sprintf(buf, "unnamed_register%u", reg);
  return buf;
}

void DwarfCFIToModule::Record(Module::Address address, int reg,
                              const string &rule) {
  assert(entry_);

  // Place the name in our global set of strings, and then use the string
  // from the set. Even though the assignment looks like a copy, all the
  // major std::string implementations use reference counting internally,
  // so the effect is to have all our data structures share copies of rules
  // whenever possible. Since register names are drawn from a
  // vector<string>, register names are already shared.
  string shared_rule = *common_strings_.insert(rule).first;

  // Is this one of this entry's initial rules?
  if (address == entry_->address)
    entry_->initial_rules[RegisterName(reg)] = shared_rule;
  // File it under the appropriate address.
  else
    entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
}

bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) {
  reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) {
  ostringstream s;
  s << RegisterName(reg);
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::OffsetRule(uint64 address, int reg,
                                  int base_register, long offset) {
  ostringstream s;
  s << RegisterName(base_register) << " " << offset << " + ^";
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg,
                                     int base_register, long offset) {
  ostringstream s;
  s << RegisterName(base_register) << " " << offset << " +";
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::RegisterRule(uint64 address, int reg,
                                    int base_register) {
  ostringstream s;
  s << RegisterName(base_register);
  Record(address, reg, s.str());
  return true;
}

bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg,
                                      const string &expression) {
  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg,
                                         const string &expression) {
  reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
  // Treat this as a non-fatal error.
  return true;
}

bool DwarfCFIToModule::End() {
  module_->AddStackFrameEntry(entry_);
  entry_ = NULL;
  return true;
}

void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx refers to register %d,"
          " whose name we don't know\n",
          file_.c_str(), section_.c_str(), offset, reg);
}

void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
                                                       const string &reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx sets the rule for "
          "register '%s' to 'undefined', but the Breakpad symbol file format"
          " cannot express this\n",
          file_.c_str(), section_.c_str(), offset, reg.c_str());
}

void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
                                                         const string &reg) {
  fprintf(stderr, "%s, section '%s': "
          "the call frame entry at offset 0x%zx uses a DWARF expression to"
          " describe how to recover register '%s', "
          " but this translator cannot yet translate DWARF expressions to"
          " Breakpad postfix expressions\n",
          file_.c_str(), section_.c_str(), offset, reg.c_str());
}

} // namespace google_breakpad
<|endoftext|>


<commit_before>#include "acsetup.hpp"
#include "python_server.hpp"

#include <stdexcept>
#include <signal.h>
#include <boost/python/errors.hpp>

#include "xiva/message.hpp"

#include "details/channels_stat_impl.hpp"
#include "details/server_impl.hpp"

#include "server_class.hpp"
#include "python_logger.hpp"
#include "python_handler.hpp"
#include "python_listener.hpp"
#include "python_message_filter.hpp"
#include "python_settings.hpp"
#include "python_ping_formatter.hpp"
#include "python_formatter_creator.hpp"
#include "interpreter_lock.hpp"

namespace xiva { namespace python {

python_server::python_server() :
	impl_(new details::server_impl())
{
	signal(SIGPIPE, SIG_IGN);
}

python_server::~python_server() {
}

void
python_server::stop() {
	try {
		if (impl_) {
			impl_.reset();
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::init(py::object const &impl) {
	try {
		check_server();
		python_settings settings(impl);
		interpreter_thread_lock thread_lock;
		impl_->init(settings);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::list_channels_enable() {
	try {
		check_server();
		channels_stat_ = impl_->init_channels_stat();
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::start() {
	try {
		check_server();
		{
			interpreter_thread_lock thread_lock;
			cleanup_list_auto cleanup_auto(cleanup_);
			logger_->start();
			impl_->start();
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

py::list
python_server::list_channels() const {

	py::list result;
	try {
		if (channels_stat_) {
			//interpreter_unlock unlock;
			enumeration<std::string>::ptr_type en = channels_stat_->load_names();
			while (!en->empty()) {
				result.append(en->next());
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
	return result;
}

py::list
python_server::list_channel(std::string const &channel_name) const {

	py::list result;
	try {
		if (channels_stat_) {
			//interpreter_unlock unlock;
			enumeration<std::string>::ptr_type en = channels_stat_->load_keys(channel_name);
			while (!en->empty()) {
				result.append(en->next());
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
	return result;
}

void
python_server::send(std::string const &to, std::string const &msg) {

	try {
		if (impl_) {
			//interpreter_unlock unlock;
			boost::shared_ptr<message> m(new message(msg));
			impl_->send(to, m);
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::send_to_channel(
		std::string const &to, std::string const &msg,
		std::string const &channel_name, std::string const &channel_key, std::string const &channel_data) {

	try {
		if (impl_) {
			//interpreter_unlock unlock;
			boost::shared_ptr<message> m(new message(msg));
			channel_info ch_info(channel_name, channel_key, channel_data);
			if (!ch_info.empty()) {
				m->set_channel_info(ch_info);
				impl_->send(to, m);
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

//void
//python_server::load(std::string const &name) {
//	(void) name;
//}

void
python_server::attach_logger(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<python_logger> l(new python_logger(impl));
		impl_->attach_logger(l);
		logger_ = l;
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_response_handler(py::object const &impl) {
	try {
		check_server();
		boost::intrusive_ptr<response_handler> m(new python_handler(impl));
		impl_->attach_response_handler(m);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_ping_formatter(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<ping_formatter> f(new python_ping_formatter(impl, cleanup_));
		impl_->attach_ping_formatter(f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_formatter_creator(std::string const &fmt_id, py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<formatter_creator> f(new python_formatter_creator(impl, cleanup_));
		impl_->attach_formatter_creator(fmt_id, f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::add_connection_listener(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<connection_listener> l(new python_listener(impl));
		impl_->add_connection_listener(l);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_message_filter(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<message_filter> f(new python_message_filter(impl));
		impl_->attach_message_filter(f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::check_server() const {
	if (!impl_) {
		throw std::runtime_error("server already stopped");
	}
}

void
register_server_class() throw () {
	py::class_<python_server, py::bases<>, boost::shared_ptr<python_server>, boost::noncopyable> reg("server", py::init<>());
	reg.def("stop", &python_server::stop);
	//reg.def("load", &python_server::load);
	reg.def("init", &python_server::init);
	reg.def("send", &python_server::send);
	reg.def("send_to_channel", &python_server::send_to_channel);
	reg.def("start", &python_server::start);
	reg.def("attach_logger", &python_server::attach_logger);
	reg.def("add_connection_listener", &python_server::add_connection_listener);
	reg.def("attach_response_handler", &python_server::attach_response_handler);
	reg.def("attach_ping_formatter", &python_server::attach_ping_formatter);
	reg.def("attach_formatter_creator", &python_server::attach_formatter_creator);
	reg.def("attach_message_filter", &python_server::attach_message_filter);
	reg.def("list_channels_enable", &python_server::list_channels_enable);
	reg.def("list_channels", &python_server::list_channels);
	reg.def("list_channel", &python_server::list_channel);
}

}} // namespaces
<commit_msg>removed dead lock on stop server<commit_after>#include "acsetup.hpp"
#include "python_server.hpp"

#include <stdexcept>
#include <signal.h>
#include <boost/python/errors.hpp>

#include "xiva/message.hpp"

#include "details/channels_stat_impl.hpp"
#include "details/server_impl.hpp"

#include "server_class.hpp"
#include "python_logger.hpp"
#include "python_handler.hpp"
#include "python_listener.hpp"
#include "python_message_filter.hpp"
#include "python_settings.hpp"
#include "python_ping_formatter.hpp"
#include "python_formatter_creator.hpp"
#include "interpreter_lock.hpp"

namespace xiva { namespace python {

python_server::python_server() :
	impl_(new details::server_impl())
{
	signal(SIGPIPE, SIG_IGN);
}

python_server::~python_server() {
}

void
python_server::stop() {
	try {
		if (impl_) {
			boost::shared_ptr<details::server_impl> impl(impl_);
			impl_.reset();
			{
				interpreter_unlock unlock;
				impl->stop();
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::init(py::object const &impl) {
	try {
		check_server();
		python_settings settings(impl);
		interpreter_thread_lock thread_lock;
		impl_->init(settings);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::list_channels_enable() {
	try {
		check_server();
		channels_stat_ = impl_->init_channels_stat();
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::start() {
	try {
		check_server();
		{
			interpreter_thread_lock thread_lock;
			cleanup_list_auto cleanup_auto(cleanup_);
			logger_->start();
			impl_->start();
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

py::list
python_server::list_channels() const {

	py::list result;
	try {
		if (channels_stat_) {
			//interpreter_unlock unlock;
			enumeration<std::string>::ptr_type en = channels_stat_->load_names();
			while (!en->empty()) {
				result.append(en->next());
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
	return result;
}

py::list
python_server::list_channel(std::string const &channel_name) const {

	py::list result;
	try {
		if (channels_stat_) {
			//interpreter_unlock unlock;
			enumeration<std::string>::ptr_type en = channels_stat_->load_keys(channel_name);
			while (!en->empty()) {
				result.append(en->next());
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
	return result;
}

void
python_server::send(std::string const &to, std::string const &msg) {

	try {
		if (impl_) {
			//interpreter_unlock unlock;
			boost::shared_ptr<message> m(new message(msg));
			impl_->send(to, m);
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::send_to_channel(
		std::string const &to, std::string const &msg,
		std::string const &channel_name, std::string const &channel_key, std::string const &channel_data) {

	try {
		if (impl_) {
			//interpreter_unlock unlock;
			boost::shared_ptr<message> m(new message(msg));
			channel_info ch_info(channel_name, channel_key, channel_data);
			if (!ch_info.empty()) {
				m->set_channel_info(ch_info);
				impl_->send(to, m);
			}
		}
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

//void
//python_server::load(std::string const &name) {
//	(void) name;
//}

void
python_server::attach_logger(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<python_logger> l(new python_logger(impl));
		impl_->attach_logger(l);
		logger_ = l;
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_response_handler(py::object const &impl) {
	try {
		check_server();
		boost::intrusive_ptr<response_handler> m(new python_handler(impl));
		impl_->attach_response_handler(m);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_ping_formatter(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<ping_formatter> f(new python_ping_formatter(impl, cleanup_));
		impl_->attach_ping_formatter(f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_formatter_creator(std::string const &fmt_id, py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<formatter_creator> f(new python_formatter_creator(impl, cleanup_));
		impl_->attach_formatter_creator(fmt_id, f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::add_connection_listener(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<connection_listener> l(new python_listener(impl));
		impl_->add_connection_listener(l);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::attach_message_filter(py::object const &impl) {

	try {
		check_server();
		boost::intrusive_ptr<message_filter> f(new python_message_filter(impl));
		impl_->attach_message_filter(f);
	}
	catch (std::exception const &e) {
		PyErr_SetString(PyExc_RuntimeError, e.what());
		boost::python::throw_error_already_set();
	}
}

void
python_server::check_server() const {
	if (!impl_) {
		throw std::runtime_error("server already stopped");
	}
}

void
register_server_class() throw () {
	py::class_<python_server, py::bases<>, boost::shared_ptr<python_server>, boost::noncopyable> reg("server", py::init<>());
	reg.def("stop", &python_server::stop);
	//reg.def("load", &python_server::load);
	reg.def("init", &python_server::init);
	reg.def("send", &python_server::send);
	reg.def("send_to_channel", &python_server::send_to_channel);
	reg.def("start", &python_server::start);
	reg.def("attach_logger", &python_server::attach_logger);
	reg.def("add_connection_listener", &python_server::add_connection_listener);
	reg.def("attach_response_handler", &python_server::attach_response_handler);
	reg.def("attach_ping_formatter", &python_server::attach_ping_formatter);
	reg.def("attach_formatter_creator", &python_server::attach_formatter_creator);
	reg.def("attach_message_filter", &python_server::attach_message_filter);
	reg.def("list_channels_enable", &python_server::list_channels_enable);
	reg.def("list_channels", &python_server::list_channels);
	reg.def("list_channel", &python_server::list_channel);
}

}} // namespaces
<|endoftext|>