<commit_before>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2012  Sandro Santilli <strk@kbt.io>
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * NOTE: this is not in JTS. JTS has a snapround/GeometryNoder though
 *
 **********************************************************************/

#include <geos/noding/GeometryNoder.h>
#include <geos/noding/SegmentString.h>
#include <geos/noding/NodedSegmentString.h>
#include <geos/noding/OrientedCoordinateArray.h>
#include <geos/noding/Noder.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/LineString.h>

#include <geos/noding/IteratedNoder.h>

#include <geos/algorithm/LineIntersector.h>
#include <geos/noding/IntersectionAdder.h>
#include <geos/noding/MCIndexNoder.h>

#include <geos/noding/snapround/SimpleSnapRounder.h>
#include <geos/noding/snapround/MCIndexSnapRounder.h>

#include <memory> // for unique_ptr
#include <iostream>

namespace geos {
namespace noding { // geos.noding

namespace {

/**
 * Add every linear element in a geometry into SegmentString vector
 */
class SegmentStringExtractor: public geom::GeometryComponentFilter {
public:
    SegmentStringExtractor(SegmentString::NonConstVect& to)
        : _to(to)
    {}

    void
    filter_ro(const geom::Geometry* g) override
    {
        const geom::LineString* ls = dynamic_cast<const geom::LineString*>(g);
        if(ls) {
            auto coord = ls->getCoordinates();
            // coord ownership transferred to SegmentString
            SegmentString* ss = new NodedSegmentString(coord.release(), nullptr);
            _to.push_back(ss);
        }
    }
private:
    SegmentString::NonConstVect& _to;

    SegmentStringExtractor(SegmentStringExtractor const&); /*= delete*/
    SegmentStringExtractor& operator=(SegmentStringExtractor const&); /*= delete*/
};

}

/* public static */
std::unique_ptr<geom::Geometry>
GeometryNoder::node(const geom::Geometry& geom)
{
    GeometryNoder noder(geom);
    return noder.getNoded();
}

/* public */
GeometryNoder::GeometryNoder(const geom::Geometry& g)
    :
    argGeom(g)
{
}

/* private */
std::unique_ptr<geom::Geometry>
GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges)
{
    const geom::GeometryFactory* geomFact = argGeom.getFactory();

    std::set< OrientedCoordinateArray > ocas;

    // Create a geometry out of the noded substrings.
    std::vector< geom::Geometry* >* lines = new std::vector< geom::Geometry* >();
    lines->reserve(nodedEdges.size());
    for(auto& ss :  nodedEdges) {
        const geom::CoordinateSequence* coords = ss->getCoordinates();

        // Check if an equivalent edge is known
        OrientedCoordinateArray oca1(*coords);
        if(ocas.insert(oca1).second) {
            geom::Geometry* tmp = geomFact->createLineString(coords->clone().release());
            lines->push_back(tmp);
        }
    }

    std::unique_ptr<geom::Geometry> noded(geomFact->createMultiLineString(lines));

    return noded;
}

/* public */
std::unique_ptr<geom::Geometry>
GeometryNoder::getNoded()
{
    SegmentString::NonConstVect p_lineList;
    extractSegmentStrings(argGeom, p_lineList);

    Noder& p_noder = getNoder();
    SegmentString::NonConstVect* nodedEdges = nullptr;

    try {
        p_noder.computeNodes(&p_lineList);
        nodedEdges = p_noder.getNodedSubstrings();
    }
    catch(const std::exception&) {
        for(size_t i = 0, n = p_lineList.size(); i < n; ++i) {
            delete p_lineList[i];
        }
        throw;
    }

    std::unique_ptr<geom::Geometry> noded = toGeometry(*nodedEdges);

    for(auto& elem : (*nodedEdges)) {
        delete elem;
    }
    delete nodedEdges;

    for(auto& elem : p_lineList) {
        delete elem;
    }

    return noded;
}

/* private static */
void
GeometryNoder::extractSegmentStrings(const geom::Geometry& g,
                                     SegmentString::NonConstVect& to)
{
    SegmentStringExtractor ex(to);
    g.apply_ro(&ex);
}

/* private */
Noder&
GeometryNoder::getNoder()
{
    if(! noder.get()) {
        const geom::PrecisionModel* pm = argGeom.getFactory()->getPrecisionModel();
#if 0
        using algorithm::LineIntersector;
        LineIntersector li;
        IntersectionAdder intersectionAdder(li);
        noder.reset(new MCIndexNoder(&intersectionAdder));
#else

        IteratedNoder* in = new IteratedNoder(pm);
        //in->setMaximumIterations(0);
        noder.reset(in);

        //using snapround::SimpleSnapRounder;
        //noder.reset( new SimpleSnapRounder(*pm) );

        //using snapround::MCIndexSnapRounder;
        //noder.reset( new MCIndexSnapRounder(*pm) );
#endif
    }
    return *noder;

}

} // namespace geos.noding
} // namespace geos
<commit_msg>Avoid heap alloc in GeometryNoder::toGeometry<commit_after>/**********************************************************************
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.osgeo.org
 *
 * Copyright (C) 2012  Sandro Santilli <strk@kbt.io>
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************
 *
 * NOTE: this is not in JTS. JTS has a snapround/GeometryNoder though
 *
 **********************************************************************/

#include <geos/noding/GeometryNoder.h>
#include <geos/noding/SegmentString.h>
#include <geos/noding/NodedSegmentString.h>
#include <geos/noding/OrientedCoordinateArray.h>
#include <geos/noding/Noder.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/PrecisionModel.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/GeometryFactory.h>
#include <geos/geom/LineString.h>

#include <geos/noding/IteratedNoder.h>

#include <geos/algorithm/LineIntersector.h>
#include <geos/noding/IntersectionAdder.h>
#include <geos/noding/MCIndexNoder.h>

#include <geos/noding/snapround/SimpleSnapRounder.h>
#include <geos/noding/snapround/MCIndexSnapRounder.h>

#include <memory> // for unique_ptr
#include <iostream>

namespace geos {
namespace noding { // geos.noding

namespace {

/**
 * Add every linear element in a geometry into SegmentString vector
 */
class SegmentStringExtractor: public geom::GeometryComponentFilter {
public:
    SegmentStringExtractor(SegmentString::NonConstVect& to)
        : _to(to)
    {}

    void
    filter_ro(const geom::Geometry* g) override
    {
        const geom::LineString* ls = dynamic_cast<const geom::LineString*>(g);
        if(ls) {
            auto coord = ls->getCoordinates();
            // coord ownership transferred to SegmentString
            SegmentString* ss = new NodedSegmentString(coord.release(), nullptr);
            _to.push_back(ss);
        }
    }
private:
    SegmentString::NonConstVect& _to;

    SegmentStringExtractor(SegmentStringExtractor const&); /*= delete*/
    SegmentStringExtractor& operator=(SegmentStringExtractor const&); /*= delete*/
};

}

/* public static */
std::unique_ptr<geom::Geometry>
GeometryNoder::node(const geom::Geometry& geom)
{
    GeometryNoder noder(geom);
    return noder.getNoded();
}

/* public */
GeometryNoder::GeometryNoder(const geom::Geometry& g)
    :
    argGeom(g)
{
}

/* private */
std::unique_ptr<geom::Geometry>
GeometryNoder::toGeometry(SegmentString::NonConstVect& nodedEdges)
{
    const geom::GeometryFactory* geomFact = argGeom.getFactory();

    std::set< OrientedCoordinateArray > ocas;

    // Create a geometry out of the noded substrings.
    std::vector<std::unique_ptr<geom::Geometry>> lines;
    lines.reserve(nodedEdges.size());
    for(auto& ss :  nodedEdges) {
        const geom::CoordinateSequence* coords = ss->getCoordinates();

        // Check if an equivalent edge is known
        OrientedCoordinateArray oca1(*coords);
        if(ocas.insert(oca1).second) {
            lines.push_back(geomFact->createLineString(coords->clone()));
        }
    }

    return geomFact->createMultiLineString(std::move(lines));
}

/* public */
std::unique_ptr<geom::Geometry>
GeometryNoder::getNoded()
{
    SegmentString::NonConstVect p_lineList;
    extractSegmentStrings(argGeom, p_lineList);

    Noder& p_noder = getNoder();
    SegmentString::NonConstVect* nodedEdges = nullptr;

    try {
        p_noder.computeNodes(&p_lineList);
        nodedEdges = p_noder.getNodedSubstrings();
    }
    catch(const std::exception&) {
        for(size_t i = 0, n = p_lineList.size(); i < n; ++i) {
            delete p_lineList[i];
        }
        throw;
    }

    std::unique_ptr<geom::Geometry> noded = toGeometry(*nodedEdges);

    for(auto& elem : (*nodedEdges)) {
        delete elem;
    }
    delete nodedEdges;

    for(auto& elem : p_lineList) {
        delete elem;
    }

    return noded;
}

/* private static */
void
GeometryNoder::extractSegmentStrings(const geom::Geometry& g,
                                     SegmentString::NonConstVect& to)
{
    SegmentStringExtractor ex(to);
    g.apply_ro(&ex);
}

/* private */
Noder&
GeometryNoder::getNoder()
{
    if(! noder.get()) {
        const geom::PrecisionModel* pm = argGeom.getFactory()->getPrecisionModel();
#if 0
        using algorithm::LineIntersector;
        LineIntersector li;
        IntersectionAdder intersectionAdder(li);
        noder.reset(new MCIndexNoder(&intersectionAdder));
#else

        IteratedNoder* in = new IteratedNoder(pm);
        //in->setMaximumIterations(0);
        noder.reset(in);

        //using snapround::SimpleSnapRounder;
        //noder.reset( new SimpleSnapRounder(*pm) );

        //using snapround::MCIndexSnapRounder;
        //noder.reset( new MCIndexSnapRounder(*pm) );
#endif
    }
    return *noder;

}

} // namespace geos.noding
} // namespace geos
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
 * Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
 */

#include "DatabaseWorkerPool.h"
#include "AdhocStatement.h"
#include "Common.h"
#include "Errors.h"
#include "Implementation/CharacterDatabase.h"
#include "Implementation/LoginDatabase.h"
#include "Implementation/WorldDatabase.h"
#include "Log.h"
#include "MySQLPreparedStatement.h"
#include "MySQLWorkaround.h"
#include "PreparedStatement.h"
#include "ProducerConsumerQueue.h"
#include "QueryCallback.h"
#include "QueryHolder.h"
#include "QueryResult.h"
#include "SQLOperation.h"
#include "Transaction.h"
#include <mysqld_error.h>

#ifdef ACORE_DEBUG
#include <boost/stacktrace.hpp>
#include <sstream>
#endif

#define MIN_MYSQL_SERVER_VERSION 50700u
#define MIN_MYSQL_CLIENT_VERSION 50700u

class PingOperation : public SQLOperation
{
    //! Operation for idle delaythreads
    bool Execute() override
    {
        m_conn->Ping();
        return true;
    }
};

