<commit_before>//https://code.google.com/p/nya-engine/

#include "dds.h"
#include "memory/memory_reader.h"
#include "memory/tmp_buffer.h"
#include "resources/resources.h"

//ToDo: mipmaps, cubemaps

namespace nya_formats
{

struct dds_pixel_format
{
    typedef unsigned int uint;

    uint size;
    uint flags;
    uint four_cc;
    uint bpp;
    uint bit_mask[4]; //rgba
};

size_t dds::decode_header(const void *data,size_t size)
{
    *this=dds();

    if(!data || size<128)
        return 0;

    typedef unsigned int uint;

    nya_memory::memory_reader reader(data,size);
    if(!reader.test("DDS ",4))
        return 0;

    if(reader.read<uint>()!=124)
        return 0;

    const uint dds_pixelformat=0x00001000;
    const uint dds_caps=0x00000001;

    const uint flags=reader.read<uint>();
    if(!(flags & dds_pixelformat) || !(flags & dds_caps))
        return 0;

    height=reader.read<uint>();
    width=reader.read<uint>();
    reader.skip(4); //const uint pitch=reader.read<uint>();
    const uint depth=reader.read<uint>();
    if(depth>0) //ToDo
        return 0;

    mipmap_count=reader.read<uint>();
    if(!mipmap_count)
    {
        need_generate_mipmaps=true;
        mipmap_count=1;
    }

    reader.skip(44);

    const uint dds_fourcc=0x00000004;
    const uint dds_rgb=0x00000040;
    const uint dds_alpha=0x00000001;
    const uint dds_cubemap=0x00000200;

    const dds_pixel_format pf=reader.read<dds_pixel_format>();
    if(pf.flags & dds_fourcc)
    {
        switch(pf.four_cc)
        {
            case '1TXD': this->pf=dxt1; break;
            case '2TXD': this->pf=dxt2; break;
            case '3TXD': this->pf=dxt3; break;
            case '4TXD':this->pf=dxt4; break;
            case '5TXD': this->pf=dxt5; break;
            default: return 0;
        };

        for(uint i=0,w=width,h=height;i<mipmap_count;++i,w/=2,h/=2)
        {
            uint s=(w>4?w:4)/4 * (h>4?h:4)/4 * (this->pf==dxt1?8:16);
            if(i==0) this->mip0_data_size=s;
            this->data_size+=s;
        }
    }
    else if(pf.flags & dds_rgb)
    {
        if(pf.bit_mask[0]!=0xff0000 || pf.bit_mask[1]!=0xff00 || pf.bit_mask[2]!=0xff )
            return 0;

        if(pf.flags & dds_alpha)
        {
            if(pf.bpp!=32 || pf.bit_mask[3]!=0xff000000U)
                return 0;

            this->pf=bgra;
        }
        else if(pf.bpp==24)
            this->pf=bgr;
        else
            return 0;

        this->mip0_data_size=width*height*pf.bpp/4;
        for(uint i=0,s=uint(mip0_data_size);i<mipmap_count;++i,s/=4)
            this->data_size+=s;
    }
    else
        return 0;

    unsigned int caps1=reader.read<unsigned int>();
    unsigned int caps2=reader.read<unsigned int>();

    type=texture_2d;
    if(caps2 & dds_cubemap)
    {
        type=texture_cube;
        this->data_size*=6;
    }

    reader.seek(128);
    if(!reader.check_remained(this->data_size))
        return 0;

    this->data=reader.get_data();

    return reader.get_offset();
}

}
<commit_msg>dds load fix<commit_after>//https://code.google.com/p/nya-engine/

#include "dds.h"
#include "memory/memory_reader.h"
#include "memory/tmp_buffer.h"
#include "resources/resources.h"

//ToDo: mipmaps, cubemaps

namespace nya_formats
{

struct dds_pixel_format
{
    typedef unsigned int uint;

    uint size;
    uint flags;
    uint four_cc;
    uint bpp;
    uint bit_mask[4]; //rgba
};

size_t dds::decode_header(const void *data,size_t size)
{
    *this=dds();

    if(!data || size<128)
        return 0;

    typedef unsigned int uint;

    nya_memory::memory_reader reader(data,size);
    if(!reader.test("DDS ",4))
        return 0;

    if(reader.read<uint>()!=124)
        return 0;

    const uint dds_pixelformat=0x00001000;
    const uint dds_caps=0x00000001;

    const uint flags=reader.read<uint>();
    if(!(flags & dds_pixelformat) || !(flags & dds_caps))
        return 0;

    height=reader.read<uint>();
    width=reader.read<uint>();
    reader.skip(4); //const uint pitch=reader.read<uint>();
    const uint depth=reader.read<uint>();
    if(depth>0) //ToDo
        return 0;

    mipmap_count=reader.read<uint>();
    if(!mipmap_count)
    {
        need_generate_mipmaps=true;
        mipmap_count=1;
    }

    reader.skip(44);

    const uint dds_fourcc=0x00000004;
    const uint dds_rgb=0x00000040;
    const uint dds_alpha=0x00000001;
    const uint dds_cubemap=0x00000200;

    const dds_pixel_format pf=reader.read<dds_pixel_format>();
    if(pf.flags & dds_fourcc)
    {
        switch(pf.four_cc)
        {
            case '1TXD': this->pf=dxt1; break;
            case '2TXD': this->pf=dxt2; break;
            case '3TXD': this->pf=dxt3; break;
            case '4TXD':this->pf=dxt4; break;
            case '5TXD': this->pf=dxt5; break;
            default: return 0;
        };

        for(uint i=0,w=width,h=height;i<mipmap_count;++i,w/=2,h/=2)
        {
            uint s=(w>4?w:4)/4 * (h>4?h:4)/4 * (this->pf==dxt1?8:16);
            if(i==0) this->mip0_data_size=s;
            this->data_size+=s;
        }
    }
    else if(pf.flags & dds_rgb)
    {
        if(pf.bit_mask[0]!=0xff0000 || pf.bit_mask[1]!=0xff00 || pf.bit_mask[2]!=0xff )
            return 0;

        if(pf.flags & dds_alpha)
        {
            if(pf.bpp!=32 || pf.bit_mask[3]!=0xff000000U)
                return 0;

            this->pf=bgra;
        }
        else if(pf.bpp==24)
            this->pf=bgr;
        else
            return 0;

        this->mip0_data_size=width*height*(pf.bpp/4);
        for(uint i=0,w=width,h=height;i<mipmap_count;++i,w>1?w/=2:1,h>1?h/=2:1)
            this->data_size+=w*h*(pf.bpp/4);
    }
    else
        return 0;

    unsigned int caps1=reader.read<unsigned int>();
    unsigned int caps2=reader.read<unsigned int>();

    type=texture_2d;
    if(caps2 & dds_cubemap)
    {
        type=texture_cube;
        this->data_size*=6;
    }

    reader.seek(128);
    if(!reader.check_remained(this->data_size))
        return 0;

    this->data=reader.get_data();

    return reader.get_offset();
}

}
<|endoftext|>


<commit_before><commit_msg>coverity#708499 Uninitialized scalar field<commit_after><|endoftext|>


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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <com/sun/star/text/HoriOrientation.hpp>

#ifndef _SV_WINDOW_HXX //autogen
#include <vcl/window.hxx>
#endif

#include "swtypes.hxx"
#include "shdwcrsr.hxx"

using namespace ::com::sun::star;

SwShadowCursor::~SwShadowCursor()
{
    if( USHRT_MAX != nOldMode )
        DrawCrsr( aOldPt, nOldHeight, nOldMode );
}

void SwShadowCursor::SetPos( const Point& rPt, long nHeight, USHORT nMode )
{
    Point aPt( pWin->LogicToPixel( rPt ));
    nHeight = pWin->LogicToPixel( Size( 0, nHeight )).Height();
    if( aOldPt != aPt || nOldHeight != nHeight || nOldMode != nMode )
    {
        if( USHRT_MAX != nOldMode )
            DrawCrsr( aOldPt, nOldHeight, nOldMode );

        DrawCrsr( aPt, nHeight, nMode );
        nOldMode = nMode;
        nOldHeight = nHeight;
        aOldPt = aPt;
    }
}

void SwShadowCursor::DrawTri( const Point& rPt, long nHeight, BOOL bLeft )
{
    long nLineDiff = ( nHeight / 2 );
    long nLineDiffHalf = nLineDiff / 2;

    // Punkt oben
    Point aPt1( (bLeft ? rPt.X() - 3 : rPt.X() + 3),
                rPt.Y() + nLineDiffHalf );
    // Punkt unten
    Point aPt2( aPt1.X(), aPt1.Y() + nHeight - nLineDiff - 1 );
    long nDiff = bLeft ? -1 : 1;
    while( aPt1.Y() <= aPt2.Y() )
    {
        pWin->DrawLine( aPt1, aPt2 );
        aPt1.Y()++, aPt2.Y()--;
        aPt2.X() = aPt1.X() += nDiff;
    }
}

void SwShadowCursor::DrawCrsr( const Point& rPt, long nHeight, USHORT nMode )
{
    nHeight = (((nHeight / 4)+1) * 4) + 1;

    pWin->Push();

    pWin->SetMapMode( MAP_PIXEL );
    pWin->SetRasterOp( ROP_XOR );

    pWin->SetLineColor( Color( aCol.GetColor() ^ COL_WHITE ) );

    // 1. der Strich:
    pWin->DrawLine( Point( rPt.X(), rPt.Y() + 1),
              Point( rPt.X(), rPt.Y() - 2 + nHeight ));

    // 2. das Dreieck
    if( text::HoriOrientation::LEFT == nMode || text::HoriOrientation::CENTER == nMode )    // Pfeil nach rechts
        DrawTri( rPt, nHeight, FALSE );
    if( text::HoriOrientation::RIGHT == nMode || text::HoriOrientation::CENTER == nMode )   // Pfeil nach links
        DrawTri( rPt, nHeight, TRUE );

    pWin->Pop();
}