template <class T>
DatabaseWorkerPool<T>::DatabaseWorkerPool()
    : _queue(new ProducerConsumerQueue<SQLOperation*>()),
      _async_threads(0), _synch_threads(0)
{
    WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
    WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "AzerothCore does not support MySQL versions below 5.7");
    WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s id %lu) does not match the version id used to compile AzerothCore (id %u)",
        mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
}

template <class T>
DatabaseWorkerPool<T>::~DatabaseWorkerPool()
{
    _queue->Cancel();
}

template <class T>
void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString,
    uint8 const asyncThreads, uint8 const synchThreads)
{
    _connectionInfo = std::make_unique<MySQLConnectionInfo>(infoString);

    _async_threads = asyncThreads;
    _synch_threads = synchThreads;
}

template <class T>
uint32 DatabaseWorkerPool<T>::Open()
{
    WPFatal(_connectionInfo.get(), "Connection info was not set!");

    LOG_INFO("sql.driver", "Opening DatabasePool '%s'. "
        "Asynchronous connections: %u, synchronous connections: %u.",
        GetDatabaseName(), _async_threads, _synch_threads);

    uint32 error = OpenConnections(IDX_ASYNC, _async_threads);

    if (error)
        return error;

    error = OpenConnections(IDX_SYNCH, _synch_threads);

    if (!error)
    {
        LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD
                    " total connections running.", GetDatabaseName(),
                    (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size()));
    }

    LOG_INFO("sql.driver", " ");

    return error;
}

template <class T>
void DatabaseWorkerPool<T>::Close()
{
    LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName());

    //! Closes the actualy MySQL connection.
    _connections[IDX_ASYNC].clear();

    LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. "
                "Proceeding with synchronous connections.",
        GetDatabaseName());

    //! Shut down the synchronous connections
    //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
    //! should only be called after any other thread tasks in the core have exited,
    //! meaning there can be no concurrent access at this point.
    _connections[IDX_SYNCH].clear();

    LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}

template <class T>
bool DatabaseWorkerPool<T>::PrepareStatements()
{
    for (auto& connections : _connections)
    {
        for (auto& connection : connections)
        {
            connection->LockIfReady();
            if (!connection->PrepareStatements())
            {
                connection->Unlock();
                Close();
                return false;
            }
            else
                connection->Unlock();

            size_t const preparedSize = connection->m_stmts.size();
            if (_preparedStatementSize.size() < preparedSize)
                _preparedStatementSize.resize(preparedSize);

            for (size_t i = 0; i < preparedSize; ++i)
            {
                // already set by another connection
                // (each connection only has prepared statements of it's own type sync/async)
                if (_preparedStatementSize[i] > 0)
                    continue;

                if (MySQLPreparedStatement* stmt = connection->m_stmts[i].get())
                {
                    uint32 const paramCount = stmt->GetParameterCount();

                    // TC only supports uint8 indices.
                    ASSERT(paramCount < std::numeric_limits<uint8>::max());

                    _preparedStatementSize[i] = static_cast<uint8>(paramCount);
                }
            }
        }
    }

    return true;
}

template <class T>
QueryResult DatabaseWorkerPool<T>::Query(char const* sql, T* connection /*= nullptr*/)
{
    if (!connection)
        connection = GetFreeConnection();

    ResultSet* result = connection->Query(sql);
    connection->Unlock();
    if (!result || !result->GetRowCount() || !result->NextRow())
    {
        delete result;
        return QueryResult(nullptr);
    }

    return QueryResult(result);
}

template <class T>
PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement<T>* stmt)
{
    auto connection = GetFreeConnection();
    PreparedResultSet* ret = connection->Query(stmt);
    connection->Unlock();

    //! Delete proxy-class. Not needed anymore
    delete stmt;

    if (!ret || !ret->GetRowCount())
    {
        delete ret;
        return PreparedQueryResult(nullptr);
    }

    return PreparedQueryResult(ret);
}

template <class T>
QueryCallback DatabaseWorkerPool<T>::AsyncQuery(char const* sql)
{
    BasicStatementTask* task = new BasicStatementTask(sql, true);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    QueryResultFuture result = task->GetFuture();
    Enqueue(task);
    return QueryCallback(std::move(result));
}

template <class T>
QueryCallback DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement<T>* stmt)
{
    PreparedStatementTask* task = new PreparedStatementTask(stmt, true);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    PreparedQueryResultFuture result = task->GetFuture();
    Enqueue(task);
    return QueryCallback(std::move(result));
}

template <class T>
SQLQueryHolderCallback DatabaseWorkerPool<T>::DelayQueryHolder(std::shared_ptr<SQLQueryHolder<T>> holder)
{
    SQLQueryHolderTask* task = new SQLQueryHolderTask(holder);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    QueryResultHolderFuture result = task->GetFuture();
    Enqueue(task);
    return { std::move(holder), std::move(result) };
}

template <class T>
SQLTransaction<T> DatabaseWorkerPool<T>::BeginTransaction()
{
    return std::make_shared<Transaction<T>>();
}

template <class T>
void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction<T> transaction)
{
#ifdef ACORE_DEBUG
    //! Only analyze transaction weaknesses in Debug mode.
    //! Ideally we catch the faults in Debug mode and then correct them,
    //! so there's no need to waste these CPU cycles in Release mode.
    switch (transaction->GetSize())
    {
    case 0:
        LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
        return;
    case 1:
        LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
        break;
    default:
        break;
    }
#endif // ACORE_DEBUG

    Enqueue(new TransactionTask(transaction));
}

template <class T>
TransactionCallback DatabaseWorkerPool<T>::AsyncCommitTransaction(SQLTransaction<T> transaction)
{
#ifdef ACORE_DEBUG
    //! Only analyze transaction weaknesses in Debug mode.
    //! Ideally we catch the faults in Debug mode and then correct them,
    //! so there's no need to waste these CPU cycles in Release mode.
    switch (transaction->GetSize())
    {
        case 0:
            LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
            break;
        case 1:
            LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
            break;
        default:
            break;
    }
#endif // ACORE_DEBUG

    TransactionWithResultTask* task = new TransactionWithResultTask(transaction);
    TransactionFuture result = task->GetFuture();
    Enqueue(task);
    return TransactionCallback(std::move(result));
}

template <class T>
void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction<T>& transaction)
{
    T* connection = GetFreeConnection();
    int errorCode = connection->ExecuteTransaction(transaction);
    if (!errorCode)
    {
        connection->Unlock();      // OK, operation succesful
        return;
    }

    //! Handle MySQL Errno 1213 without extending deadlock to the core itself
    /// @todo More elegant way
    if (errorCode == ER_LOCK_DEADLOCK)
    {
        //todo: handle multiple sync threads deadlocking in a similar way as async threads
        uint8 loopBreaker = 5;
        for (uint8 i = 0; i < loopBreaker; ++i)
        {
            if (!connection->ExecuteTransaction(transaction))
                break;
        }
    }

    //! Clean up now.
    transaction->Cleanup();

    connection->Unlock();
}

template <class T>
PreparedStatement<T>* DatabaseWorkerPool<T>::GetPreparedStatement(PreparedStatementIndex index)
{
    return new PreparedStatement<T>(index, _preparedStatementSize[index]);
}

template <class T>
void DatabaseWorkerPool<T>::EscapeString(std::string& str)
{
    if (str.empty())
        return;

    char* buf = new char[str.size() * 2 + 1];
    EscapeString(buf, str.c_str(), uint32(str.size()));
    str = buf;
    delete[] buf;
}

template <class T>
void DatabaseWorkerPool<T>::KeepAlive()
{
    //! Ping synchronous connections
    for (auto& connection : _connections[IDX_SYNCH])
    {
        if (connection->LockIfReady())
        {
            connection->Ping();
            connection->Unlock();
        }
    }

    //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request
    //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter
    //! as the sole purpose is to prevent connections from idling.
    auto const count = _connections[IDX_ASYNC].size();
    for (uint8 i = 0; i < count; ++i)
        Enqueue(new PingOperation);
}

template <class T>
uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections)
{
    for (uint8 i = 0; i < numConnections; ++i)
    {
        // Create the connection
        auto connection = [&] {
            switch (type)
            {
            case IDX_ASYNC:
                return std::make_unique<T>(_queue.get(), *_connectionInfo);
            case IDX_SYNCH:
                return std::make_unique<T>(*_connectionInfo);
            default:
                ABORT();
            }
        }();

        if (uint32 error = connection->Open())
        {
            // Failed to open a connection or invalid version, abort and cleanup
            _connections[type].clear();
            return error;
        }
        else if (connection->GetServerVersion() < MIN_MYSQL_SERVER_VERSION)
        {
            LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 5.7");
            return 1;
        }
        else
        {
            _connections[type].push_back(std::move(connection));
        }
    }

    // Everything is fine
    return 0;
}

template <class T>
unsigned long DatabaseWorkerPool<T>::EscapeString(char* to, char const* from, unsigned long length)
{
    if (!to || !from || !length)
        return 0;

    return _connections[IDX_SYNCH].front()->EscapeString(to, from, length);
}

template <class T>
void DatabaseWorkerPool<T>::Enqueue(SQLOperation* op)
{
    _queue->Push(op);
}

template <class T>
T* DatabaseWorkerPool<T>::GetFreeConnection()
{
#ifdef ACORE_DEBUG
    if (_warnSyncQueries)
    {
        std::ostringstream ss;
        ss << boost::stacktrace::stacktrace();
        LOG_WARN("sql.performances", "Sync query at:\n%s", ss.str().c_str());
    }
#endif

    uint8 i = 0;
    auto const num_cons = _connections[IDX_SYNCH].size();
    T* connection = nullptr;

    //! Block forever until a connection is free
    for (;;)
    {
        connection = _connections[IDX_SYNCH][++i % num_cons].get();
        //! Must be matched with t->Unlock() or you will get deadlocks
        if (connection->LockIfReady())
            break;
    }

    return connection;
}

template <class T>
char const* DatabaseWorkerPool<T>::GetDatabaseName() const
{
    return _connectionInfo->database.c_str();
}

template <class T>
void DatabaseWorkerPool<T>::Execute(char const* sql)
{
    if (Acore::IsFormatEmptyOrNull(sql))
        return;

    BasicStatementTask* task = new BasicStatementTask(sql);
    Enqueue(task);
}

template <class T>
void DatabaseWorkerPool<T>::Execute(PreparedStatement<T>* stmt)
{
    PreparedStatementTask* task = new PreparedStatementTask(stmt);
    Enqueue(task);
}

template <class T>
void DatabaseWorkerPool<T>::DirectExecute(char const* sql)
{
    if (Acore::IsFormatEmptyOrNull(sql))
        return;

    T* connection = GetFreeConnection();
    connection->Execute(sql);
    connection->Unlock();
}

template <class T>
void DatabaseWorkerPool<T>::DirectExecute(PreparedStatement<T>* stmt)
{
    T* connection = GetFreeConnection();
    connection->Execute(stmt);
    connection->Unlock();

    //! Delete proxy-class. Not needed anymore
    delete stmt;
}

template <class T>
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction<T>& trans, char const* sql)
{
    if (!trans)
        Execute(sql);
    else
        trans->Append(sql);
}

template <class T>
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction<T>& trans, PreparedStatement<T>* stmt)
{
    if (!trans)
        Execute(stmt);
    else
        trans->Append(stmt);
}

template class AC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>;
<commit_msg>chore(Core/Database): add info about errors (#6895)<commit_after>/*
 * Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
 * Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
 */

#include "DatabaseWorkerPool.h"
#include "AdhocStatement.h"
#include "Common.h"
#include "Errors.h"
#include "Implementation/CharacterDatabase.h"
#include "Implementation/LoginDatabase.h"
#include "Implementation/WorldDatabase.h"
#include "Log.h"
#include "MySQLPreparedStatement.h"
#include "MySQLWorkaround.h"
#include "PreparedStatement.h"
#include "ProducerConsumerQueue.h"
#include "QueryCallback.h"
#include "QueryHolder.h"
#include "QueryResult.h"
#include "SQLOperation.h"
#include "Transaction.h"
#include <mysqld_error.h>

#ifdef ACORE_DEBUG
#include <boost/stacktrace.hpp>
#include <sstream>
#endif

#define MIN_MYSQL_SERVER_VERSION 50700u
#define MIN_MYSQL_CLIENT_VERSION 50700u

class PingOperation : public SQLOperation
{
    //! Operation for idle delaythreads
    bool Execute() override
    {
        m_conn->Ping();
        return true;
    }
};

template <class T>
DatabaseWorkerPool<T>::DatabaseWorkerPool()
    : _queue(new ProducerConsumerQueue<SQLOperation*>()),
      _async_threads(0), _synch_threads(0)
{
    WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
    WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "AzerothCore does not support MySQL versions below 5.7.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors).");
    WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s id %lu) does not match the version id used to compile AzerothCore (id %u).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors).",
        mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
}

template <class T>
DatabaseWorkerPool<T>::~DatabaseWorkerPool()
{
    _queue->Cancel();
}

template <class T>
void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString,
    uint8 const asyncThreads, uint8 const synchThreads)
{
    _connectionInfo = std::make_unique<MySQLConnectionInfo>(infoString);

    _async_threads = asyncThreads;
    _synch_threads = synchThreads;
}

template <class T>
uint32 DatabaseWorkerPool<T>::Open()
{
    WPFatal(_connectionInfo.get(), "Connection info was not set!");

    LOG_INFO("sql.driver", "Opening DatabasePool '%s'. "
        "Asynchronous connections: %u, synchronous connections: %u.",
        GetDatabaseName(), _async_threads, _synch_threads);

    uint32 error = OpenConnections(IDX_ASYNC, _async_threads);

    if (error)
        return error;

    error = OpenConnections(IDX_SYNCH, _synch_threads);

    if (!error)
    {
        LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD
                    " total connections running.", GetDatabaseName(),
                    (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size()));
    }

    LOG_INFO("sql.driver", " ");

    return error;
}

template <class T>
void DatabaseWorkerPool<T>::Close()
{
    LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName());

    //! Closes the actualy MySQL connection.
    _connections[IDX_ASYNC].clear();

    LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. "
                "Proceeding with synchronous connections.",
        GetDatabaseName());

    //! Shut down the synchronous connections
    //! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
    //! should only be called after any other thread tasks in the core have exited,
    //! meaning there can be no concurrent access at this point.
    _connections[IDX_SYNCH].clear();

    LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}

template <class T>
bool DatabaseWorkerPool<T>::PrepareStatements()
{
    for (auto& connections : _connections)
    {
        for (auto& connection : connections)
        {
            connection->LockIfReady();
            if (!connection->PrepareStatements())
            {
                connection->Unlock();
                Close();
                return false;
            }
            else
                connection->Unlock();

            size_t const preparedSize = connection->m_stmts.size();
            if (_preparedStatementSize.size() < preparedSize)
                _preparedStatementSize.resize(preparedSize);

            for (size_t i = 0; i < preparedSize; ++i)
            {
                // already set by another connection
                // (each connection only has prepared statements of it's own type sync/async)
                if (_preparedStatementSize[i] > 0)
                    continue;

                if (MySQLPreparedStatement* stmt = connection->m_stmts[i].get())
                {
                    uint32 const paramCount = stmt->GetParameterCount();

                    // TC only supports uint8 indices.
                    ASSERT(paramCount < std::numeric_limits<uint8>::max());

                    _preparedStatementSize[i] = static_cast<uint8>(paramCount);
                }
            }
        }
    }

    return true;
}

template <class T>
QueryResult DatabaseWorkerPool<T>::Query(char const* sql, T* connection /*= nullptr*/)
{
    if (!connection)
        connection = GetFreeConnection();

    ResultSet* result = connection->Query(sql);
    connection->Unlock();
    if (!result || !result->GetRowCount() || !result->NextRow())
    {
        delete result;
        return QueryResult(nullptr);
    }

    return QueryResult(result);
}

template <class T>
PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement<T>* stmt)
{
    auto connection = GetFreeConnection();
    PreparedResultSet* ret = connection->Query(stmt);
    connection->Unlock();

    //! Delete proxy-class. Not needed anymore
    delete stmt;

    if (!ret || !ret->GetRowCount())
    {
        delete ret;
        return PreparedQueryResult(nullptr);
    }

    return PreparedQueryResult(ret);
}

template <class T>
QueryCallback DatabaseWorkerPool<T>::AsyncQuery(char const* sql)
{
    BasicStatementTask* task = new BasicStatementTask(sql, true);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    QueryResultFuture result = task->GetFuture();
    Enqueue(task);
    return QueryCallback(std::move(result));
}

template <class T>
QueryCallback DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement<T>* stmt)
{
    PreparedStatementTask* task = new PreparedStatementTask(stmt, true);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    PreparedQueryResultFuture result = task->GetFuture();
    Enqueue(task);
    return QueryCallback(std::move(result));
}

template <class T>
SQLQueryHolderCallback DatabaseWorkerPool<T>::DelayQueryHolder(std::shared_ptr<SQLQueryHolder<T>> holder)
{
    SQLQueryHolderTask* task = new SQLQueryHolderTask(holder);
    // Store future result before enqueueing - task might get already processed and deleted before returning from this method
    QueryResultHolderFuture result = task->GetFuture();
    Enqueue(task);
    return { std::move(holder), std::move(result) };
}

template <class T>
SQLTransaction<T> DatabaseWorkerPool<T>::BeginTransaction()
{
    return std::make_shared<Transaction<T>>();
}

template <class T>
void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction<T> transaction)
{
#ifdef ACORE_DEBUG
    //! Only analyze transaction weaknesses in Debug mode.
    //! Ideally we catch the faults in Debug mode and then correct them,
    //! so there's no need to waste these CPU cycles in Release mode.
    switch (transaction->GetSize())
    {
    case 0:
        LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
        return;
    case 1:
        LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
        break;
    default:
        break;
    }
#endif // ACORE_DEBUG

    Enqueue(new TransactionTask(transaction));
}

template <class T>
TransactionCallback DatabaseWorkerPool<T>::AsyncCommitTransaction(SQLTransaction<T> transaction)
{
#ifdef ACORE_DEBUG
    //! Only analyze transaction weaknesses in Debug mode.
    //! Ideally we catch the faults in Debug mode and then correct them,
    //! so there's no need to waste these CPU cycles in Release mode.
    switch (transaction->GetSize())
    {
        case 0:
            LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
            break;
        case 1:
            LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
            break;
        default:
            break;
    }
#endif // ACORE_DEBUG

    TransactionWithResultTask* task = new TransactionWithResultTask(transaction);
    TransactionFuture result = task->GetFuture();
    Enqueue(task);
    return TransactionCallback(std::move(result));
}

template <class T>
void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction<T>& transaction)
{
    T* connection = GetFreeConnection();
    int errorCode = connection->ExecuteTransaction(transaction);
    if (!errorCode)
    {
        connection->Unlock();      // OK, operation succesful
        return;
    }

    //! Handle MySQL Errno 1213 without extending deadlock to the core itself
    /// @todo More elegant way
    if (errorCode == ER_LOCK_DEADLOCK)
    {
        //todo: handle multiple sync threads deadlocking in a similar way as async threads
        uint8 loopBreaker = 5;
        for (uint8 i = 0; i < loopBreaker; ++i)
        {
            if (!connection->ExecuteTransaction(transaction))
                break;
        }
    }

    //! Clean up now.
    transaction->Cleanup();

    connection->Unlock();
}

template <class T>
PreparedStatement<T>* DatabaseWorkerPool<T>::GetPreparedStatement(PreparedStatementIndex index)
{
    return new PreparedStatement<T>(index, _preparedStatementSize[index]);
}

template <class T>
void DatabaseWorkerPool<T>::EscapeString(std::string& str)
{
    if (str.empty())
        return;

    char* buf = new char[str.size() * 2 + 1];
    EscapeString(buf, str.c_str(), uint32(str.size()));
    str = buf;
    delete[] buf;
}

template <class T>
void DatabaseWorkerPool<T>::KeepAlive()
{
    //! Ping synchronous connections
    for (auto& connection : _connections[IDX_SYNCH])
    {
        if (connection->LockIfReady())
        {
            connection->Ping();
            connection->Unlock();
        }
    }

    //! Assuming all worker threads are free, every worker thread will receive 1 ping operation request
    //! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter
    //! as the sole purpose is to prevent connections from idling.
    auto const count = _connections[IDX_ASYNC].size();
    for (uint8 i = 0; i < count; ++i)
        Enqueue(new PingOperation);
}

template <class T>
uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections)
{
    for (uint8 i = 0; i < numConnections; ++i)
    {
        // Create the connection
        auto connection = [&] {
            switch (type)
            {
            case IDX_ASYNC:
                return std::make_unique<T>(_queue.get(), *_connectionInfo);
            case IDX_SYNCH:
                return std::make_unique<T>(*_connectionInfo);
            default:
                ABORT();
            }
        }();

        if (uint32 error = connection->Open())
        {
            // Failed to open a connection or invalid version, abort and cleanup
            _connections[type].clear();
            return error;
        }
        else if (connection->GetServerVersion() < MIN_MYSQL_SERVER_VERSION)
        {
            LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 5.7");
            return 1;
        }
        else
        {
            _connections[type].push_back(std::move(connection));
        }
    }

    // Everything is fine
    return 0;
}

template <class T>
unsigned long DatabaseWorkerPool<T>::EscapeString(char* to, char const* from, unsigned long length)
{
    if (!to || !from || !length)
        return 0;

    return _connections[IDX_SYNCH].front()->EscapeString(to, from, length);
}