void SwShadowCursor::Paint()
{
    if( USHRT_MAX != nOldMode )
        DrawCrsr( aOldPt, nOldHeight, nOldMode );
}

Rectangle SwShadowCursor::GetRect() const
{
    long nH = nOldHeight;
    Point aPt( aOldPt );

    nH = (((nH / 4)+1) * 4) + 1;
    long nWidth = nH / 4 + 3 + 1;

    Size aSz( nWidth, nH );

    if( text::HoriOrientation::RIGHT == nOldMode )
        aPt.X() -= aSz.Width();
    else if( text::HoriOrientation::CENTER == nOldMode )
    {
        aPt.X() -= aSz.Width();
        aSz.Width() *= 2;
    }

    return pWin->PixelToLogic( Rectangle( aPt, aSz ) );
}

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

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"

#include <com/sun/star/text/HoriOrientation.hpp>
#include <vcl/window.hxx>

#include "swtypes.hxx"
#include "shdwcrsr.hxx"

using namespace ::com::sun::star;

SwShadowCursor::~SwShadowCursor()
{
    if( USHRT_MAX != nOldMode )
        DrawCrsr( aOldPt, nOldHeight, nOldMode );
}

void SwShadowCursor::SetPos( const Point& rPt, long nHeight, USHORT nMode )
{
    Point aPt( pWin->LogicToPixel( rPt ));
    nHeight = pWin->LogicToPixel( Size( 0, nHeight )).Height();
    if( aOldPt != aPt || nOldHeight != nHeight || nOldMode != nMode )
    {
        if( USHRT_MAX != nOldMode )
            DrawCrsr( aOldPt, nOldHeight, nOldMode );

        DrawCrsr( aPt, nHeight, nMode );
        nOldMode = nMode;
        nOldHeight = nHeight;
        aOldPt = aPt;
    }
}

void SwShadowCursor::DrawTri( const Point& rPt, long nHeight, BOOL bLeft )
{
    long nLineDiff = ( nHeight / 2 );
    long nLineDiffHalf = nLineDiff / 2;

    // Punkt oben
    Point aPt1( (bLeft ? rPt.X() - 3 : rPt.X() + 3),
                rPt.Y() + nLineDiffHalf );
    // Punkt unten
    Point aPt2( aPt1.X(), aPt1.Y() + nHeight - nLineDiff - 1 );
    long nDiff = bLeft ? -1 : 1;
    while( aPt1.Y() <= aPt2.Y() )
    {
        pWin->DrawLine( aPt1, aPt2 );
        aPt1.Y()++, aPt2.Y()--;
        aPt2.X() = aPt1.X() += nDiff;
    }
}

void SwShadowCursor::DrawCrsr( const Point& rPt, long nHeight, USHORT nMode )
{
    nHeight = (((nHeight / 4)+1) * 4) + 1;

    pWin->Push();

    pWin->SetMapMode( MAP_PIXEL );
    pWin->SetRasterOp( ROP_XOR );

    pWin->SetLineColor( Color( aCol.GetColor() ^ COL_WHITE ) );

    // 1. der Strich:
    pWin->DrawLine( Point( rPt.X(), rPt.Y() + 1),
              Point( rPt.X(), rPt.Y() - 2 + nHeight ));

    // 2. das Dreieck
    if( text::HoriOrientation::LEFT == nMode || text::HoriOrientation::CENTER == nMode )    // Pfeil nach rechts
        DrawTri( rPt, nHeight, FALSE );
    if( text::HoriOrientation::RIGHT == nMode || text::HoriOrientation::CENTER == nMode )   // Pfeil nach links
        DrawTri( rPt, nHeight, TRUE );

    pWin->Pop();
}

void SwShadowCursor::Paint()
{
    if( USHRT_MAX != nOldMode )
        DrawCrsr( aOldPt, nOldHeight, nOldMode );
}

Rectangle SwShadowCursor::GetRect() const
{
    long nH = nOldHeight;
    Point aPt( aOldPt );

    nH = (((nH / 4)+1) * 4) + 1;
    long nWidth = nH / 4 + 3 + 1;

    Size aSz( nWidth, nH );

    if( text::HoriOrientation::RIGHT == nOldMode )
        aPt.X() -= aSz.Width();
    else if( text::HoriOrientation::CENTER == nOldMode )
    {
        aPt.X() -= aSz.Width();
        aSz.Width() *= 2;
    }

    return pWin->PixelToLogic( Rectangle( aPt, aSz ) );
}

<|endoftext|>