template <class T>
void DatabaseWorkerPool<T>::Enqueue(SQLOperation* op)
{
    _queue->Push(op);
}

template <class T>
T* DatabaseWorkerPool<T>::GetFreeConnection()
{
#ifdef ACORE_DEBUG
    if (_warnSyncQueries)
    {
        std::ostringstream ss;
        ss << boost::stacktrace::stacktrace();
        LOG_WARN("sql.performances", "Sync query at:\n%s", ss.str().c_str());
    }
#endif

    uint8 i = 0;
    auto const num_cons = _connections[IDX_SYNCH].size();
    T* connection = nullptr;

    //! Block forever until a connection is free
    for (;;)
    {
        connection = _connections[IDX_SYNCH][++i % num_cons].get();
        //! Must be matched with t->Unlock() or you will get deadlocks
        if (connection->LockIfReady())
            break;
    }

    return connection;
}

template <class T>
char const* DatabaseWorkerPool<T>::GetDatabaseName() const
{
    return _connectionInfo->database.c_str();
}

template <class T>
void DatabaseWorkerPool<T>::Execute(char const* sql)
{
    if (Acore::IsFormatEmptyOrNull(sql))
        return;

    BasicStatementTask* task = new BasicStatementTask(sql);
    Enqueue(task);
}

template <class T>
void DatabaseWorkerPool<T>::Execute(PreparedStatement<T>* stmt)
{
    PreparedStatementTask* task = new PreparedStatementTask(stmt);
    Enqueue(task);
}

template <class T>
void DatabaseWorkerPool<T>::DirectExecute(char const* sql)
{
    if (Acore::IsFormatEmptyOrNull(sql))
        return;

    T* connection = GetFreeConnection();
    connection->Execute(sql);
    connection->Unlock();
}

template <class T>
void DatabaseWorkerPool<T>::DirectExecute(PreparedStatement<T>* stmt)
{
    T* connection = GetFreeConnection();
    connection->Execute(stmt);
    connection->Unlock();

    //! Delete proxy-class. Not needed anymore
    delete stmt;
}

template <class T>
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction<T>& trans, char const* sql)
{
    if (!trans)
        Execute(sql);
    else
        trans->Append(sql);
}

template <class T>
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction<T>& trans, PreparedStatement<T>* stmt)
{
    if (!trans)
        Execute(stmt);
    else
        trans->Append(stmt);
}

template class AC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>;
template class AC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>;
<|endoftext|>


<commit_before>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005 0x539 dev group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <windows.h>
#include <gdk/gdkwin32.h>
#include <net6/error.hpp>
#include "io/main_connection.hpp"

#include <iostream>

namespace
{
	// Note that this is not threadsafe, but we do not need threading here
	// anyways: We register all existing main_connections in a map that
	// associates their socket to the connection to regain the
	// main_connection object in the event handler.
	typedef std::map<net6::socket::socket_type, obby::io::main_connection*>
		connmap_type;

	// The map of main_connections
	connmap_type connmap;

	// Registers a new main_connection
	void register_connection(obby::io::main_connection& conn)
	{
		connmap[conn.get_socket().cobj()] = &conn;
	}

	// Unregisters a main_connection
	void unregister_connection(obby::io::main_connection& conn)
	{
		connmap_type::iterator iter =
			connmap.find(conn.get_socket().cobj() );

		if(iter != connmap.end() )
			connmap.erase(iter);
	}

	// Returns the main_connection for a given socket
	obby::io::main_connection*
	get_connection(net6::socket::socket_type socket)
	{
		connmap_type::iterator iter = connmap.find(socket);

		if(iter == connmap.end() )
			return NULL;
		else
			return iter->second;
	}

	// Network message
	const UINT WM_NETWORK = RegisterWindowMessageA("GOBBY_NETWORK_EVENT");

	// Gets a HWND for a given Gtk::Window
	HWND hwnd_from_window(Gtk::Window& window)
	{
		return reinterpret_cast<HWND>(
			GDK_WINDOW_HWND(window.get_window()->gobj() )
		);
	}

	// Callback function for window filter
	GdkFilterReturn on_filter(GdkXEvent* xevent,
	                          GdkEvent* event,
	                          gpointer data)
	{
		// Get window message
		MSG* msg = static_cast<MSG*>(xevent);

		// Network event?
		if(msg->message == WM_NETWORK)
		{
			long error, event;
			net6::socket::socket_type c_socket;

			// Get parameter from windows message
			c_socket = msg->wParam;
			error = WSAGETSELECTERROR(msg->lParam);
			event = WSAGETSELECTEVENT(msg->lParam);

			// Get main_connection, if any
			obby::io::main_connection* conn =
				get_connection(c_socket);
			if(conn == NULL) return GDK_FILTER_REMOVE;
			const net6::socket& sock = conn->get_socket();

			// Check for error
			if(error != 0)
			{
				if(conn->get_events() &
				   obby::io::main_connection::IO_ERROR)
					sock.io_event().emit(
						net6::socket::IOERROR
					);

				return GDK_FILTER_REMOVE;
			}

			// No error occured. Check for events
			// which cause a net6::socket::INCOMING.
			if(event == FD_READ || event == FD_ACCEPT ||
			   event == FD_CLOSE)
			{
				try
				{
					// Read until the read call would block
					// which means that no more data is to
					// read. Only perform one read operation
					// in case of a close or accept event.
					do
					{
						// TODO: On connection loss, 0
						// bytes are read -> we run into
						// an endless loop.
						sock.io_event().emit(
							net6::socket::INCOMING
						);
					} while(event == FD_READ);
				}
				catch(net6::error& e)
				{
					// Ignore WOULD_BLOCK errors.
					if(e.get_code() !=
					   net6::error::WOULD_BLOCK)
						throw e;
				}
			}

			// Check for something to write.
			if(event == FD_WRITE)
			{
				try
				{
					// Write until the call would block
					// (which means that no more buffer
					// space is available for writing) or
					// until there is nothing to write
					// anymore.
					while(conn->get_events() &
					      obby::io::main_connection::IO_OUT)
					{
						sock.io_event().emit(
							net6::socket::OUTGOING
						);
					}
				}
				catch(net6::error& e)
				{
					// Ignore WOULD_BLOCK errors
					if(e.get_code() !=
					   net6::error::WOULD_BLOCK)
						throw e;
				}
			}

			return GDK_FILTER_REMOVE;
		}
		else
		{
			// No network event: Handle normally.
			return GDK_FILTER_CONTINUE;
		}
	}
}

obby::io::main_connection::main_connection(Gtk::Window& window,
                                           const net6::socket& sock,
                                           Condition condition)
 : m_window(window), m_socket(sock),
   m_condition(static_cast<main_connection::Condition>(0) )
{
	// Add filter if there is none set
	if(connmap.size() == 0)
		window.get_window()->add_filter(&on_filter, NULL);

	// Register object
	register_connection(*this);

	// Wait for events
	set_events(condition);
}

obby::io::main_connection::~main_connection()
{
	// Unregister object
	unregister_connection(*this);

	// Remove filter if it is not needed anymore
	if(connmap.size() == 0)
		m_window.get_window()->remove_filter(&on_filter, NULL);

	// Do not wait for anything any longer
	WSAAsyncSelect(
		m_socket.cobj(),
		hwnd_from_window(m_window),
		WM_NETWORK,
		0
	);

	// Do not do any error handling because we are running a destructor.
	// Throwing exceptions in destructors is evil.
}

void obby::io::main_connection::set_events(Condition condition)
{
	// Do only do something if we shall watch for other conditions
//	if(m_condition != condition)
	{
		// Build lEvent parameter for WSAAsyncSelect
		long levent = 0;

		if(condition & IO_IN) levent |= (FD_READ | FD_CLOSE);
		if(condition & IO_ACCEPT) levent |= FD_ACCEPT;
		if(condition & IO_OUT) levent |= FD_WRITE;

		// Save conditions we are currently watching for
		m_condition = condition;

		// Select for new conditions
		int result = WSAAsyncSelect(
			m_socket.cobj(),
			hwnd_from_window(m_window),
			WM_NETWORK,
			levent
		);

		if(result != 0)
			throw net6::error(net6::error::SYSTEM);
	}
}

void obby::io::main_connection::add_events(Condition condition)
{
	set_events(m_condition | condition);
}

void obby::io::main_connection::remove_events(Condition condition)
{
	set_events(m_condition & ~condition);
}
<commit_msg>[project @ Added #include to <winsock2.h> to avoid <winsock.h> being included later.]<commit_after>/* gobby - A GTKmm driven libobby client
 * Copyright (C) 2005 0x539 dev group
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <winsock2.h>
#include <windows.h>
#include <gdk/gdkwin32.h>
#include <net6/error.hpp>
#include "io/main_connection.hpp"

#include <iostream>

namespace
{
	// Note that this is not threadsafe, but we do not need threading here
	// anyways: We register all existing main_connections in a map that
	// associates their socket to the connection to regain the
	// main_connection object in the event handler.
	typedef std::map<net6::socket::socket_type, obby::io::main_connection*>
		connmap_type;

	// The map of main_connections
	connmap_type connmap;

	// Registers a new main_connection
	void register_connection(obby::io::main_connection& conn)
	{
		connmap[conn.get_socket().cobj()] = &conn;
	}

	// Unregisters a main_connection
	void unregister_connection(obby::io::main_connection& conn)
	{
		connmap_type::iterator iter =
			connmap.find(conn.get_socket().cobj() );

		if(iter != connmap.end() )
			connmap.erase(iter);
	}

	// Returns the main_connection for a given socket
	obby::io::main_connection*
	get_connection(net6::socket::socket_type socket)
	{
		connmap_type::iterator iter = connmap.find(socket);

		if(iter == connmap.end() )
			return NULL;
		else
			return iter->second;
	}

	// Network message
	const UINT WM_NETWORK = RegisterWindowMessageA("GOBBY_NETWORK_EVENT");

	// Gets a HWND for a given Gtk::Window
	HWND hwnd_from_window(Gtk::Window& window)
	{
		return reinterpret_cast<HWND>(
			GDK_WINDOW_HWND(window.get_window()->gobj() )
		);
	}

	// Callback function for window filter
	GdkFilterReturn on_filter(GdkXEvent* xevent,
	                          GdkEvent* event,
	                          gpointer data)
	{
		// Get window message
		MSG* msg = static_cast<MSG*>(xevent);

		// Network event?
		if(msg->message == WM_NETWORK)
		{
			long error, event;
			net6::socket::socket_type c_socket;

			// Get parameter from windows message
			c_socket = msg->wParam;
			error = WSAGETSELECTERROR(msg->lParam);
			event = WSAGETSELECTEVENT(msg->lParam);

			// Get main_connection, if any
			obby::io::main_connection* conn =
				get_connection(c_socket);
			if(conn == NULL) return GDK_FILTER_REMOVE;
			const net6::socket& sock = conn->get_socket();

			// Check for error
			if(error != 0)
			{
				if(conn->get_events() &
				   obby::io::main_connection::IO_ERROR)
					sock.io_event().emit(
						net6::socket::IOERROR
					);

				return GDK_FILTER_REMOVE;
			}

			// No error occured. Check for events
			// which cause a net6::socket::INCOMING.
			if(event == FD_READ || event == FD_ACCEPT ||
			   event == FD_CLOSE)
			{
				try
				{
					// Read until the read call would block
					// which means that no more data is to
					// read. Only perform one read operation
					// in case of a close or accept event.
					do
					{
						// TODO: On connection loss, 0
						// bytes are read -> we run into
						// an endless loop.
						sock.io_event().emit(
							net6::socket::INCOMING
						);
					} while(event == FD_READ);
				}
				catch(net6::error& e)
				{
					// Ignore WOULD_BLOCK errors.
					if(e.get_code() !=
					   net6::error::WOULD_BLOCK)
						throw e;
				}
			}

			// Check for something to write.
			if(event == FD_WRITE)
			{
				try
				{
					// Write until the call would block
					// (which means that no more buffer
					// space is available for writing) or
					// until there is nothing to write
					// anymore.
					while(conn->get_events() &
					      obby::io::main_connection::IO_OUT)
					{
						sock.io_event().emit(
							net6::socket::OUTGOING
						);
					}
				}
				catch(net6::error& e)
				{
					// Ignore WOULD_BLOCK errors
					if(e.get_code() !=
					   net6::error::WOULD_BLOCK)
						throw e;
				}
			}

			return GDK_FILTER_REMOVE;
		}
		else
		{
			// No network event: Handle normally.
			return GDK_FILTER_CONTINUE;
		}
	}
}

obby::io::main_connection::main_connection(Gtk::Window& window,
                                           const net6::socket& sock,
                                           Condition condition)
 : m_window(window), m_socket(sock),
   m_condition(static_cast<main_connection::Condition>(0) )
{
	// Add filter if there is none set
	if(connmap.size() == 0)
		window.get_window()->add_filter(&on_filter, NULL);

	// Register object
	register_connection(*this);

	// Wait for events
	set_events(condition);
}

obby::io::main_connection::~main_connection()
{
	// Unregister object
	unregister_connection(*this);

	// Remove filter if it is not needed anymore
	if(connmap.size() == 0)
		m_window.get_window()->remove_filter(&on_filter, NULL);

	// Do not wait for anything any longer
	WSAAsyncSelect(
		m_socket.cobj(),
		hwnd_from_window(m_window),
		WM_NETWORK,
		0
	);

	// Do not do any error handling because we are running a destructor.
	// Throwing exceptions in destructors is evil.
}

void obby::io::main_connection::set_events(Condition condition)
{
	// Do only do something if we shall watch for other conditions
//	if(m_condition != condition)
	{
		// Build lEvent parameter for WSAAsyncSelect
		long levent = 0;

		if(condition & IO_IN) levent |= (FD_READ | FD_CLOSE);
		if(condition & IO_ACCEPT) levent |= FD_ACCEPT;
		if(condition & IO_OUT) levent |= FD_WRITE;

		// Save conditions we are currently watching for
		m_condition = condition;

		// Select for new conditions
		int result = WSAAsyncSelect(
			m_socket.cobj(),
			hwnd_from_window(m_window),
			WM_NETWORK,
			levent
		);

		if(result != 0)
			throw net6::error(net6::error::SYSTEM);
	}
}

void obby::io::main_connection::add_events(Condition condition)
{
	set_events(m_condition | condition);
}

void obby::io::main_connection::remove_events(Condition condition)
{
	set_events(m_condition & ~condition);
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/compiler/xla/util.h"

#include <limits>
#include <list>

#include "tensorflow/compiler/xla/test.h"
#include "tensorflow/compiler/xla/types.h"

namespace xla {
namespace {

// Verifies that, even with a different number of leading spaces, the
// Reindent routine turns them into a uniform number of leading spaces.
//
// Also throws in some trailing whitespace on the original to show it is
// removed.
TEST(UtilTest, ReindentsDifferentNumberOfLeadingSpacesUniformly) {
  std::string original = R"(   hello there
      world)";
  std::string got = Reindent(original, "  ");
  std::string want = R"(  hello there
  world)";
  EXPECT_EQ(want, got);
}

TEST(UtilTest, HumanReadableNumFlopsExample) {
  ASSERT_EQ("1.00GFLOP/s", HumanReadableNumFlops(1e9, 1e9));
}

TEST(UtilTest, CommaSeparatedString) {
  EXPECT_EQ(CommaSeparatedString({}), "");
  EXPECT_EQ(CommaSeparatedString({"hello world"}), "hello world");
  EXPECT_EQ(CommaSeparatedString({1, 57, 2}, "foo", "bar"), "foo1, 57, 2bar");
}

TEST(UtilTest, VectorString) {
  std::list<int64_t> empty_list;
  EXPECT_EQ(VectorString(empty_list), "()");

  std::vector<float> float_vector = {5.5};
  EXPECT_EQ(VectorString(float_vector), "(5.5)");

  std::set<const char*> string_set = {"a", "b"};
  EXPECT_EQ(VectorString(string_set), "(a, b)");

  EXPECT_EQ(VectorString({}), "()");
  EXPECT_EQ(VectorString({1, 57, 2}), "(1, 57, 2)");
}

TEST(UtilTest, LogLines) {
  // Just make sure this code runs (not verifying the output).
  LogLines(tensorflow::INFO, "hello\n\nworld", __FILE__, __LINE__);
}

TEST(UtilTest, CommonFactors) {
  struct {
    std::vector<int64_t> a, b;
    absl::InlinedVector<std::pair<int64_t, int64_t>, 8> expected;
  } test_cases[] = {
      {/*.a =*/{0}, /*.b =*/{0}, /*.expected =*/{{0, 0}, {1, 1}}},
      {/*.a =*/{1}, /*.b =*/{}, /*.expected =*/{{0, 0}, {1, 0}}},
      {/*.a =*/{}, /*.b =*/{1}, /*.expected =*/{{0, 0}, {0, 1}}},
      {/*.a =*/{0, 10}, /*.b =*/{0, 10, 3}, /*.expected =*/{{0, 0}, {2, 3}}},
      {/*.a =*/{1, 0}, /*.b =*/{1, 0, 1},
       /*.expected =*/{{0, 0}, {1, 1}, {2, 2}, {2, 3}}},
      {/*.a =*/{0, 1}, /*.b =*/{0, 1}, /*.expected =*/{{0, 0}, {1, 1}, {2, 2}}},
      {/*.a =*/{}, /*.b =*/{}, /*.expected =*/{{0, 0}}},
      {/*.a =*/{2, 5, 1, 3},
       /*.b =*/{1, 10, 3, 1},
       /*.expected =*/{{0, 0}, {0, 1}, {2, 2}, {3, 2}, {4, 3}, {4, 4}}},
      {/*.a =*/{1, 1, 3},
       /*.b =*/{1, 1, 3},
       /*.expected =*/{{0, 0}, {1, 1}, {2, 2}, {3, 3}}},
      // Splitting and combining dimensions.
      {/*.a =*/{2, 6},
       /*.b =*/{4, 3},
       /*.expected =*/{{0, 0}, {2, 2}}},
      {/*.a =*/{1, 2, 6},
       /*.b =*/{4, 1, 3, 1},
       /*.expected =*/{{0, 0}, {1, 0}, {3, 3}, {3, 4}}},
      // Extra degenerated dimension (second and third dims in the output) forms
      // single common factor group.
      {/*.a =*/{1, 2, 1},
       /*.b =*/{1, 1, 1, 2},
       /*.expected =*/{{0, 0}, {1, 1}, {1, 2}, {1, 3}, {2, 4}, {3, 4}}}};
  for (const auto& test_case : test_cases) {
    EXPECT_EQ(test_case.expected, CommonFactors(test_case.a, test_case.b));
  }
}

TEST(UtilTest, SanitizeFileName) {
  EXPECT_EQ(SanitizeFileName(""), "");
  EXPECT_EQ(SanitizeFileName("abc"), "abc");
  EXPECT_EQ(SanitizeFileName("/\\[]"), "____");
  EXPECT_EQ(SanitizeFileName("/A\\B[C]"), "_A_B_C_");
}

TEST(UtilTest, RoundTripFpToString) {
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(
                false, QuietNanWithoutPayload<half>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(
                true, QuietNanWithoutPayload<half>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(
                false, QuietNanWithoutPayload<bfloat16>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(
                true, QuietNanWithoutPayload<bfloat16>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(
                false, QuietNanWithoutPayload<float>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(
                true, QuietNanWithoutPayload<float>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(
                false, QuietNanWithoutPayload<double>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(
                true, QuietNanWithoutPayload<double>())),
            "-nan");

  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(true, 0x1)),
            "-nan(0x1)");
}

TEST(UtilTest, SplitF64ToF32) {
  // Overflowing the F32 exponent in SplitF64ToF32 should result in a pair of
  // [∞,0].
  EXPECT_EQ(SplitF64ToF32(std::numeric_limits<double>::max()).first,
            std::numeric_limits<float>::infinity());
  EXPECT_EQ(SplitF64ToF32(std::numeric_limits<double>::max()).second, 0.0f);
}

}  // namespace
}  // namespace xla
<commit_msg>Fix comparison of `const char*` strings with > and <<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/compiler/xla/util.h"

#include <limits>
#include <list>

#include "tensorflow/compiler/xla/test.h"
#include "tensorflow/compiler/xla/types.h"

namespace xla {
namespace {

// Verifies that, even with a different number of leading spaces, the
// Reindent routine turns them into a uniform number of leading spaces.
//
// Also throws in some trailing whitespace on the original to show it is
// removed.
TEST(UtilTest, ReindentsDifferentNumberOfLeadingSpacesUniformly) {
  std::string original = R"(   hello there
      world)";
  std::string got = Reindent(original, "  ");
  std::string want = R"(  hello there
  world)";
  EXPECT_EQ(want, got);
}

TEST(UtilTest, HumanReadableNumFlopsExample) {
  ASSERT_EQ("1.00GFLOP/s", HumanReadableNumFlops(1e9, 1e9));
}

TEST(UtilTest, CommaSeparatedString) {
  EXPECT_EQ(CommaSeparatedString({}), "");
  EXPECT_EQ(CommaSeparatedString({"hello world"}), "hello world");
  EXPECT_EQ(CommaSeparatedString({1, 57, 2}, "foo", "bar"), "foo1, 57, 2bar");
}

TEST(UtilTest, VectorString) {
  std::list<int64_t> empty_list;
  EXPECT_EQ(VectorString(empty_list), "()");

  std::vector<float> float_vector = {5.5};
  EXPECT_EQ(VectorString(float_vector), "(5.5)");

  std::set<std::string_view> string_set = {std::string_view("a"),
                                           std::string_view("b")};
  EXPECT_EQ(VectorString(string_set), "(a, b)");

  EXPECT_EQ(VectorString({}), "()");
  EXPECT_EQ(VectorString({1, 57, 2}), "(1, 57, 2)");
}

TEST(UtilTest, LogLines) {
  // Just make sure this code runs (not verifying the output).
  LogLines(tensorflow::INFO, "hello\n\nworld", __FILE__, __LINE__);
}

TEST(UtilTest, CommonFactors) {
  struct {
    std::vector<int64_t> a, b;
    absl::InlinedVector<std::pair<int64_t, int64_t>, 8> expected;
  } test_cases[] = {
      {/*.a =*/{0}, /*.b =*/{0}, /*.expected =*/{{0, 0}, {1, 1}}},
      {/*.a =*/{1}, /*.b =*/{}, /*.expected =*/{{0, 0}, {1, 0}}},
      {/*.a =*/{}, /*.b =*/{1}, /*.expected =*/{{0, 0}, {0, 1}}},
      {/*.a =*/{0, 10}, /*.b =*/{0, 10, 3}, /*.expected =*/{{0, 0}, {2, 3}}},
      {/*.a =*/{1, 0}, /*.b =*/{1, 0, 1},
       /*.expected =*/{{0, 0}, {1, 1}, {2, 2}, {2, 3}}},
      {/*.a =*/{0, 1}, /*.b =*/{0, 1}, /*.expected =*/{{0, 0}, {1, 1}, {2, 2}}},
      {/*.a =*/{}, /*.b =*/{}, /*.expected =*/{{0, 0}}},
      {/*.a =*/{2, 5, 1, 3},
       /*.b =*/{1, 10, 3, 1},
       /*.expected =*/{{0, 0}, {0, 1}, {2, 2}, {3, 2}, {4, 3}, {4, 4}}},
      {/*.a =*/{1, 1, 3},
       /*.b =*/{1, 1, 3},
       /*.expected =*/{{0, 0}, {1, 1}, {2, 2}, {3, 3}}},
      // Splitting and combining dimensions.
      {/*.a =*/{2, 6},
       /*.b =*/{4, 3},
       /*.expected =*/{{0, 0}, {2, 2}}},
      {/*.a =*/{1, 2, 6},
       /*.b =*/{4, 1, 3, 1},
       /*.expected =*/{{0, 0}, {1, 0}, {3, 3}, {3, 4}}},
      // Extra degenerated dimension (second and third dims in the output) forms
      // single common factor group.
      {/*.a =*/{1, 2, 1},
       /*.b =*/{1, 1, 1, 2},
       /*.expected =*/{{0, 0}, {1, 1}, {1, 2}, {1, 3}, {2, 4}, {3, 4}}}};
  for (const auto& test_case : test_cases) {
    EXPECT_EQ(test_case.expected, CommonFactors(test_case.a, test_case.b));
  }
}

TEST(UtilTest, SanitizeFileName) {
  EXPECT_EQ(SanitizeFileName(""), "");
  EXPECT_EQ(SanitizeFileName("abc"), "abc");
  EXPECT_EQ(SanitizeFileName("/\\[]"), "____");
  EXPECT_EQ(SanitizeFileName("/A\\B[C]"), "_A_B_C_");
}

TEST(UtilTest, RoundTripFpToString) {
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(
                false, QuietNanWithoutPayload<half>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(
                true, QuietNanWithoutPayload<half>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(
                false, QuietNanWithoutPayload<bfloat16>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(
                true, QuietNanWithoutPayload<bfloat16>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(
                false, QuietNanWithoutPayload<float>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(
                true, QuietNanWithoutPayload<float>())),
            "-nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(
                false, QuietNanWithoutPayload<double>())),
            "nan");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(
                true, QuietNanWithoutPayload<double>())),
            "-nan");

  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<half>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<bfloat16>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<float>(true, 0x1)),
            "-nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(false, 0x1)),
            "nan(0x1)");
  EXPECT_EQ(RoundTripFpToString(NanWithSignAndPayload<double>(true, 0x1)),
            "-nan(0x1)");
}