<commit_before>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    _______    _                                     *
 *                   (  ____ \  ( \     |\     /|                      *
 *                   | (    \/  | (     ( \   / )                      *
 *                   | (__      | |      \ (_) /                       *
 *                   |  __)     | |       \   /                        *
 *                   | (        | |        ) (                         *
 *                   | )        | (____/\  | |                         *
 *                   |/         (_______/  \_/                         *
 *                                                                     *
 *                                                                     *
 *     fly is an awesome c++11 network library.                        *
 *                                                                     *
 *   @author: lichuan                                                  *
 *   @qq: 308831759                                                    *
 *   @email: 308831759@qq.com                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-24 20:43:56                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include "fly/base/logger.hpp"
#include "fly/net/poller_task.hpp"

namespace fly {
namespace net {

template<typename T>
Poller_Task<T>::Poller_Task(uint64 seq) : Loop_Task(seq)
{
    m_fd = epoll_create1(0);

    if(m_fd < 0)
    {
        LOG_FATAL("epoll_create1 failed in Poller_Task::Poller_Task %s", strerror(errno));
        return;
    }

    m_close_event_fd = eventfd(0, 0);

    if(m_close_event_fd < 0)
    {
        LOG_FATAL("close event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    m_write_event_fd = eventfd(0, 0);

    if(m_write_event_fd < 0)
    {
        LOG_FATAL("write event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    m_stop_event_fd = eventfd(0, 0);

    if(m_stop_event_fd < 0)
    {
        LOG_FATAL("stop event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    struct epoll_event event;
    m_close_udata.reset(new Connection<T>(m_close_event_fd, Addr("close_event", 0)));
    event.data.ptr = m_close_udata.get();
    event.events = EPOLLIN;
    int32 ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_close_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("close event epoll_ctl failed in Poller_Task::Poller_Task");
        return;
    }

    m_write_udata.reset(new Connection<T>(m_write_event_fd, Addr("write_event", 0)));
    event.data.ptr = m_write_udata.get();
    ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_write_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("write event epoll_ctl failed in Poller_Task::Poller_Task");
        return;
    }

    m_stop_udata.reset(new Connection<T>(m_stop_event_fd, Addr("stop_event", 0)));
    event.data.ptr = m_stop_udata.get();
    ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_stop_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("stop event epoll_ctl failed in Poller_Task::Poller_Task");
    }
}

template<typename T>
bool Poller_Task<T>::register_connection(std::shared_ptr<Connection<T>> connection)
{
    struct epoll_event event;
    event.data.ptr = connection.get();
    event.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET;
    connection->m_poller_task = this;
    connection->m_self = connection;
    connection->m_init_cb(connection);
    int32 ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, connection->m_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("epoll_ctl failed in Poller_Task::register_connection: %s", strerror(errno));
        close(connection->m_fd);
        connection->m_closed.store(true, std::memory_order_relaxed);
        connection->m_be_closed_cb(connection->shared_from_this());
        connection->m_self.reset();

        return false;
    }

    return true;
}

template<typename T>
void Poller_Task<T>::close_connection(std::shared_ptr<Connection<T>> connection)
{
    m_close_queue.push(connection);
    uint64 data = 1;
    int32 num = write(m_close_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_close_event_fd failed in Poller_Task::close_connection");
    }
}

template<typename T>
void Poller_Task<T>::stop()
{
    uint64 data = 1;
    int32 num = write(m_stop_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_stop_event_fd failed in Poller_Task::stop");
    }
}

template<typename T>
void Poller_Task<T>::write_connection(std::shared_ptr<Connection<T>> connection)
{
    m_write_queue.push(connection);
    uint64 data = 1;
    int32 num = write(m_write_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_write_event_fd failed in Poller_Task::write_connection");
    }
}

template<typename T>
void Poller_Task<T>::do_write(std::shared_ptr<Connection<T>> connection)
{
    int32 fd = connection->m_fd;
    Message_Chunk_Queue &send_queue = connection->m_send_msg_queue;

    while(Message_Chunk *message_chunk = send_queue.pop())
    {
        int32 message_length = message_chunk->length();
        int32 num = write(fd, message_chunk->read_ptr(), message_length);

        if(num < 0)
        {
            if(errno == EAGAIN || errno == EWOULDBLOCK)
            {
                send_queue.push_front(message_chunk);

                break;
            }
        }

        if(num == 0)
        {
            LOG_FATAL("write return 0, it's impossible, in Poller_Task::do_write(arg)");
        }

        if(num <= 0)
        {
            epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);
            close(fd);
            connection->m_self.reset();
            connection->m_closed.store(true, std::memory_order_relaxed);
            connection->m_be_closed_cb(connection);

            break;
        }

        if(num < message_length)
        {
            message_chunk->read_ptr(num);
            send_queue.push_front(message_chunk);

            break;
        }
        else
        {
            delete message_chunk;
        }
    }
}

template<typename T>
void Poller_Task<T>::do_write()
{
    uint64 data = 0;
    int32 num = read(m_write_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("read m_write_event_fd failed in Poller_Task::do_write");

        return;
    }

    std::list<std::shared_ptr<Connection<T>>> write_queue;

    if(m_write_queue.pop(write_queue))
    {
        for(auto &connection : write_queue)
        {
            if(!connection->m_closed.load(std::memory_order_relaxed))
            {
                do_write(connection);
            }
        }
    }
}

template<typename T>
void Poller_Task<T>::do_close()
{
    uint64 data = 0;
    int32 num = read(m_close_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("read m_close_event_fd failed in Poller_Task::do_close");

        return;
    }

    std::list<std::shared_ptr<Connection<T>>> close_queue;

    if(m_close_queue.pop(close_queue))
    {
        for(auto &connection : close_queue)
        {
            if(!connection->m_closed.load(std::memory_order_relaxed))
            {
                int32 fd = connection->m_fd;
                int ret = epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);

                if(ret < 0)
                {
                    LOG_FATAL("epoll_ctl EPOLL_CTL_DEL failed in Poller_Task::do_close: %s", strerror(errno));
                }

                close(fd);
                connection->m_self.reset();
                connection->m_closed.store(true, std::memory_order_relaxed);
                connection->m_close_cb(connection);
            }
        }
    }
}

template<typename T>
void Poller_Task<T>::run_in_loop()
{
    struct epoll_event events[2048];
    int32 fd_num = epoll_wait(m_fd, events, 2048, -1);

    if(fd_num < 0)
    {
        LOG_FATAL("epoll_wait failed in Poller_Task::run_in_loop %s", strerror(errno));

        return;
    }

    for(auto i = 0; i < fd_num; ++i)
    {
        Connection<T> *connection = static_cast<Connection<T>*>(events[i].data.ptr);
        int32 fd = connection->m_fd;
        uint32 event = events[i].events;

        if(event & (EPOLLERR | EPOLLHUP | EPOLLRDHUP))
        {
            if(connection->m_closed.load(std::memory_order_relaxed))
            {
                continue;
            }

            int ret = epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);

            if(ret < 0)
            {
                LOG_FATAL("epoll_ctl EPOLL_CTL_DEL failed in Poller_Task::run_in_loop: %s", strerror(errno));
            }

            close(fd);
            connection->m_closed.store(true, std::memory_order_relaxed);
            connection->m_be_closed_cb(connection->shared_from_this());
            connection->m_self.reset();
        }
        else if(event & EPOLLIN)
        {
            if(fd == m_close_event_fd)
            {
                do_close();
            }
            else if(fd == m_write_event_fd)
            {
                do_write();
            }
            else if(fd == m_stop_event_fd)
            {
                Loop_Task::stop();
                close(m_fd);
                break;
            }
            else
            {
                if(connection->m_closed.load(std::memory_order_relaxed))
                {
                    continue;
                }

                while(true)
                {
                    const uint32 REQ_SIZE = 100 * 1024;
                    Message_Chunk_Queue &recv_queue = connection->m_recv_msg_queue;
                    std::unique_ptr<Message_Chunk> message_chunk(new Message_Chunk(REQ_SIZE));
                    int32 num = read(fd, message_chunk->read_ptr(), REQ_SIZE);

                    if(num < 0)
                    {
                        if(errno == EAGAIN || errno == EWOULDBLOCK)
                        {
                            break;
                        }
                    }

                    if(num <= 0)
                    {
                        epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);
                        close(fd);
                        connection->m_closed.store(true, std::memory_order_relaxed);
                        connection->m_be_closed_cb(connection->shared_from_this());
                        connection->m_self.reset();

                        break;
                    }

                    message_chunk->write_ptr(num);
                    recv_queue.push(message_chunk.release());
                    connection->parse();

                    if(num < REQ_SIZE)
                    {
                        break;
                    }
                }
            }
        }
        else if(event & EPOLLOUT)
        {
            if(connection->m_closed.load(std::memory_order_relaxed))
            {
                continue;
            }

            do_write(connection->shared_from_this());
        }
    }
}

template class Poller_Task<Json>;
template class Poller_Task<Wsock>;
template class Poller_Task<Proto>;

}
}
<commit_msg>fix epoll EPOLLOUT event<commit_after>/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *                    _______    _                                     *
 *                   (  ____ \  ( \     |\     /|                      *
 *                   | (    \/  | (     ( \   / )                      *
 *                   | (__      | |      \ (_) /                       *
 *                   |  __)     | |       \   /                        *
 *                   | (        | |        ) (                         *
 *                   | )        | (____/\  | |                         *
 *                   |/         (_______/  \_/                         *
 *                                                                     *
 *                                                                     *
 *     fly is an awesome c++11 network library.                        *
 *                                                                     *
 *   @author: lichuan                                                  *
 *   @qq: 308831759                                                    *
 *   @email: 308831759@qq.com                                          *
 *   @github: https://github.com/lichuan/fly                           *
 *   @date: 2015-06-24 20:43:56                                        *
 *                                                                     *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include "fly/base/logger.hpp"
#include "fly/net/poller_task.hpp"

namespace fly {
namespace net {

template<typename T>
Poller_Task<T>::Poller_Task(uint64 seq) : Loop_Task(seq)
{
    m_fd = epoll_create1(0);

    if(m_fd < 0)
    {
        LOG_FATAL("epoll_create1 failed in Poller_Task::Poller_Task %s", strerror(errno));
        return;
    }

    m_close_event_fd = eventfd(0, 0);

    if(m_close_event_fd < 0)
    {
        LOG_FATAL("close event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    m_write_event_fd = eventfd(0, 0);

    if(m_write_event_fd < 0)
    {
        LOG_FATAL("write event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    m_stop_event_fd = eventfd(0, 0);

    if(m_stop_event_fd < 0)
    {
        LOG_FATAL("stop event eventfd failed in Poller_Task::Poller_Task");
        return;
    }

    struct epoll_event event;
    m_close_udata.reset(new Connection<T>(m_close_event_fd, Addr("close_event", 0)));
    event.data.ptr = m_close_udata.get();
    event.events = EPOLLIN;
    int32 ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_close_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("close event epoll_ctl failed in Poller_Task::Poller_Task");
        return;
    }

    m_write_udata.reset(new Connection<T>(m_write_event_fd, Addr("write_event", 0)));
    event.data.ptr = m_write_udata.get();
    ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_write_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("write event epoll_ctl failed in Poller_Task::Poller_Task");
        return;
    }

    m_stop_udata.reset(new Connection<T>(m_stop_event_fd, Addr("stop_event", 0)));
    event.data.ptr = m_stop_udata.get();
    ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, m_stop_event_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("stop event epoll_ctl failed in Poller_Task::Poller_Task");
    }
}

template<typename T>
bool Poller_Task<T>::register_connection(std::shared_ptr<Connection<T>> connection)
{
    struct epoll_event event;
    event.data.ptr = connection.get();
    event.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET;
    connection->m_poller_task = this;
    connection->m_self = connection;
    connection->m_init_cb(connection);
    int32 ret = epoll_ctl(m_fd, EPOLL_CTL_ADD, connection->m_fd, &event);

    if(ret < 0)
    {
        LOG_FATAL("epoll_ctl failed in Poller_Task::register_connection: %s", strerror(errno));
        close(connection->m_fd);
        connection->m_closed.store(true, std::memory_order_relaxed);
        connection->m_be_closed_cb(connection->shared_from_this());
        connection->m_self.reset();

        return false;
    }

    return true;
}

template<typename T>
void Poller_Task<T>::close_connection(std::shared_ptr<Connection<T>> connection)
{
    m_close_queue.push(connection);
    uint64 data = 1;
    int32 num = write(m_close_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_close_event_fd failed in Poller_Task::close_connection");
    }
}

template<typename T>
void Poller_Task<T>::stop()
{
    uint64 data = 1;
    int32 num = write(m_stop_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_stop_event_fd failed in Poller_Task::stop");
    }
}

template<typename T>
void Poller_Task<T>::write_connection(std::shared_ptr<Connection<T>> connection)
{
    m_write_queue.push(connection);
    uint64 data = 1;
    int32 num = write(m_write_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("write m_write_event_fd failed in Poller_Task::write_connection");
    }
}

template<typename T>
void Poller_Task<T>::do_write(std::shared_ptr<Connection<T>> connection)
{
    int32 fd = connection->m_fd;
    Message_Chunk_Queue &send_queue = connection->m_send_msg_queue;

    while(Message_Chunk *message_chunk = send_queue.pop())
    {
        int32 message_length = message_chunk->length();
        int32 num = write(fd, message_chunk->read_ptr(), message_length);

        if(num < 0)
        {
            if(errno == EAGAIN || errno == EWOULDBLOCK)
            {
                send_queue.push_front(message_chunk);

                break;
            }
        }

        if(num == 0)
        {
            LOG_FATAL("write return 0, it's impossible, in Poller_Task::do_write(arg)");
        }

        if(num <= 0)
        {
            epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);
            close(fd);
            connection->m_self.reset();
            connection->m_closed.store(true, std::memory_order_relaxed);
            connection->m_be_closed_cb(connection);

            break;
        }

        if(num < message_length)
        {
            message_chunk->read_ptr(num);
            send_queue.push_front(message_chunk);

            break;
        }
        else
        {
            delete message_chunk;
        }
    }
}

template<typename T>
void Poller_Task<T>::do_write()
{
    uint64 data = 0;
    int32 num = read(m_write_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("read m_write_event_fd failed in Poller_Task::do_write");

        return;
    }

    std::list<std::shared_ptr<Connection<T>>> write_queue;

    if(m_write_queue.pop(write_queue))
    {
        for(auto &connection : write_queue)
        {
            if(!connection->m_closed.load(std::memory_order_relaxed))
            {
                do_write(connection);
            }
        }
    }
}

template<typename T>
void Poller_Task<T>::do_close()
{
    uint64 data = 0;
    int32 num = read(m_close_event_fd, &data, sizeof(uint64));

    if(num != sizeof(uint64))
    {
        LOG_FATAL("read m_close_event_fd failed in Poller_Task::do_close");

        return;
    }

    std::list<std::shared_ptr<Connection<T>>> close_queue;

    if(m_close_queue.pop(close_queue))
    {
        for(auto &connection : close_queue)
        {
            if(!connection->m_closed.load(std::memory_order_relaxed))
            {
                int32 fd = connection->m_fd;
                int ret = epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);

                if(ret < 0)
                {
                    LOG_FATAL("epoll_ctl EPOLL_CTL_DEL failed in Poller_Task::do_close: %s", strerror(errno));
                }

                close(fd);
                connection->m_self.reset();
                connection->m_closed.store(true, std::memory_order_relaxed);
                connection->m_close_cb(connection);
            }
        }
    }
}

template<typename T>
void Poller_Task<T>::run_in_loop()
{
    struct epoll_event events[2048];
    int32 fd_num = epoll_wait(m_fd, events, 2048, -1);

    if(fd_num < 0)
    {
        LOG_FATAL("epoll_wait failed in Poller_Task::run_in_loop %s", strerror(errno));

        return;
    }

    for(auto i = 0; i < fd_num; ++i)
    {
        Connection<T> *connection = static_cast<Connection<T>*>(events[i].data.ptr);
        int32 fd = connection->m_fd;
        uint32 event = events[i].events;

        if(event & (EPOLLERR | EPOLLHUP | EPOLLRDHUP))
        {
            if(connection->m_closed.load(std::memory_order_relaxed))
            {
                continue;
            }

            int ret = epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);

            if(ret < 0)
            {
                LOG_FATAL("epoll_ctl EPOLL_CTL_DEL failed in Poller_Task::run_in_loop: %s", strerror(errno));
            }

            close(fd);
            connection->m_closed.store(true, std::memory_order_relaxed);
            connection->m_be_closed_cb(connection->shared_from_this());
            connection->m_self.reset();
        }
        else if(event & EPOLLIN)
        {
            if(fd == m_close_event_fd)
            {
                do_close();
            }
            else if(fd == m_write_event_fd)
            {
                do_write();
            }
            else if(fd == m_stop_event_fd)
            {
                Loop_Task::stop();
                close(m_fd);
                break;
            }
            else
            {
                if(connection->m_closed.load(std::memory_order_relaxed))
                {
                    continue;
                }

                while(true)
                {
                    const uint32 REQ_SIZE = 100 * 1024;
                    Message_Chunk_Queue &recv_queue = connection->m_recv_msg_queue;
                    std::unique_ptr<Message_Chunk> message_chunk(new Message_Chunk(REQ_SIZE));
                    int32 num = read(fd, message_chunk->read_ptr(), REQ_SIZE);

                    if(num < 0)
                    {
                        if(errno == EAGAIN || errno == EWOULDBLOCK)
                        {
                            break;
                        }
                    }

                    if(num <= 0)
                    {
                        epoll_ctl(m_fd, EPOLL_CTL_DEL, fd, NULL);
                        close(fd);
                        connection->m_closed.store(true, std::memory_order_relaxed);
                        connection->m_be_closed_cb(connection->shared_from_this());
                        connection->m_self.reset();

                        break;
                    }

                    message_chunk->write_ptr(num);
                    recv_queue.push(message_chunk.release());
                    connection->parse();

                    if(num < REQ_SIZE)
                    {
                        break;
                    }
                }
            }
        }

        if(event & EPOLLOUT)
        {
            if(connection->m_closed.load(std::memory_order_relaxed))
            {
                continue;
            }

            do_write(connection->shared_from_this());
        }
    }
}

template class Poller_Task<Json>;
template class Poller_Task<Wsock>;
template class Poller_Task<Proto>;

}
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "tri-zip.h"

#include "Basics/files.h"
#include "Basics/FileUtils.h"
#include "Basics/tri-strings.h"
#include "Zip/unzip.h"
#include "Zip/zip.h"

#ifdef _WIN32
#define USEWIN32IOAPI
#include "Zip/iowin32.h"
#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the current file
////////////////////////////////////////////////////////////////////////////////

static int ExtractCurrentFile(unzFile uf, void* buffer, size_t const bufferSize,
                              char const* outPath, bool const skipPaths,
                              bool const overwrite, char const* password,
                              std::string& errorMessage) {
  char filenameInZip[256];
  char* filenameWithoutPath;
  char* fullPath;
  char* p;
  unz_file_info64 fileInfo;
  long systemError;
  int err;

  // cppcheck-suppress *
  FILE* fout;

  filenameInZip[0] = '\0';
  err = unzGetCurrentFileInfo64(uf, &fileInfo, filenameInZip,
                                sizeof(filenameInZip), NULL, 0, NULL, 0);
  if (err != UNZ_OK) {
    errorMessage = std::string("Failed to get file info for ") + filenameInZip +
                   ": " + std::to_string(err);
    return TRI_ERROR_INTERNAL;
  }

  // adjust file name
  p = filenameInZip;
  while (*p != '\0') {
#ifdef WIN32
    if (*p == '/') {
      *p = '\\';
    }
#else
    if (*p == '\\') {
      *p = '/';
    }
#endif
    ++p;
  }

  p = filenameWithoutPath = filenameInZip;

  // get the file name without any path prefix
  while (*p != '\0') {
    if (*p == '/' || *p == '\\' || *p == ':') {
      filenameWithoutPath = p + 1;
    }

    p++;
  }

  // found a directory
  if (*filenameWithoutPath == '\0') {
    if (!skipPaths) {
      fullPath = TRI_Concatenate2File(outPath, filenameInZip);
      int res =
          TRI_CreateRecursiveDirectory(fullPath, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
    }
  }

  // found a file
  else {
    char const* writeFilename;

    if (!skipPaths) {
      writeFilename = filenameInZip;
    } else {
      writeFilename = filenameWithoutPath;
    }

    err = unzOpenCurrentFilePassword(uf, password);
    if (err != UNZ_OK) {
      errorMessage = "failed to authenticate the password in the zip: " +
                     std::to_string(err);
      return TRI_ERROR_INTERNAL;
    }

    // prefix the name from the zip file with the path specified
    fullPath = TRI_Concatenate2File(outPath, writeFilename);

    if (!overwrite && TRI_ExistsFile(fullPath)) {
      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
      errorMessage = std::string("not allowed to overwrite file ") + fullPath;
      return TRI_ERROR_CANNOT_OVERWRITE_FILE;
    }

    // try to write the outfile
    fout = fopen(fullPath, "wb");

    // cannot write to outfile. this may be due to the target directory missing
    if (fout == nullptr && !skipPaths &&
        filenameWithoutPath != (char*)filenameInZip) {
      char c = *(filenameWithoutPath - 1);
      *(filenameWithoutPath - 1) = '\0';

      // create target directory recursively
      char* d = TRI_Concatenate2File(outPath, filenameInZip);
      int res = TRI_CreateRecursiveDirectory(d, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, d);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, d);

      *(filenameWithoutPath - 1) = c;

      // try again
      fout = fopen(fullPath, "wb");
    } else if (fout == nullptr) {
      // try to create the target directory recursively
      char* d = TRI_Concatenate2File(outPath, filenameInZip);
      // strip filename so we only have the directory name
      char* dir = TRI_Dirname(d);
      int res = TRI_CreateRecursiveDirectory(dir, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, d);
        TRI_Free(TRI_CORE_MEM_ZONE, dir);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, d);
      TRI_Free(TRI_CORE_MEM_ZONE, dir);
      // try again
      fout = fopen(fullPath, "wb");
    }

    if (fout == NULL) {
      errorMessage = std::string("failed to open file for writing: ") +
                     fullPath + " - " + strerror(errno);
      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
      return TRI_ERROR_CANNOT_WRITE_FILE;
    }

    while (true) {
      int result = unzReadCurrentFile(uf, buffer, (unsigned int)bufferSize);

      if (result < 0) {
        errorMessage = std::string("failed to write file ") + fullPath + " - " +
                       strerror(errno);
        fclose(fout);
        TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
        return TRI_ERROR_CANNOT_WRITE_FILE;
      }

      if (result > 0) {
        if (fwrite(buffer, result, 1, fout) != 1) {
          errorMessage = std::string("failed to write file ") + fullPath +
                         " - " + strerror(errno);
          TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
          fclose(fout);
          return TRI_set_errno(TRI_ERROR_SYS_ERROR);
        }
      } else {
        TRI_ASSERT(result == 0);
        break;
      }
    }
    TRI_Free(TRI_CORE_MEM_ZONE, fullPath);

    fclose(fout);
  }

  unzCloseCurrentFile(uf);

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief unzips a single file
////////////////////////////////////////////////////////////////////////////////

static int UnzipFile(unzFile uf, void* buffer, size_t const bufferSize,
                     char const* outPath, bool const skipPaths,
                     bool const overwrite, char const* password,
                     std::string& errorMessage) {
  unz_global_info64 gi;
  uLong i;
  int res = TRI_ERROR_NO_ERROR;
  int err;

  err = unzGetGlobalInfo64(uf, &gi);
  if (err != UNZ_OK) {
    errorMessage = "Failed to get info: " + std::to_string(err);
    return TRI_ERROR_INTERNAL;
  }

  for (i = 0; i < gi.number_entry; i++) {
    res = ExtractCurrentFile(uf, buffer, bufferSize, outPath, skipPaths,
                             overwrite, password, errorMessage);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }

    if ((i + 1) < gi.number_entry) {
      err = unzGoToNextFile(uf);
      if (err == UNZ_END_OF_LIST_OF_FILE) {
        break;
      } else if (err != UNZ_OK) {
        errorMessage = "Failed to jump to next file: " + std::to_string(err);
        res = TRI_ERROR_INTERNAL;
        break;
      }
    }
  }

  return res;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief zips a file
////////////////////////////////////////////////////////////////////////////////

int TRI_ZipFile(char const* filename, char const* dir,
                std::vector<std::string> const& files, char const* password) {
  void* buffer;
#ifdef USEWIN32IOAPI
  zlib_filefunc64_def ffunc;
#endif

  if (TRI_ExistsFile(filename)) {
    return TRI_ERROR_CANNOT_OVERWRITE_FILE;
  }

  int bufferSize = 16384;
  buffer = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t)bufferSize, false);

  if (buffer == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

#ifdef USEWIN32IOAPI
  fill_win32_filefunc64A(&ffunc);
  zipFile zf = zipOpen2_64(filename, 0, NULL, &ffunc);
#else
  zipFile zf = zipOpen64(filename, 0);
#endif

  if (zf == nullptr) {
    TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

    return ZIP_ERRNO;
  }

  int res = TRI_ERROR_NO_ERROR;

  size_t n = files.size();
  for (size_t i = 0; i < n; ++i) {
    std::string fullfile;

    if (*dir == '\0') {
      fullfile = files[i];
    } else {
      fullfile = arangodb::basics::FileUtils::buildFilename(dir, files[i]);
    }

    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    uint32_t crc;
    res = TRI_Crc32File(fullfile.c_str(), &crc);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }

    int isLarge = (TRI_SizeFile(files[i].c_str()) > 0xFFFFFFFFLL);

    char const* saveName = files[i].c_str();

    while (*saveName == '\\' || *saveName == '/') {
      ++saveName;
    }

    if (zipOpenNewFileInZip3_64(
            zf, saveName, &zi, NULL, 0, NULL, 0, NULL, /* comment*/
            Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL,
            Z_DEFAULT_STRATEGY, password, (unsigned long)crc,
            isLarge) != ZIP_OK) {
      res = TRI_ERROR_INTERNAL;
      break;
    }

    FILE* fin = fopen(fullfile.c_str(), "rb");

    if (fin == nullptr) {
      break;
    }

    while (true) {
      int sizeRead = (int)fread(buffer, 1, bufferSize, fin);
      if (sizeRead < bufferSize) {
        if (feof(fin) == 0) {
          res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
          break;
        }
      }

      if (sizeRead > 0) {
        res = zipWriteInFileInZip(zf, buffer, sizeRead);
        if (res != 0) {
          break;
        }
      } else /* if (sizeRead <= 0) */ {
        break;
      }
    }

    fclose(fin);

    zipCloseFileInZip(zf);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }
  }

  zipClose(zf, NULL);

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

  return res;
}

int TRI_Adler32(char const* filename, uint32_t& checksum) {
  checksum = 0;

  if (!TRI_IsRegularFile(filename) && !TRI_IsSymbolicLink(filename)) {
    return TRI_ERROR_FILE_NOT_FOUND;
  }

  int fd = TRI_OPEN(filename, O_RDONLY);
  if (fd < 0) {
    return TRI_ERROR_FILE_NOT_FOUND;
  }
  TRI_DEFER(TRI_CLOSE(fd));

  struct TRI_STAT statbuf;
  TRI_FSTAT(fd, &statbuf);

  ssize_t chunkRemain = static_cast<TRI_read_t>(statbuf.st_size);
  char* buf =
      static_cast<char*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, 131072, false));

  if (buf == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

  uLong adler = adler32(0L, Z_NULL, 0);
  while (chunkRemain > 0) {
    TRI_read_t readChunk;
    if (chunkRemain > 131072) {
      readChunk = 131072;
    } else {
      readChunk = chunkRemain;
    }

    ssize_t nRead = TRI_READ(fd, buf, readChunk);

    if (nRead < 0) {
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, buf);
      return TRI_ERROR_INTERNAL;
    }

    adler = adler32(adler, reinterpret_cast<const unsigned char *>(buf), static_cast<uInt>(nRead));
    chunkRemain -= nRead;
  }

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buf);

  checksum = static_cast<uint32_t>(adler);
  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief unzips a file
////////////////////////////////////////////////////////////////////////////////

int TRI_UnzipFile(char const* filename, char const* outPath,
                  bool skipPaths, bool overwrite,
                  char const* password, std::string& errorMessage) {
#ifdef USEWIN32IOAPI
  zlib_filefunc64_def ffunc;
#endif
  size_t bufferSize = 16384;
  void* buffer = (void*)TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, bufferSize, false);

  if (buffer == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

#ifdef USEWIN32IOAPI
  fill_win32_filefunc64A(&ffunc);
  unzFile uf = unzOpen2_64(filename, &ffunc);
#else
  unzFile uf = unzOpen64(filename);
#endif
  if (uf == nullptr) {
    TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);
    errorMessage = std::string("unable to open zip file ") + filename;
    return TRI_ERROR_INTERNAL;
  }

  int res = UnzipFile(uf, buffer, bufferSize, outPath, skipPaths, overwrite,
                      password, errorMessage);

  unzClose(uf);

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

  return res;
}
<commit_msg>honor result of stat() call<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "tri-zip.h"

#include "Basics/files.h"
#include "Basics/FileUtils.h"
#include "Basics/tri-strings.h"
#include "Zip/unzip.h"
#include "Zip/zip.h"

#ifdef _WIN32
#define USEWIN32IOAPI
#include "Zip/iowin32.h"
#endif

////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the current file
////////////////////////////////////////////////////////////////////////////////

static int ExtractCurrentFile(unzFile uf, void* buffer, size_t const bufferSize,
                              char const* outPath, bool const skipPaths,
                              bool const overwrite, char const* password,
                              std::string& errorMessage) {
  char filenameInZip[256];
  char* filenameWithoutPath;
  char* fullPath;
  char* p;
  unz_file_info64 fileInfo;
  long systemError;
  int err;

  // cppcheck-suppress *
  FILE* fout;

  filenameInZip[0] = '\0';
  err = unzGetCurrentFileInfo64(uf, &fileInfo, filenameInZip,
                                sizeof(filenameInZip), NULL, 0, NULL, 0);
  if (err != UNZ_OK) {
    errorMessage = std::string("Failed to get file info for ") + filenameInZip +
                   ": " + std::to_string(err);
    return TRI_ERROR_INTERNAL;
  }

  // adjust file name
  p = filenameInZip;
  while (*p != '\0') {
#ifdef WIN32
    if (*p == '/') {
      *p = '\\';
    }
#else
    if (*p == '\\') {
      *p = '/';
    }
#endif
    ++p;
  }

  p = filenameWithoutPath = filenameInZip;

  // get the file name without any path prefix
  while (*p != '\0') {
    if (*p == '/' || *p == '\\' || *p == ':') {
      filenameWithoutPath = p + 1;
    }

    p++;
  }

  // found a directory
  if (*filenameWithoutPath == '\0') {
    if (!skipPaths) {
      fullPath = TRI_Concatenate2File(outPath, filenameInZip);
      int res =
          TRI_CreateRecursiveDirectory(fullPath, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
    }
  }

  // found a file
  else {
    char const* writeFilename;

    if (!skipPaths) {
      writeFilename = filenameInZip;
    } else {
      writeFilename = filenameWithoutPath;
    }

    err = unzOpenCurrentFilePassword(uf, password);
    if (err != UNZ_OK) {
      errorMessage = "failed to authenticate the password in the zip: " +
                     std::to_string(err);
      return TRI_ERROR_INTERNAL;
    }

    // prefix the name from the zip file with the path specified
    fullPath = TRI_Concatenate2File(outPath, writeFilename);

    if (!overwrite && TRI_ExistsFile(fullPath)) {
      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
      errorMessage = std::string("not allowed to overwrite file ") + fullPath;
      return TRI_ERROR_CANNOT_OVERWRITE_FILE;
    }

    // try to write the outfile
    fout = fopen(fullPath, "wb");

    // cannot write to outfile. this may be due to the target directory missing
    if (fout == nullptr && !skipPaths &&
        filenameWithoutPath != (char*)filenameInZip) {
      char c = *(filenameWithoutPath - 1);
      *(filenameWithoutPath - 1) = '\0';

      // create target directory recursively
      char* d = TRI_Concatenate2File(outPath, filenameInZip);
      int res = TRI_CreateRecursiveDirectory(d, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, d);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, d);

      *(filenameWithoutPath - 1) = c;

      // try again
      fout = fopen(fullPath, "wb");
    } else if (fout == nullptr) {
      // try to create the target directory recursively
      char* d = TRI_Concatenate2File(outPath, filenameInZip);
      // strip filename so we only have the directory name
      char* dir = TRI_Dirname(d);
      int res = TRI_CreateRecursiveDirectory(dir, systemError, errorMessage);

      if (res != TRI_ERROR_NO_ERROR) {
        TRI_Free(TRI_CORE_MEM_ZONE, d);
        TRI_Free(TRI_CORE_MEM_ZONE, dir);
        return res;
      }

      TRI_Free(TRI_CORE_MEM_ZONE, d);
      TRI_Free(TRI_CORE_MEM_ZONE, dir);
      // try again
      fout = fopen(fullPath, "wb");
    }

    if (fout == NULL) {
      errorMessage = std::string("failed to open file for writing: ") +
                     fullPath + " - " + strerror(errno);
      TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
      return TRI_ERROR_CANNOT_WRITE_FILE;
    }

    while (true) {
      int result = unzReadCurrentFile(uf, buffer, (unsigned int)bufferSize);

      if (result < 0) {
        errorMessage = std::string("failed to write file ") + fullPath + " - " +
                       strerror(errno);
        fclose(fout);
        TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
        return TRI_ERROR_CANNOT_WRITE_FILE;
      }

      if (result > 0) {
        if (fwrite(buffer, result, 1, fout) != 1) {
          errorMessage = std::string("failed to write file ") + fullPath +
                         " - " + strerror(errno);
          TRI_Free(TRI_CORE_MEM_ZONE, fullPath);
          fclose(fout);
          return TRI_set_errno(TRI_ERROR_SYS_ERROR);
        }
      } else {
        TRI_ASSERT(result == 0);
        break;
      }
    }
    TRI_Free(TRI_CORE_MEM_ZONE, fullPath);

    fclose(fout);
  }

  unzCloseCurrentFile(uf);

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief unzips a single file
////////////////////////////////////////////////////////////////////////////////

static int UnzipFile(unzFile uf, void* buffer, size_t const bufferSize,
                     char const* outPath, bool const skipPaths,
                     bool const overwrite, char const* password,
                     std::string& errorMessage) {
  unz_global_info64 gi;
  uLong i;
  int res = TRI_ERROR_NO_ERROR;
  int err;

  err = unzGetGlobalInfo64(uf, &gi);
  if (err != UNZ_OK) {
    errorMessage = "Failed to get info: " + std::to_string(err);
    return TRI_ERROR_INTERNAL;
  }

  for (i = 0; i < gi.number_entry; i++) {
    res = ExtractCurrentFile(uf, buffer, bufferSize, outPath, skipPaths,
                             overwrite, password, errorMessage);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }

    if ((i + 1) < gi.number_entry) {
      err = unzGoToNextFile(uf);
      if (err == UNZ_END_OF_LIST_OF_FILE) {
        break;
      } else if (err != UNZ_OK) {
        errorMessage = "Failed to jump to next file: " + std::to_string(err);
        res = TRI_ERROR_INTERNAL;
        break;
      }
    }
  }

  return res;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief zips a file
////////////////////////////////////////////////////////////////////////////////

int TRI_ZipFile(char const* filename, char const* dir,
                std::vector<std::string> const& files, char const* password) {
  void* buffer;
#ifdef USEWIN32IOAPI
  zlib_filefunc64_def ffunc;
#endif

  if (TRI_ExistsFile(filename)) {
    return TRI_ERROR_CANNOT_OVERWRITE_FILE;
  }

  int bufferSize = 16384;
  buffer = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, (size_t)bufferSize, false);

  if (buffer == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

#ifdef USEWIN32IOAPI
  fill_win32_filefunc64A(&ffunc);
  zipFile zf = zipOpen2_64(filename, 0, NULL, &ffunc);
#else
  zipFile zf = zipOpen64(filename, 0);
#endif

  if (zf == nullptr) {
    TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

    return ZIP_ERRNO;
  }

  int res = TRI_ERROR_NO_ERROR;

  size_t n = files.size();
  for (size_t i = 0; i < n; ++i) {
    std::string fullfile;

    if (*dir == '\0') {
      fullfile = files[i];
    } else {
      fullfile = arangodb::basics::FileUtils::buildFilename(dir, files[i]);
    }

    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    uint32_t crc;
    res = TRI_Crc32File(fullfile.c_str(), &crc);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }

    int isLarge = (TRI_SizeFile(files[i].c_str()) > 0xFFFFFFFFLL);

    char const* saveName = files[i].c_str();

    while (*saveName == '\\' || *saveName == '/') {
      ++saveName;
    }

    if (zipOpenNewFileInZip3_64(
            zf, saveName, &zi, NULL, 0, NULL, 0, NULL, /* comment*/
            Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, -MAX_WBITS, DEF_MEM_LEVEL,
            Z_DEFAULT_STRATEGY, password, (unsigned long)crc,
            isLarge) != ZIP_OK) {
      res = TRI_ERROR_INTERNAL;
      break;
    }

    FILE* fin = fopen(fullfile.c_str(), "rb");

    if (fin == nullptr) {
      break;
    }

    while (true) {
      int sizeRead = (int)fread(buffer, 1, bufferSize, fin);
      if (sizeRead < bufferSize) {
        if (feof(fin) == 0) {
          res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
          break;
        }
      }

      if (sizeRead > 0) {
        res = zipWriteInFileInZip(zf, buffer, sizeRead);
        if (res != 0) {
          break;
        }
      } else /* if (sizeRead <= 0) */ {
        break;
      }
    }

    fclose(fin);

    zipCloseFileInZip(zf);

    if (res != TRI_ERROR_NO_ERROR) {
      break;
    }
  }

  zipClose(zf, NULL);

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

  return res;
}

int TRI_Adler32(char const* filename, uint32_t& checksum) {
  checksum = 0;

  if (!TRI_IsRegularFile(filename) && !TRI_IsSymbolicLink(filename)) {
    return TRI_ERROR_FILE_NOT_FOUND;
  }

  int fd = TRI_OPEN(filename, O_RDONLY);
  if (fd < 0) {
    return TRI_ERROR_FILE_NOT_FOUND;
  }
  TRI_DEFER(TRI_CLOSE(fd));

  struct TRI_STAT statbuf;
  int res = TRI_FSTAT(fd, &statbuf);
  if (res < 0) {
    TRI_SYSTEM_ERROR();
    return TRI_set_errno(TRI_ERROR_SYS_ERROR);
  }

  ssize_t chunkRemain = static_cast<TRI_read_t>(statbuf.st_size);
  char* buf =
      static_cast<char*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, 131072, false));

  if (buf == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

  uLong adler = adler32(0L, Z_NULL, 0);
  while (chunkRemain > 0) {
    TRI_read_t readChunk;
    if (chunkRemain > 131072) {
      readChunk = 131072;
    } else {
      readChunk = chunkRemain;
    }

    ssize_t nRead = TRI_READ(fd, buf, readChunk);

    if (nRead < 0) {
      TRI_Free(TRI_UNKNOWN_MEM_ZONE, buf);
      return TRI_ERROR_INTERNAL;
    }

    adler = adler32(adler, reinterpret_cast<const unsigned char *>(buf), static_cast<uInt>(nRead));
    chunkRemain -= nRead;
  }

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buf);

  checksum = static_cast<uint32_t>(adler);
  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief unzips a file
////////////////////////////////////////////////////////////////////////////////

int TRI_UnzipFile(char const* filename, char const* outPath,
                  bool skipPaths, bool overwrite,
                  char const* password, std::string& errorMessage) {
#ifdef USEWIN32IOAPI
  zlib_filefunc64_def ffunc;
#endif
  size_t bufferSize = 16384;
  void* buffer = (void*)TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, bufferSize, false);

  if (buffer == nullptr) {
    return TRI_ERROR_OUT_OF_MEMORY;
  }

#ifdef USEWIN32IOAPI
  fill_win32_filefunc64A(&ffunc);
  unzFile uf = unzOpen2_64(filename, &ffunc);
#else
  unzFile uf = unzOpen64(filename);
#endif
  if (uf == nullptr) {
    TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);
    errorMessage = std::string("unable to open zip file ") + filename;
    return TRI_ERROR_INTERNAL;
  }

  int res = UnzipFile(uf, buffer, bufferSize, outPath, skipPaths, overwrite,
                      password, errorMessage);

  unzClose(uf);

  TRI_Free(TRI_UNKNOWN_MEM_ZONE, buffer);

  return res;
}
<|endoftext|>