TEST(UtilTest, SplitF64ToF32) {
  // Overflowing the F32 exponent in SplitF64ToF32 should result in a pair of
  // [∞,0].
  EXPECT_EQ(SplitF64ToF32(std::numeric_limits<double>::max()).first,
            std::numeric_limits<float>::infinity());
  EXPECT_EQ(SplitF64ToF32(std::numeric_limits<double>::max()).second, 0.0f);
}

}  // namespace
}  // namespace xla
<|endoftext|>


<commit_before>//===-- sanitizer_common.cc -----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//

#include "sanitizer_common.h"
#include "sanitizer_allocator_interface.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

const char *SanitizerToolName = "SanitizerTool";

atomic_uint32_t current_verbosity;
uptr PageSizeCached;

// PID of the tracer task in StopTheWorld. It shares the address space with the
// main process, but has a different PID and thus requires special handling.
uptr stoptheworld_tracer_pid = 0;
// Cached pid of parent process - if the parent process dies, we want to keep
// writing to the same log file.
uptr stoptheworld_tracer_ppid = 0;

StaticSpinMutex CommonSanitizerReportMutex;

void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
                                      const char *mmap_type, error_t err,
                                      bool raw_report) {
  static int recursion_count;
  if (raw_report || recursion_count) {
    // If raw report is requested or we went into recursion, just die.
    // The Report() and CHECK calls below may call mmap recursively and fail.
    RawWrite("ERROR: Failed to mmap\n");
    Die();
  }
  recursion_count++;
  Report("ERROR: %s failed to "
         "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
         SanitizerToolName, mmap_type, size, size, mem_type, err);
#if !SANITIZER_GO
  DumpProcessMap();
#endif
  UNREACHABLE("unable to mmap");
}

typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);

template<class T>
static inline bool CompareLess(const T &a, const T &b) {
  return a < b;
}

void SortArray(uptr *array, uptr size) {
  InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
}

void SortArray(u32 *array, uptr size) {
  InternalSort<u32*, U32ComparisonFunction>(&array, size, CompareLess);
}

const char *StripPathPrefix(const char *filepath,
                            const char *strip_path_prefix) {
  if (!filepath) return nullptr;
  if (!strip_path_prefix) return filepath;
  const char *res = filepath;
  if (const char *pos = internal_strstr(filepath, strip_path_prefix))
    res = pos + internal_strlen(strip_path_prefix);
  if (res[0] == '.' && res[1] == '/')
    res += 2;
  return res;
}

const char *StripModuleName(const char *module) {
  if (!module)
    return nullptr;
  if (SANITIZER_WINDOWS) {
    // On Windows, both slash and backslash are possible.
    // Pick the one that goes last.
    if (const char *bslash_pos = internal_strrchr(module, '\\'))
      return StripModuleName(bslash_pos + 1);
  }
  if (const char *slash_pos = internal_strrchr(module, '/')) {
    return slash_pos + 1;
  }
  return module;
}

void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
  if (!common_flags()->print_summary)
    return;
  InternalScopedString buff(kMaxSummaryLength);
  buff.append("SUMMARY: %s: %s",
              alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
  __sanitizer_report_error_summary(buff.data());
}

#if !SANITIZER_GO
void ReportErrorSummary(const char *error_type, const AddressInfo &info,
                        const char *alt_tool_name) {
  if (!common_flags()->print_summary) return;
  InternalScopedString buff(kMaxSummaryLength);
  buff.append("%s ", error_type);
  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
              common_flags()->strip_path_prefix);
  ReportErrorSummary(buff.data(), alt_tool_name);
}
#endif

// Removes the ANSI escape sequences from the input string (in-place).
void RemoveANSIEscapeSequencesFromString(char *str) {
  if (!str)
    return;

  // We are going to remove the escape sequences in place.
  char *s = str;
  char *z = str;
  while (*s != '\0') {
    CHECK_GE(s, z);
    // Skip over ANSI escape sequences with pointer 's'.
    if (*s == '\033' && *(s + 1) == '[') {
      s = internal_strchrnul(s, 'm');
      if (*s == '\0') {
        break;
      }
      s++;
      continue;
    }
    // 's' now points at a character we want to keep. Copy over the buffer
    // content if the escape sequence has been perviously skipped andadvance
    // both pointers.
    if (s != z)
      *z = *s;

    // If we have not seen an escape sequence, just advance both pointers.
    z++;
    s++;
  }

  // Null terminate the string.
  *z = '\0';
}

void LoadedModule::set(const char *module_name, uptr base_address) {
  clear();
  full_name_ = internal_strdup(module_name);
  base_address_ = base_address;
}

void LoadedModule::set(const char *module_name, uptr base_address,
                       ModuleArch arch, u8 uuid[kModuleUUIDSize],
                       bool instrumented) {
  set(module_name, base_address);
  arch_ = arch;
  internal_memcpy(uuid_, uuid, sizeof(uuid_));
  instrumented_ = instrumented;
}

void LoadedModule::clear() {
  InternalFree(full_name_);
  base_address_ = 0;
  max_executable_address_ = 0;
  full_name_ = nullptr;
  arch_ = kModuleArchUnknown;
  internal_memset(uuid_, 0, kModuleUUIDSize);
  instrumented_ = false;
  while (!ranges_.empty()) {
    AddressRange *r = ranges_.front();
    ranges_.pop_front();
    InternalFree(r);
  }
}

void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
                                   bool writable, const char *name) {
  void *mem = InternalAlloc(sizeof(AddressRange));
  AddressRange *r =
      new(mem) AddressRange(beg, end, executable, writable, name);
  ranges_.push_back(r);
  if (executable && end > max_executable_address_)
    max_executable_address_ = end;
}

bool LoadedModule::containsAddress(uptr address) const {
  for (const AddressRange &r : ranges()) {
    if (r.beg <= address && address < r.end)
      return true;
  }
  return false;
}

static atomic_uintptr_t g_total_mmaped;

void IncreaseTotalMmap(uptr size) {
  if (!common_flags()->mmap_limit_mb) return;
  uptr total_mmaped =
      atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
  // Since for now mmap_limit_mb is not a user-facing flag, just kill
  // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
  RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
}

void DecreaseTotalMmap(uptr size) {
  if (!common_flags()->mmap_limit_mb) return;
  atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
}

bool TemplateMatch(const char *templ, const char *str) {
  if ((!str) || str[0] == 0)
    return false;
  bool start = false;
  if (templ && templ[0] == '^') {
    start = true;
    templ++;
  }
  bool asterisk = false;
  while (templ && templ[0]) {
    if (templ[0] == '*') {
      templ++;
      start = false;
      asterisk = true;
      continue;
    }
    if (templ[0] == '$')
      return str[0] == 0 || asterisk;
    if (str[0] == 0)
      return false;
    char *tpos = (char*)internal_strchr(templ, '*');
    char *tpos1 = (char*)internal_strchr(templ, '$');
    if ((!tpos) || (tpos1 && tpos1 < tpos))
      tpos = tpos1;
    if (tpos)
      tpos[0] = 0;
    const char *str0 = str;
    const char *spos = internal_strstr(str, templ);
    str = spos + internal_strlen(templ);
    templ = tpos;
    if (tpos)
      tpos[0] = tpos == tpos1 ? '$' : '*';
    if (!spos)
      return false;
    if (start && spos != str0)
      return false;
    start = false;
    asterisk = false;
  }
  return true;
}

static char binary_name_cache_str[kMaxPathLength];
static char process_name_cache_str[kMaxPathLength];

const char *GetProcessName() {
  return process_name_cache_str;
}

static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
  ReadLongProcessName(buf, buf_len);
  char *s = const_cast<char *>(StripModuleName(buf));
  uptr len = internal_strlen(s);
  if (s != buf) {
    internal_memmove(buf, s, len);
    buf[len] = '\0';
  }
  return len;
}

void UpdateProcessName() {
  ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}

// Call once to make sure that binary_name_cache_str is initialized
void CacheBinaryName() {
  if (binary_name_cache_str[0] != '\0')
    return;
  ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
  ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}

uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
  CacheBinaryName();
  uptr name_len = internal_strlen(binary_name_cache_str);
  name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
  if (buf_len == 0)
    return 0;
  internal_memcpy(buf, binary_name_cache_str, name_len);
  buf[name_len] = '\0';
  return name_len;
}

void PrintCmdline() {
  char **argv = GetArgv();
  if (!argv) return;
  Printf("\nCommand: ");
  for (uptr i = 0; argv[i]; ++i)
    Printf("%s ", argv[i]);
  Printf("\n\n");
}

// Malloc hooks.
static const int kMaxMallocFreeHooks = 5;
struct MallocFreeHook {
  void (*malloc_hook)(const void *, uptr);
  void (*free_hook)(const void *);
};

static MallocFreeHook MFHooks[kMaxMallocFreeHooks];

void RunMallocHooks(const void *ptr, uptr size) {
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    auto hook = MFHooks[i].malloc_hook;
    if (!hook) return;
    hook(ptr, size);
  }
}

void RunFreeHooks(const void *ptr) {
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    auto hook = MFHooks[i].free_hook;
    if (!hook) return;
    hook(ptr);
  }
}

static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
                                  void (*free_hook)(const void *)) {
  if (!malloc_hook || !free_hook) return 0;
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    if (MFHooks[i].malloc_hook == nullptr) {
      MFHooks[i].malloc_hook = malloc_hook;
      MFHooks[i].free_hook = free_hook;
      return i + 1;
    }
  }
  return 0;
}

static const u32 kUnclaimedTid = 0xfffffe;
static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid};

ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) {
  for (;;) {
    u32 expected_tid = kUnclaimedTid;
    if (current_tid == kUnclaimedTid ||
        atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid,
                                       current_tid, memory_order_relaxed)) {
      // We've claimed reporting_thread_tid_ so proceed.
      CommonSanitizerReportMutex.Lock();
      return;
    }

    if (expected_tid == current_tid) {
      // This is either asynch signal or nested error during error reporting.
      // Fail simple to avoid deadlocks in Report().

      // Can't use Report() here because of potential deadlocks in nested
      // signal handlers.
      static const char msg[] =
          "AddressSanitizer: nested bug in the same thread, aborting.\n";
      CatastrophicErrorWrite(msg, sizeof(msg) - 1);

      internal__exit(common_flags()->exitcode);
    }

    internal_sched_yield();
  }
}

ScopedErrorReportLock::~ScopedErrorReportLock() {
  CommonSanitizerReportMutex.Unlock();
  atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid);
}

} // namespace __sanitizer

using namespace __sanitizer;  // NOLINT

extern "C" {
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
                             const char *error_summary) {
  Printf("%s\n", error_summary);
}

SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_death_callback(void (*callback)(void)) {
  SetUserDieCallback(callback);
}

SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
                                                                  uptr),
                                              void (*free_hook)(const void *)) {
  return InstallMallocFreeHooks(malloc_hook, free_hook);
}
} // extern "C"
<commit_msg>[sanitizer] Replace AddressSanitizer with correct tool name<commit_after>//===-- sanitizer_common.cc -----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
//===----------------------------------------------------------------------===//

#include "sanitizer_common.h"
#include "sanitizer_allocator_interface.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_flags.h"
#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_stacktrace_printer.h"
#include "sanitizer_symbolizer.h"

namespace __sanitizer {

const char *SanitizerToolName = "SanitizerTool";

atomic_uint32_t current_verbosity;
uptr PageSizeCached;

// PID of the tracer task in StopTheWorld. It shares the address space with the
// main process, but has a different PID and thus requires special handling.
uptr stoptheworld_tracer_pid = 0;
// Cached pid of parent process - if the parent process dies, we want to keep
// writing to the same log file.
uptr stoptheworld_tracer_ppid = 0;

StaticSpinMutex CommonSanitizerReportMutex;

void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
                                      const char *mmap_type, error_t err,
                                      bool raw_report) {
  static int recursion_count;
  if (raw_report || recursion_count) {
    // If raw report is requested or we went into recursion, just die.
    // The Report() and CHECK calls below may call mmap recursively and fail.
    RawWrite("ERROR: Failed to mmap\n");
    Die();
  }
  recursion_count++;
  Report("ERROR: %s failed to "
         "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
         SanitizerToolName, mmap_type, size, size, mem_type, err);
#if !SANITIZER_GO
  DumpProcessMap();
#endif
  UNREACHABLE("unable to mmap");
}

typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);

template<class T>
static inline bool CompareLess(const T &a, const T &b) {
  return a < b;
}

void SortArray(uptr *array, uptr size) {
  InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
}

void SortArray(u32 *array, uptr size) {
  InternalSort<u32*, U32ComparisonFunction>(&array, size, CompareLess);
}

const char *StripPathPrefix(const char *filepath,
                            const char *strip_path_prefix) {
  if (!filepath) return nullptr;
  if (!strip_path_prefix) return filepath;
  const char *res = filepath;
  if (const char *pos = internal_strstr(filepath, strip_path_prefix))
    res = pos + internal_strlen(strip_path_prefix);
  if (res[0] == '.' && res[1] == '/')
    res += 2;
  return res;
}

const char *StripModuleName(const char *module) {
  if (!module)
    return nullptr;
  if (SANITIZER_WINDOWS) {
    // On Windows, both slash and backslash are possible.
    // Pick the one that goes last.
    if (const char *bslash_pos = internal_strrchr(module, '\\'))
      return StripModuleName(bslash_pos + 1);
  }
  if (const char *slash_pos = internal_strrchr(module, '/')) {
    return slash_pos + 1;
  }
  return module;
}

void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
  if (!common_flags()->print_summary)
    return;
  InternalScopedString buff(kMaxSummaryLength);
  buff.append("SUMMARY: %s: %s",
              alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
  __sanitizer_report_error_summary(buff.data());
}

#if !SANITIZER_GO
void ReportErrorSummary(const char *error_type, const AddressInfo &info,
                        const char *alt_tool_name) {
  if (!common_flags()->print_summary) return;
  InternalScopedString buff(kMaxSummaryLength);
  buff.append("%s ", error_type);
  RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
              common_flags()->strip_path_prefix);
  ReportErrorSummary(buff.data(), alt_tool_name);
}
#endif

// Removes the ANSI escape sequences from the input string (in-place).
void RemoveANSIEscapeSequencesFromString(char *str) {
  if (!str)
    return;

  // We are going to remove the escape sequences in place.
  char *s = str;
  char *z = str;
  while (*s != '\0') {
    CHECK_GE(s, z);
    // Skip over ANSI escape sequences with pointer 's'.
    if (*s == '\033' && *(s + 1) == '[') {
      s = internal_strchrnul(s, 'm');
      if (*s == '\0') {
        break;
      }
      s++;
      continue;
    }
    // 's' now points at a character we want to keep. Copy over the buffer
    // content if the escape sequence has been perviously skipped andadvance
    // both pointers.
    if (s != z)
      *z = *s;

    // If we have not seen an escape sequence, just advance both pointers.
    z++;
    s++;
  }

  // Null terminate the string.
  *z = '\0';
}

void LoadedModule::set(const char *module_name, uptr base_address) {
  clear();
  full_name_ = internal_strdup(module_name);
  base_address_ = base_address;
}

void LoadedModule::set(const char *module_name, uptr base_address,
                       ModuleArch arch, u8 uuid[kModuleUUIDSize],
                       bool instrumented) {
  set(module_name, base_address);
  arch_ = arch;
  internal_memcpy(uuid_, uuid, sizeof(uuid_));
  instrumented_ = instrumented;
}

void LoadedModule::clear() {
  InternalFree(full_name_);
  base_address_ = 0;
  max_executable_address_ = 0;
  full_name_ = nullptr;
  arch_ = kModuleArchUnknown;
  internal_memset(uuid_, 0, kModuleUUIDSize);
  instrumented_ = false;
  while (!ranges_.empty()) {
    AddressRange *r = ranges_.front();
    ranges_.pop_front();
    InternalFree(r);
  }
}

void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
                                   bool writable, const char *name) {
  void *mem = InternalAlloc(sizeof(AddressRange));
  AddressRange *r =
      new(mem) AddressRange(beg, end, executable, writable, name);
  ranges_.push_back(r);
  if (executable && end > max_executable_address_)
    max_executable_address_ = end;
}

bool LoadedModule::containsAddress(uptr address) const {
  for (const AddressRange &r : ranges()) {
    if (r.beg <= address && address < r.end)
      return true;
  }
  return false;
}

static atomic_uintptr_t g_total_mmaped;

void IncreaseTotalMmap(uptr size) {
  if (!common_flags()->mmap_limit_mb) return;
  uptr total_mmaped =
      atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
  // Since for now mmap_limit_mb is not a user-facing flag, just kill
  // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
  RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
}

void DecreaseTotalMmap(uptr size) {
  if (!common_flags()->mmap_limit_mb) return;
  atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
}

bool TemplateMatch(const char *templ, const char *str) {
  if ((!str) || str[0] == 0)
    return false;
  bool start = false;
  if (templ && templ[0] == '^') {
    start = true;
    templ++;
  }
  bool asterisk = false;
  while (templ && templ[0]) {
    if (templ[0] == '*') {
      templ++;
      start = false;
      asterisk = true;
      continue;
    }
    if (templ[0] == '$')
      return str[0] == 0 || asterisk;
    if (str[0] == 0)
      return false;
    char *tpos = (char*)internal_strchr(templ, '*');
    char *tpos1 = (char*)internal_strchr(templ, '$');
    if ((!tpos) || (tpos1 && tpos1 < tpos))
      tpos = tpos1;
    if (tpos)
      tpos[0] = 0;
    const char *str0 = str;
    const char *spos = internal_strstr(str, templ);
    str = spos + internal_strlen(templ);
    templ = tpos;
    if (tpos)
      tpos[0] = tpos == tpos1 ? '$' : '*';
    if (!spos)
      return false;
    if (start && spos != str0)
      return false;
    start = false;
    asterisk = false;
  }
  return true;
}