<commit_before>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008, 2009 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

Redistribution and use of HOOMD-blue, in source and binary forms, with or
without modification, are permitted, provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions, and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of HOOMD-blue's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR
ANY WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// $Id: FIREEnergyMinimizerGPU.cc 2587 2010-01-08 17:02:54Z joaander $
// $URL: https://codeblue.umich.edu/hoomd-blue/svn/trunk/libhoomd/updaters/FIREEnergyMinimizerGPU.cc $
// Maintainer: joaander

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include <boost/python.hpp>
using namespace boost::python;
#include <boost/bind.hpp>
using namespace boost;

#include "FIREEnergyMinimizerGPU.h"
#include "FIREEnergyMinimizerGPU.cuh"
#include "TwoStepNVEGPU.h"

/*! \file FIREEnergyMinimizerGPU.h
    \brief Contains code for the FIREEnergyMinimizerGPU class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param group The group of particles this integration method is to work on
    \post The method is constructed with the given particle data and a NULL profiler.
*/
FIREEnergyMinimizerGPU::FIREEnergyMinimizerGPU(boost::shared_ptr<SystemDefinition> sysdef, boost::shared_ptr<ParticleGroup> group, Scalar dt)
    :   FIREEnergyMinimizer(sysdef, group, dt, false)
    {
    const ParticleDataArraysConst& arrays = m_pdata->acquireReadOnly();
    m_nparticles = arrays.nparticles;
    m_pdata->release();

    // only one GPU is supported
    if (exec_conf.gpu.size() != 1)
        {
        cerr << endl << "***Error! Creating a FIREEnergyMinimizer with 0 or more than one GPUs" << endl << endl;
        throw std::runtime_error("Error initializing FIREEnergyMinimizer");
        }

    // allocate the sum arrays
    GPUArray<float> sum(1, m_pdata->getExecConf());
    m_sum.swap(sum);
    GPUArray<float> sum3(3, m_pdata->getExecConf());
    m_sum3.swap(sum3);

    // initialize the partial sum arrays
    m_block_size = 256; //128;
    m_num_blocks = m_nparticles / m_block_size + 1;
    GPUArray<float> partial_sum1(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum1.swap(partial_sum1);
    GPUArray<float> partial_sum2(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum2.swap(partial_sum2);
    GPUArray<float> partial_sum3(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum3.swap(partial_sum3);

    reset();
    createIntegrator();
    }

void FIREEnergyMinimizerGPU::createIntegrator()
    {
    boost::shared_ptr<ParticleSelector> selector_all(new ParticleSelectorTag(m_sysdef, 0, m_pdata->getN()-1));
    boost::shared_ptr<ParticleGroup> group_all(new ParticleGroup(m_sysdef, selector_all));
    boost::shared_ptr<TwoStepNVEGPU> integrator(new TwoStepNVEGPU(m_sysdef, group_all));
    addIntegrationMethod(integrator);
    setDeltaT(m_deltaT);
    }

void FIREEnergyMinimizerGPU::reset()
    {
    m_converged = false;
    m_n_since_negative = 0;
    m_alpha = m_alpha_start;
    m_was_reset = true;
    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
    exec_conf.gpu[0]->call(bind(gpu_fire_zero_v, d_pdata[0]));
    m_pdata->release();
    setDeltaT(m_deltaT_set);
    }

/*! \param timesteps is the iteration number
*/
void FIREEnergyMinimizerGPU::update(unsigned int timesteps)
    {

    if (m_converged)
        return;

    IntegratorTwoStep::update(timesteps);

    Scalar P(0.0);
    Scalar vnorm(0.0);
    Scalar fnorm(0.0);
    Scalar energy(0.0);

    // compute the total energy on the GPU
    // CPU version is Scalar energy = computePotentialEnergy(timesteps)/Scalar(n);
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE compute total energy");

    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadOnlyGPU();
    ArrayHandle<Scalar4> d_net_force(m_pdata->getNetForce(), access_location::device, access_mode::read);
    ArrayHandle<float> d_partial_sumE(m_partial_sum1, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_sumE(m_sum, access_location::device, access_mode::overwrite);
    exec_conf.gpu[0]->call(bind(gpu_fire_compute_sum_pe, d_pdata[0], d_net_force.data, d_sumE.data, d_partial_sumE.data, m_block_size, m_num_blocks));
    }
    {
    ArrayHandle<float> h_sumE(m_sum, access_location::host, access_mode::read);
    energy = h_sumE.data[0]/Scalar(m_nparticles);

    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);

    }

    if (m_was_reset)
        {
        m_was_reset = false;
        m_old_energy = energy + Scalar(100000)*m_etol;
        }

    //sum P, vnorm, fnorm
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE P, vnorm, fnorm");

    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadOnlyGPU();
    ArrayHandle<float> d_partial_sum_P(m_partial_sum1, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_partial_sum_vsq(m_partial_sum2, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_partial_sum_fsq(m_partial_sum3, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_sum(m_sum3, access_location::device, access_mode::overwrite);
    exec_conf.gpu[0]->call(bind(gpu_fire_compute_sum_all, d_pdata[0], d_sum.data, d_partial_sum_P.data, d_partial_sum_vsq.data, d_partial_sum_fsq.data, m_block_size, m_num_blocks));
    }
    {
    ArrayHandle<float> h_sum(m_sum3, access_location::host, access_mode::read);
    P = h_sum.data[0];
    vnorm = sqrt(h_sum.data[1]);
    fnorm = sqrt(h_sum.data[2]);

    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);
    }

    if (fnorm/sqrt(m_sysdef->getNDimensions()*m_nparticles) < m_ftol || fabs(energy-m_old_energy) < m_etol)
        {
        m_converged = true;
        return;
        }

    //update velocities
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE update velocities");

    Scalar invfnorm = 1.0/fnorm;
    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
    exec_conf.gpu[0]->call(bind(gpu_fire_update_v, d_pdata[0], m_alpha, vnorm, invfnorm));
    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);
    }

    if (P > Scalar(0.0))
        {
        m_n_since_negative++;
        if (m_n_since_negative > m_nmin)
            {
            IntegratorTwoStep::setDeltaT(std::min(m_deltaT*m_finc, m_deltaT_max));
            m_alpha *= m_falpha;
            }
        }
    else if (P <= Scalar(0.0))
        {
        IntegratorTwoStep::setDeltaT(m_deltaT*m_fdec);
        m_alpha = m_alpha_start;
        m_n_since_negative = 0;
        if (m_prof)
            m_prof->push(exec_conf, "FIRE zero velocities");
        vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
        exec_conf.gpu[0]->call(bind(gpu_fire_zero_v, d_pdata[0]));
        m_pdata->release();
        if (m_prof)
            m_prof->pop(exec_conf);
        }
    m_old_energy = energy;
    }

void export_FIREEnergyMinimizerGPU()
    {
    class_<FIREEnergyMinimizerGPU, boost::shared_ptr<FIREEnergyMinimizerGPU>,  bases<IntegratorTwoStep>, boost::noncopyable>
        ("FIREEnergyMinimizerGPU", init< boost::shared_ptr<SystemDefinition>, boost::shared_ptr<ParticleGroup>, Scalar >())
        ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif

<commit_msg>fixed GPU base class<commit_after>/*
Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
(HOOMD-blue) Open Source Software License Copyright 2008, 2009 Ames Laboratory
Iowa State University and The Regents of the University of Michigan All rights
reserved.

HOOMD-blue may contain modifications ("Contributions") provided, and to which
copyright is held, by various Contributors who have granted The Regents of the
University of Michigan the right to modify and/or distribute such Contributions.

Redistribution and use of HOOMD-blue, in source and binary forms, with or
without modification, are permitted, provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions, and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions, and the following disclaimer in the documentation and/or
other materials provided with the distribution.

* Neither the name of the copyright holder nor the names of HOOMD-blue's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR
ANY WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// $Id: FIREEnergyMinimizerGPU.cc 2587 2010-01-08 17:02:54Z joaander $
// $URL: https://codeblue.umich.edu/hoomd-blue/svn/trunk/libhoomd/updaters/FIREEnergyMinimizerGPU.cc $
// Maintainer: joaander

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4244 )
#endif

#include <boost/python.hpp>
using namespace boost::python;
#include <boost/bind.hpp>
using namespace boost;

#include "FIREEnergyMinimizerGPU.h"
#include "FIREEnergyMinimizerGPU.cuh"
#include "TwoStepNVEGPU.h"

/*! \file FIREEnergyMinimizerGPU.h
    \brief Contains code for the FIREEnergyMinimizerGPU class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param group The group of particles this integration method is to work on
    \post The method is constructed with the given particle data and a NULL profiler.
*/
FIREEnergyMinimizerGPU::FIREEnergyMinimizerGPU(boost::shared_ptr<SystemDefinition> sysdef, boost::shared_ptr<ParticleGroup> group, Scalar dt)
    :   FIREEnergyMinimizer(sysdef, group, dt, false)
    {
    const ParticleDataArraysConst& arrays = m_pdata->acquireReadOnly();
    m_nparticles = arrays.nparticles;
    m_pdata->release();

    // only one GPU is supported
    if (exec_conf.gpu.size() != 1)
        {
        cerr << endl << "***Error! Creating a FIREEnergyMinimizer with 0 or more than one GPUs" << endl << endl;
        throw std::runtime_error("Error initializing FIREEnergyMinimizer");
        }

    // allocate the sum arrays
    GPUArray<float> sum(1, m_pdata->getExecConf());
    m_sum.swap(sum);
    GPUArray<float> sum3(3, m_pdata->getExecConf());
    m_sum3.swap(sum3);

    // initialize the partial sum arrays
    m_block_size = 256; //128;
    m_num_blocks = m_nparticles / m_block_size + 1;
    GPUArray<float> partial_sum1(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum1.swap(partial_sum1);
    GPUArray<float> partial_sum2(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum2.swap(partial_sum2);
    GPUArray<float> partial_sum3(m_num_blocks, m_pdata->getExecConf());
    m_partial_sum3.swap(partial_sum3);

    reset();
    createIntegrator();
    }

void FIREEnergyMinimizerGPU::createIntegrator()
    {
    boost::shared_ptr<ParticleSelector> selector_all(new ParticleSelectorTag(m_sysdef, 0, m_pdata->getN()-1));
    boost::shared_ptr<ParticleGroup> group_all(new ParticleGroup(m_sysdef, selector_all));
    boost::shared_ptr<TwoStepNVEGPU> integrator(new TwoStepNVEGPU(m_sysdef, group_all));
    addIntegrationMethod(integrator);
    setDeltaT(m_deltaT);
    }

void FIREEnergyMinimizerGPU::reset()
    {
    m_converged = false;
    m_n_since_negative = 0;
    m_alpha = m_alpha_start;
    m_was_reset = true;
    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
    exec_conf.gpu[0]->call(bind(gpu_fire_zero_v, d_pdata[0]));
    m_pdata->release();
    setDeltaT(m_deltaT_set);
    }

/*! \param timesteps is the iteration number
*/
void FIREEnergyMinimizerGPU::update(unsigned int timesteps)
    {

    if (m_converged)
        return;

    IntegratorTwoStep::update(timesteps);

    Scalar P(0.0);
    Scalar vnorm(0.0);
    Scalar fnorm(0.0);
    Scalar energy(0.0);

    // compute the total energy on the GPU
    // CPU version is Scalar energy = computePotentialEnergy(timesteps)/Scalar(n);
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE compute total energy");

    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadOnlyGPU();
    ArrayHandle<Scalar4> d_net_force(m_pdata->getNetForce(), access_location::device, access_mode::read);
    ArrayHandle<float> d_partial_sumE(m_partial_sum1, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_sumE(m_sum, access_location::device, access_mode::overwrite);
    exec_conf.gpu[0]->call(bind(gpu_fire_compute_sum_pe, d_pdata[0], d_net_force.data, d_sumE.data, d_partial_sumE.data, m_block_size, m_num_blocks));
    }
    {
    ArrayHandle<float> h_sumE(m_sum, access_location::host, access_mode::read);
    energy = h_sumE.data[0]/Scalar(m_nparticles);

    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);

    }

    if (m_was_reset)
        {
        m_was_reset = false;
        m_old_energy = energy + Scalar(100000)*m_etol;
        }

    //sum P, vnorm, fnorm
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE P, vnorm, fnorm");

    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadOnlyGPU();
    ArrayHandle<float> d_partial_sum_P(m_partial_sum1, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_partial_sum_vsq(m_partial_sum2, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_partial_sum_fsq(m_partial_sum3, access_location::device, access_mode::overwrite);
    ArrayHandle<float> d_sum(m_sum3, access_location::device, access_mode::overwrite);
    exec_conf.gpu[0]->call(bind(gpu_fire_compute_sum_all, d_pdata[0], d_sum.data, d_partial_sum_P.data, d_partial_sum_vsq.data, d_partial_sum_fsq.data, m_block_size, m_num_blocks));
    }
    {
    ArrayHandle<float> h_sum(m_sum3, access_location::host, access_mode::read);
    P = h_sum.data[0];
    vnorm = sqrt(h_sum.data[1]);
    fnorm = sqrt(h_sum.data[2]);

    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);
    }

    if (fnorm/sqrt(m_sysdef->getNDimensions()*m_nparticles) < m_ftol || fabs(energy-m_old_energy) < m_etol)
        {
        m_converged = true;
        return;
        }

    //update velocities
    {
    if (m_prof)
        m_prof->push(exec_conf, "FIRE update velocities");

    Scalar invfnorm = 1.0/fnorm;
    vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
    exec_conf.gpu[0]->call(bind(gpu_fire_update_v, d_pdata[0], m_alpha, vnorm, invfnorm));
    m_pdata->release();

    if (m_prof)
        m_prof->pop(exec_conf);
    }

    if (P > Scalar(0.0))
        {
        m_n_since_negative++;
        if (m_n_since_negative > m_nmin)
            {
            IntegratorTwoStep::setDeltaT(std::min(m_deltaT*m_finc, m_deltaT_max));
            m_alpha *= m_falpha;
            }
        }
    else if (P <= Scalar(0.0))
        {
        IntegratorTwoStep::setDeltaT(m_deltaT*m_fdec);
        m_alpha = m_alpha_start;
        m_n_since_negative = 0;
        if (m_prof)
            m_prof->push(exec_conf, "FIRE zero velocities");
        vector<gpu_pdata_arrays>& d_pdata = m_pdata->acquireReadWriteGPU();
        exec_conf.gpu[0]->call(bind(gpu_fire_zero_v, d_pdata[0]));
        m_pdata->release();
        if (m_prof)
            m_prof->pop(exec_conf);
        }
    m_old_energy = energy;
    }

void export_FIREEnergyMinimizerGPU()
    {
    class_<FIREEnergyMinimizerGPU, boost::shared_ptr<FIREEnergyMinimizerGPU>,  bases<FIREEnergyMinimizer>, boost::noncopyable>
        ("FIREEnergyMinimizerGPU", init< boost::shared_ptr<SystemDefinition>, boost::shared_ptr<ParticleGroup>, Scalar >())
        ;
    }

#ifdef WIN32
#pragma warning( pop )
#endif

<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_GC_HH__
#define __MINIZINC_GC_HH__

#include <cstdlib>
#include <cassert>
#include <new>

namespace MiniZinc {

  /**
   * \brief Base class for abstract syntax tree nodes
   */
  class ASTNode {
    friend class GC;
  protected:
    /// Mark for garbage collection
    unsigned int _gc_mark : 1;
    /// Id of the node
    unsigned int _id : 7;
    /// Secondary id
    unsigned int _sec_id : 7;
    /// Flag
    unsigned int _flag_1 : 1;
    /// Flag
    unsigned int _flag_2 : 1;

    enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_END = NID_VEC };

    /// Constructor
    ASTNode(unsigned int id) : _gc_mark(0), _id(id) {}

    /// Allocate node
    void* operator new(size_t size) throw (std::bad_alloc);

    /// Placement-new
    void* operator new(size_t, void* n) throw() {
      return n;
    }

    /// Delete node (no-op)
    void operator delete(void*, size_t) throw() { }
    /// Delete node (no-op)
    void operator delete(void*, void*) throw() { }

    /// Delete node (no-op)
    void operator delete(void*) throw() {}
  };

  /**
   * \brief Base class for unstructured garbage collected data
   */
  class ASTChunk : public ASTNode {
    friend class GC;
  protected:
    ASTChunk* _next;
    size_t _size;
    char _data[4];
    ASTChunk(size_t size);
    size_t memsize(void) const {
      size_t s = sizeof(ASTChunk)+(_size<=4?0:_size-4)*sizeof(char);
      s += ((8 - (s & 7)) & 7);
      return s;
    }
    static void* alloc(size_t size);
  };

  /**
   * \brief Base class for structured garbage collected data
   */
  class ASTVec : public ASTNode {
    friend class GC;
  protected:
    ASTVec* _next;
    size_t _size;
    void* _data[2];
    ASTVec(size_t size);
    size_t memsize(void) const {
      size_t s = sizeof(ASTVec)+(_size<=2?0:_size-2)*sizeof(void*);
      s += ((8 - (s & 7)) & 7);
      return s;
    }
    static void* alloc(size_t size);
  };

  class Model;
  class Expression;

  class ASTRootSetIter {
  public:
    virtual Expression** begin(void) = 0;
    virtual Expression** end(void) = 0;
    virtual ~ASTRootSetIter(void) {}
  };
  class ASTRootSet {
  public:
    virtual ASTRootSetIter* rootSet(void) = 0;
  };

  /// Garbage collector
  class GC {
    friend class ASTNode;
    friend class ASTVec;
    friend class ASTChunk;
  private:
    class Heap;
    /// The memory controlled by the collector
    Heap* _heap;
    /// Count how many locks are currently active
    unsigned int _lock_count;
    /// Return thread-local GC object
    static GC*& gc(void);
    /// Constructor
    GC(void);

    /// Allocate garbage collected memory
    void* alloc(size_t size);

  public:
    /**
     * \brief Initialize thread-local GC object
     *
     * Must be called at least once per thread
     */
    static void init(void);
    /// Acquire garbage collector lock for this thread
    static void lock(void);
    /// Release garbage collector lock for this thread
    static void unlock(void);
    /// Test if garbage collector is locked
    static bool locked(void);
    /// Add model \a m to root set
    static void add(Model* m);
    /// Remove model \a m from root set
    static void remove(Model* m);

    /// Put a mark on the trail
    static void mark(void);
    /// Add a trail entry
    static void trail(void**,void*);
    /// Untrail to previous mark
    static void untrail(void);

    /// Add external root set
    static void addRootSet(ASTRootSet* rs);
    /// Remove external root set
    static void removeRootSet(ASTRootSet* rs);
  };

  /// Automatic garbage collection lock
  class GCLock {
  public:
    /// Acquire lock
    GCLock(void);
    /// Release lock upon destruction
    ~GCLock(void);
  };

}

#endif
<commit_msg>Remove unused fields<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_GC_HH__
#define __MINIZINC_GC_HH__

#include <cstdlib>
#include <cassert>
#include <new>

namespace MiniZinc {

  /**
   * \brief Base class for abstract syntax tree nodes
   */
  class ASTNode {
    friend class GC;
  protected:
    /// Mark for garbage collection
    unsigned int _gc_mark : 1;
    /// Id of the node
    unsigned int _id : 7;
    /// Secondary id
    unsigned int _sec_id : 7;
    /// Flag
    unsigned int _flag_1 : 1;
    /// Flag
    unsigned int _flag_2 : 1;

    enum BaseNodes { NID_FL, NID_CHUNK, NID_VEC, NID_END = NID_VEC };

    /// Constructor
    ASTNode(unsigned int id) : _gc_mark(0), _id(id) {}

    /// Allocate node
    void* operator new(size_t size) throw (std::bad_alloc);

    /// Placement-new
    void* operator new(size_t, void* n) throw() {
      return n;
    }

    /// Delete node (no-op)
    void operator delete(void*, size_t) throw() { }
    /// Delete node (no-op)
    void operator delete(void*, void*) throw() { }

    /// Delete node (no-op)
    void operator delete(void*) throw() {}
  };

  /**
   * \brief Base class for unstructured garbage collected data
   */
  class ASTChunk : public ASTNode {
    friend class GC;
  protected:
    size_t _size;
    char _data[4];
    ASTChunk(size_t size);
    size_t memsize(void) const {
      size_t s = sizeof(ASTChunk)+(_size<=4?0:_size-4)*sizeof(char);
      s += ((8 - (s & 7)) & 7);
      return s;
    }
    static void* alloc(size_t size);
  };

  /**
   * \brief Base class for structured garbage collected data
   */
  class ASTVec : public ASTNode {
    friend class GC;
  protected:
    size_t _size;
    void* _data[2];
    ASTVec(size_t size);
    size_t memsize(void) const {
      size_t s = sizeof(ASTVec)+(_size<=2?0:_size-2)*sizeof(void*);
      s += ((8 - (s & 7)) & 7);
      return s;
    }
    static void* alloc(size_t size);
  };

  class Model;
  class Expression;

  class ASTRootSetIter {
  public:
    virtual Expression** begin(void) = 0;
    virtual Expression** end(void) = 0;
    virtual ~ASTRootSetIter(void) {}
  };
  class ASTRootSet {
  public:
    virtual ASTRootSetIter* rootSet(void) = 0;
  };

  /// Garbage collector
  class GC {
    friend class ASTNode;
    friend class ASTVec;
    friend class ASTChunk;
  private:
    class Heap;
    /// The memory controlled by the collector
    Heap* _heap;
    /// Count how many locks are currently active
    unsigned int _lock_count;
    /// Return thread-local GC object
    static GC*& gc(void);
    /// Constructor
    GC(void);

    /// Allocate garbage collected memory
    void* alloc(size_t size);

  public:
    /**
     * \brief Initialize thread-local GC object
     *
     * Must be called at least once per thread
     */
    static void init(void);
    /// Acquire garbage collector lock for this thread
    static void lock(void);
    /// Release garbage collector lock for this thread
    static void unlock(void);
    /// Test if garbage collector is locked
    static bool locked(void);
    /// Add model \a m to root set
    static void add(Model* m);
    /// Remove model \a m from root set
    static void remove(Model* m);

    /// Put a mark on the trail
    static void mark(void);
    /// Add a trail entry
    static void trail(void**,void*);
    /// Untrail to previous mark
    static void untrail(void);

    /// Add external root set
    static void addRootSet(ASTRootSet* rs);
    /// Remove external root set
    static void removeRootSet(ASTRootSet* rs);
  };

  /// Automatic garbage collection lock
  class GCLock {
  public:
    /// Acquire lock
    GCLock(void);
    /// Release lock upon destruction
    ~GCLock(void);
  };

}

#endif
<|endoftext|>