static char binary_name_cache_str[kMaxPathLength];
static char process_name_cache_str[kMaxPathLength];

const char *GetProcessName() {
  return process_name_cache_str;
}

static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
  ReadLongProcessName(buf, buf_len);
  char *s = const_cast<char *>(StripModuleName(buf));
  uptr len = internal_strlen(s);
  if (s != buf) {
    internal_memmove(buf, s, len);
    buf[len] = '\0';
  }
  return len;
}

void UpdateProcessName() {
  ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}

// Call once to make sure that binary_name_cache_str is initialized
void CacheBinaryName() {
  if (binary_name_cache_str[0] != '\0')
    return;
  ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
  ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
}

uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
  CacheBinaryName();
  uptr name_len = internal_strlen(binary_name_cache_str);
  name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
  if (buf_len == 0)
    return 0;
  internal_memcpy(buf, binary_name_cache_str, name_len);
  buf[name_len] = '\0';
  return name_len;
}

void PrintCmdline() {
  char **argv = GetArgv();
  if (!argv) return;
  Printf("\nCommand: ");
  for (uptr i = 0; argv[i]; ++i)
    Printf("%s ", argv[i]);
  Printf("\n\n");
}

// Malloc hooks.
static const int kMaxMallocFreeHooks = 5;
struct MallocFreeHook {
  void (*malloc_hook)(const void *, uptr);
  void (*free_hook)(const void *);
};

static MallocFreeHook MFHooks[kMaxMallocFreeHooks];

void RunMallocHooks(const void *ptr, uptr size) {
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    auto hook = MFHooks[i].malloc_hook;
    if (!hook) return;
    hook(ptr, size);
  }
}

void RunFreeHooks(const void *ptr) {
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    auto hook = MFHooks[i].free_hook;
    if (!hook) return;
    hook(ptr);
  }
}

static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
                                  void (*free_hook)(const void *)) {
  if (!malloc_hook || !free_hook) return 0;
  for (int i = 0; i < kMaxMallocFreeHooks; i++) {
    if (MFHooks[i].malloc_hook == nullptr) {
      MFHooks[i].malloc_hook = malloc_hook;
      MFHooks[i].free_hook = free_hook;
      return i + 1;
    }
  }
  return 0;
}

static const u32 kUnclaimedTid = 0xfffffe;
static atomic_uint32_t reporting_thread_tid = {kUnclaimedTid};

ScopedErrorReportLock::ScopedErrorReportLock(u32 current_tid) {
  for (;;) {
    u32 expected_tid = kUnclaimedTid;
    if (current_tid == kUnclaimedTid ||
        atomic_compare_exchange_strong(&reporting_thread_tid, &expected_tid,
                                       current_tid, memory_order_relaxed)) {
      // We've claimed reporting_thread_tid_ so proceed.
      CommonSanitizerReportMutex.Lock();
      return;
    }

    if (expected_tid == current_tid) {
      // This is either asynch signal or nested error during error reporting.
      // Fail simple to avoid deadlocks in Report().

      // Can't use Report() here because of potential deadlocks in nested
      // signal handlers.
      CatastrophicErrorWrite(SanitizerToolName,
                             internal_strlen(SanitizerToolName));
      static const char msg[] = ": nested bug in the same thread, aborting.\n";
      CatastrophicErrorWrite(msg, sizeof(msg) - 1);

      internal__exit(common_flags()->exitcode);
    }

    internal_sched_yield();
  }
}

ScopedErrorReportLock::~ScopedErrorReportLock() {
  CommonSanitizerReportMutex.Unlock();
  atomic_store_relaxed(&reporting_thread_tid, kUnclaimedTid);
}

} // namespace __sanitizer

using namespace __sanitizer;  // NOLINT

extern "C" {
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
                             const char *error_summary) {
  Printf("%s\n", error_summary);
}

SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_set_death_callback(void (*callback)(void)) {
  SetUserDieCallback(callback);
}

SANITIZER_INTERFACE_ATTRIBUTE
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
                                                                  uptr),
                                              void (*free_hook)(const void *)) {
  return InstallMallocFreeHooks(malloc_hook, free_hook);
}
} // extern "C"
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>

#include <cstring>
#include <cstdlib>
#include <ctime>

#include <omp.h>

int N = 10;

void partition (int *mas, int *left, int *right)
{
    int pivot = 0;
    int elem1;
    int elem2;

    while (1) {
        elem1 = *(mas + (*left));
        elem2 = *(mas + (*right));

        while (elem1 < *(mas + pivot)) {
            ++(*left);
            elem1 = *(mas + (*left));
        }

        while (elem2 > *(mas + pivot)) {
            --(*right);
            elem2 = *(mas + (*right));
        }

        if ((*left) < (*right)) {
            std::swap (*(mas + (*left)), *(mas + (*right)));
            if ((*left) == pivot) {
                pivot = (*right);
                if (elem1 == elem2) {
                    ++(*left);
                }
            } else if ((*right) == pivot) {
                pivot = (*left);
                if (elem1 == elem2) {
                    --(*right);
                }
            }
        } else {
            break;
        }
    }
}

void quick_sort (int *mas, int size)
{
    int i = 0, j = size - 1;

    partition (mas, &i, &j);

    if (i >= 1) {
        quick_sort (mas, i);
    }
    if (size - (j + 1) > 1) {
        quick_sort (mas + i + 1, size - (j + 1));
    }
}

void quick_sort_mt (int *mas, int size)
{
    int i = 0, j = size - 1;

    partition (mas, &i, &j);

    #pragma omp parallel sections num_threads (2)
    {
        #pragma omp section
        {
            if (i >= 1) {
                quick_sort_mt (mas, i);
            }
        }

        #pragma omp section
        {
            if (size - (j + 1) > 1) {
                quick_sort_mt (mas + i + 1, size - (j + 1));
            }
        }
    }
}

int main (int argc, char *argv[])
{
    omp_set_nested (1);
    omp_set_max_active_levels (omp_get_num_threads ());

    if (argc >= 2) {
        N = atoi (argv[1]);
    }

    std::ofstream fout;

    fout.open ("res_02.txt");
    fout << "Massive:\n";

    int *mas1, *mas2;

    mas1 = new int[N];
    mas2 = new int[N];

    srand (time (NULL));

    for (int i = 0; i < N; ++i) {
        mas1[i] = rand () % 100;
        fout << mas1[i] << " ";
    }
    fout << std::endl;
    fout << "Simple quick sort:\n";

    memcpy (mas2, mas1, sizeof (int) * N);

    clock_t start, end;

    start = clock ();
    quick_sort (mas1, N);
    end = clock ();

    std::cout << "Simple quick sort:\n";
    std::cout << (end - start) / 1000000.00 << std::endl;

    for (int i = 0; i < N; ++i) {
        fout << mas1[i] << " ";
    }
    fout << std::endl;

    fout << "Multithreading quick sort:\n";

    start = clock ();
    quick_sort_mt (mas2, N);
    end = clock ();

    std::cout << "Multithreading quick sort:\n";
    std::cout << (end - start) / 1000000.00 << std::endl;

    for (int i = 0; i < N; ++i) {
        fout << mas2[i] << " ";
    }
    fout << std::endl;

    fout.close ();

    delete[] mas1;
    delete[] mas2;

    return 0;
}
<commit_msg>Update prog_02.cpp<commit_after>/*
 * Quick Sort OpenMP
 */
#include <iostream>
#include <fstream>

#include <cstring>
#include <cstdlib>
#include <ctime>

#include <omp.h>

int N = 10;         // Massive size

void partition (int *mas, int *left, int *right)
{
    int pivot = 0;
    int elem1;
    int elem2;

    while (1) {
        elem1 = *(mas + (*left));
        elem2 = *(mas + (*right));

        while (elem1 < *(mas + pivot)) {
            ++(*left);
            elem1 = *(mas + (*left));
        }

        while (elem2 > *(mas + pivot)) {
            --(*right);
            elem2 = *(mas + (*right));
        }

        if ((*left) < (*right)) {
            std::swap (*(mas + (*left)), *(mas + (*right)));
            if ((*left) == pivot) {
                pivot = (*right);
                if (elem1 == elem2) {
                    ++(*left);
                }
            } else if ((*right) == pivot) {
                pivot = (*left);
                if (elem1 == elem2) {
                    --(*right);
                }
            }
        } else {
            break;
        }
    }
}

void quick_sort (int *mas, int size)
{
    int i = 0, j = size - 1;

    partition (mas, &i, &j);

    if (i >= 1) {
        quick_sort (mas, i);
    }
    if (size - (j + 1) > 1) {
        quick_sort (mas + i + 1, size - (j + 1));
    }
}

void quick_sort_mt (int *mas, int size)
{
    int i = 0, j = size - 1;

    partition (mas, &i, &j);

    #pragma omp parallel sections num_threads (2)
    {
        #pragma omp section
        {
            if (i >= 1) {
                quick_sort_mt (mas, i);
            }
        }

        #pragma omp section
        {
            if (size - (j + 1) > 1) {
                quick_sort_mt (mas + i + 1, size - (j + 1));
            }
        }
    }
}

int main (int argc, char *argv[])
{
    omp_set_nested (1);
    omp_set_max_active_levels (omp_get_num_threads ());

    if (argc >= 2) {
        N = atoi (argv[1]);
    }

    std::ofstream fout;

    fout.open ("res_02.txt");
    fout << "Massive:\n";

    int *mas1, *mas2;

    mas1 = new int[N];
    mas2 = new int[N];

    srand (time (NULL));

    for (int i = 0; i < N; ++i) {
        mas1[i] = rand () % 100;
        fout << mas1[i] << " ";
    }
    fout << std::endl;
    fout << "Simple quick sort:\n";

    memcpy (mas2, mas1, sizeof (int) * N);

    clock_t start, end;

    start = clock ();
    quick_sort (mas1, N);
    end = clock ();

    std::cout << "Simple quick sort:\n";
    std::cout << (end - start) / 1000000.00 << std::endl;

    for (int i = 0; i < N; ++i) {
        fout << mas1[i] << " ";
    }
    fout << std::endl;

    fout << "Multithreading quick sort:\n";

    start = clock ();
    quick_sort_mt (mas2, N);
    end = clock ();

    std::cout << "Multithreading quick sort:\n";
    std::cout << (end - start) / 1000000.00 << std::endl;

    for (int i = 0; i < N; ++i) {
        fout << mas2[i] << " ";
    }
    fout << std::endl;

    fout.close ();

    delete[] mas1;
    delete[] mas2;

    return 0;
}
<|endoftext|>