<commit_before>// Copyright (C) 2015 SRG Technology, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "anyrpc/api.h"
#include "anyrpc/logger.h"
#include "anyrpc/error.h"
#include "anyrpc/value.h"
#include "anyrpc/stream.h"
#include "anyrpc/handler.h"
#include "anyrpc/reader.h"
#include "anyrpc/document.h"
#include "anyrpc/method.h"
#include "anyrpc/socket.h"
#include "anyrpc/client.h"
#include "anyrpc/internal/time.h"

namespace anyrpc
{

#if defined(ANYRPC_THREADING)
std::atomic<unsigned> ClientHandler::nextId_(1);
#else
unsigned ClientHandler::nextId_ = 1;
#endif // defined(ANYRPC_THREADING)

int ClientHandler::GetNextId()
{
    return nextId_++;
}

void ClientHandler::GenerateFaultResult(int errorCode, std::string const& errorMsg, Value& result)
{
    result["code"] = errorCode;
    result["message"] = errorMsg;
}

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

Client::Client(ClientHandler* handler)
{
    handler_ = handler;
    port_ = 0;
    timeout_ = 60000;
    responseAllocated_ = false;
    responseProcessed_ = false;
    ResetReceiveBuffer();
    ResetTransaction();
}

Client::Client(ClientHandler* handler, const char* host, int port)
{
    handler_ = handler;
    host_ = host;
    port_ = port;
    timeout_ = 60000;
    responseAllocated_ = false;
    responseProcessed_ = false;
    ResetReceiveBuffer();
    ResetTransaction();
}

Client::~Client()
{
    if (responseAllocated_)
        free(response_);
    Close();
}

bool Client::Call(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        // continue with the processing
        if (ReadHeader(result) &&
            ReadResponse(result))
        {
            switch (ProcessResponse(result))
            {
                case ProcessResponseSuccess       : return true;
                case ProcessResponseErrorKeepOpen : return false;
            }
        }
    }
    Reset();
    return false;
}

bool Client::Post(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        return true;
    }
    Reset();
    return false;
}

bool Client::GetPostResult(Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    if (responseProcessed_)
    {
        PreserveReceiveBuffer();
        ResetTransaction();
    }

    if (socket_.IsConnected(0) &&
        ReadHeader(result) &&
        ReadResponse(result))
    {
        switch (ProcessResponse(result))
        {
            case ProcessResponseSuccess       : return true;
            case ProcessResponseErrorKeepOpen : return false;
        }
    }

    Reset();
    return false;
}

bool Client::Notify(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params, true) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        // Not all notification require a response
        if (!TransportHasNotifyResponse())
        {
            requestId_.pop_front();
            return true;
        }
        // continue with the processing response
        if (ReadHeader(result) &&
            ReadResponse(result))
        {
            // don't process the response for a notification
            requestId_.pop_front();
            result.SetNull();
            return true;
        }
    }
    Reset();
    return false;
}

void Client::Reset()
{
    Close();
    ResetReceiveBuffer();
    ResetTransaction();
    requestId_.clear();
}

void Client::ResetTransaction()
{
    contentLength_ = 0;
    if (responseAllocated_)
        free(response_);
    response_ = 0;
    responseAllocated_ = false;
    responseProcessed_ = false;
    contentAvail_ = 0;
    header_.Clear();
    request_.Clear();
}

void Client::PreserveReceiveBuffer()
{
    // only need to consider preserving data if we didn't need to allocate a new buffer
    // if a new buffer was allocated, then only the required data would be read
    if (!responseAllocated_)
    {
        if (response_ != 0)
        {
            // a response was processed so there might be data left in the buffer
            if (contentAvail_ > contentLength_)
            {
                // there is data left in the buffer move it to the start of the buffer
                char* responseEnd = response_ + contentLength_;
                size_t dataRemaining = contentAvail_ - contentLength_;
                log_debug("PreserveReceiveBuffer: Preserve data: " << dataRemaining << " bytes");
                memmove(buffer_, responseEnd, dataRemaining);
                bufferLength_ = dataRemaining;
            }
            else
            {
                log_debug("PreserveReceiveBuffer: No data to preserve");
                bufferLength_ = 0;
            }
        }
        else
            log_debug("PreserveReceiveBuffer: Keep any previous data: " << bufferLength_ << " bytes");
    }
    else
    {
        log_debug("PreserveReceiveBuffer: Reset buffer");
        bufferLength_ = 0;
    }
    responseProcessed_ = true;
}

unsigned Client::GetTimeLeft()
{
    struct timeval currentTime;
    gettimeofday( &currentTime, 0 );

    int timeUsed = MilliTimeDiff(currentTime,startTime_);

    int timeLeft = std::max(0,(int)timeout_ - timeUsed);

    log_debug("GetTimeLeft: timeout=" << timeout_ << ", timeLeft=" << timeLeft << ", timeUsed=" << timeUsed);
    return timeLeft;
}

bool Client::Connect(Value& result)
{
    log_trace();
    if (socket_.IsConnected(0))
    {
        log_debug("Already connected");
        return true;
    }
    // Close the connection but keep any data that has been setup for the next message
    Close();
    ResetReceiveBuffer();

    log_debug("Create a new connection");
    socket_.Create();
    socket_.SetNonBlocking();

    socket_.Connect(host_.c_str(), port_);

    socket_.SetKeepAlive();
    socket_.SetTcpNoDelay();

    if (!socket_.IsConnected(GetTimeLeft()))
    {
        socket_.Close();
        return false;
    }
    return true;
}

bool Client::GenerateRequest(const char* method, Value& params, bool notification)
{
    int requestId;

    bool result = handler_->GenerateRequest(method,params,request_,requestId,notification);
    requestId_.push_back(requestId);
    return result;
}

bool Client::WriteRequest(Value& result)
{
    log_trace();

    size_t bytesWritten;
    size_t bytesToSend;

    // write the header - it make be in several segments
    size_t headerBytesWritten = 0;
    while (headerBytesWritten < header_.Length())
    {
        const char* buffer = header_.GetBuffer(headerBytesWritten, bytesToSend);
        if (!socket_.Send(buffer, bytesToSend, bytesWritten, GetTimeLeft()))
            return false;

        headerBytesWritten += bytesWritten;

        if (bytesToSend < bytesWritten)
            return false;   // timeout
    }

    // write the request - it make be in several segments
    size_t requestBytesWritten = 0;
    while (requestBytesWritten < request_.Length())
    {
        const char* buffer = request_.GetBuffer(requestBytesWritten, bytesToSend);
        if (!socket_.Send(buffer, bytesToSend, bytesWritten, GetTimeLeft()))
            return false;

        requestBytesWritten += bytesWritten;

        if (bytesToSend < bytesWritten)
            return false;   // timeout
    }

    return true;
}

bool Client::ReadHeader(Value& result)
{
    log_trace();
    // Read available data
    socket_.SetTimeout(0);
    while (true)
    {
        int bytesRead;
        bool eof;
        socket_.Receive(buffer_+bufferLength_, MaxBufferLength-bufferLength_, bytesRead, eof, 0);
        if (socket_.FatalError())
        {
            log_warn("error while reading header: " << socket_.GetLastError() << ", bytesRead=" << bytesRead);
            return false;
        }
        bufferLength_ += bytesRead;
        log_info("read=" << bytesRead << ", total=" << bufferLength_);

        switch (ProcessHeader(eof))
        {
            case HEADER_COMPLETE : return true;
            case HEADER_FAULT : return false;
        }
        unsigned timeLeft = GetTimeLeft();
        if (timeLeft == 0)
        {
            handler_->GenerateFaultResult(AnyRpcErrorTransportError,"Timeout reading response header",result);
            break;
        }
        socket_.WaitReadable(timeLeft);
    }
    return false;
}

bool Client::ReadResponse(Value& result)
{
    log_trace();
    if (contentAvail_ >= contentLength_)
        return true;

    int bytesRead;
    bool eof;
    bool receiveResult = socket_.Receive(response_+contentAvail_, contentLength_-contentAvail_, bytesRead, eof, GetTimeLeft());
    contentAvail_ += bytesRead;
    response_[contentAvail_] = 0;
    if (!receiveResult)
        handler_->GenerateFaultResult(AnyRpcErrorTransportError,"Failed reading response",result);
    return receiveResult;
}

ProcessResponseEnum Client::ProcessResponse(Value& result, bool notification)
{
    int requestId = requestId_.front();
    requestId_.pop_front();
    responseProcessed_ = true;
    return handler_->ProcessResponse(response_,contentLength_,result,requestId,notification);
}

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

bool HttpClient::GenerateHeader()
{
    log_trace();
    header_ << "POST /RPC2 HTTP/1.1\r\n";
    header_ << "User-Agent: " << ANYRPC_APP_NAME << " v" << ANYRPC_VERSION_STRING << "\r\n";
    header_ << "Host: " << host_ << ":" << port_ << "\r\n";
    header_ << "Content-Type: " << contentType_ << "\r\n";
    header_ << "Accept: " << contentType_ << "\r\n";
    header_ << "Content-length: " << request_.Length() << "\r\n";
    header_ << "\r\n";

    return true;
}

int HttpClient::ProcessHeader(bool eof)
{
    log_trace();
    switch (httpResponseState_.ProcessHeaderData(buffer_, bufferLength_, eof))
    {
        case internal::HttpHeader::HEADER_FAULT         : return HEADER_FAULT;
        case internal::HttpHeader::HEADER_INCOMPLETE    : return HEADER_INCOMPLETE;
    }

    size_t bodyStartPos = httpResponseState_.GetBodyStartPos();
    size_t bufferSpaceAvail = MaxBufferLength - bodyStartPos;

    contentLength_ = httpResponseState_.GetContentLength();
    contentAvail_ = bufferLength_ - bodyStartPos;
    //keepAlive_ = httpResponseState_.GetKeepAlive();

    if (contentLength_ > MaxContentLength)
    {
        log_warn("Content-length too large=" << contentLength_ << ", max allowed=" << MaxContentLength);
        return HEADER_FAULT;
    }
    if (contentLength_ > (int)bufferSpaceAvail)
    {
        // try to malloc the buffer space needed
        response_ = static_cast<char*>(malloc(contentLength_+1));
        if (response_ == 0)
        {
            log_warn("Could not allocate space=" << contentLength_);
            return HEADER_FAULT;
        }
        // copy the content that was already read to the new space
        memcpy(response_,buffer_+bodyStartPos,contentAvail_);
        responseAllocated_ = true;
    }
    else
    {
        responseAllocated_ = false;
        response_ = buffer_ + bodyStartPos;
    }
    response_[contentAvail_] = 0;

    log_info("specified content length is " << contentLength_);

    return HEADER_COMPLETE;
}

ProcessResponseEnum HttpClient::ProcessResponse(Value& result, bool notification)
{
    log_trace();
    int requestId = requestId_.front();
    requestId_.pop_front();
    responseProcessed_ = true;
    ProcessResponseEnum processResult = handler_->ProcessResponse(response_,contentLength_,result,requestId,notification);
    if (!httpResponseState_.GetKeepAlive())
    {
        log_info("Http response header indicates to close connection");
        Close();
    }
    return processResult;
}

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

bool TcpClient::GenerateHeader()
{
    log_trace();
    header_ << request_.Length() << ":";
    log_debug("Request length=" << request_.Length());

    // add the comma separator to the request buffer
    request_ << ',';

    return true;
}

int TcpClient::ProcessHeader(bool eof)
{
    // search for the length/body separator, ':'
    char* body = 0;
    char* header = buffer_;
    char* end = buffer_ + bufferLength_;
    for (char* current = buffer_; current < end; current++)
    {
        if (*current == ':')
        {
            body = current + 1;
            break;
        }
    }

    // If we haven't gotten the entire header yet, return (keep reading)
    if (body == 0)
    {
        // EOF in the middle of a request is an error, otherwise its ok
        if (eof)
        {
            log_warn("EOF while reading header");
            return HEADER_FAULT;
        }
        return HEADER_INCOMPLETE;  // Keep reading
    }

    // check for comma separator
    if (commaExpected_)
    {
        if (*header != ',')
        {
            log_warn("Expected comma to separate messages");
            log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_);
            return HEADER_FAULT;
        }
        header++;
    }

    contentLength_ = atoi(header);
    if (contentLength_ <= 0)
    {
        log_warn("Invalid string length specified " << contentLength_);
        log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_);
        return HEADER_FAULT;
    }

    int bufferSpaceAvail = buffer_ + MaxBufferLength - body;
    contentAvail_ = end - body;

    if (contentLength_ > MaxContentLength)
    {
        log_warn("String length too large=" << contentLength_ << ", max allowed=" << MaxContentLength);
        return HEADER_FAULT;
    }
    if (contentLength_ > bufferSpaceAvail)
    {
        // try to malloc the buffer space needed
        response_ = static_cast<char*>(malloc(contentLength_+1));
        if (response_ == 0)
        {
            log_warn("Could not allocate space=" << contentLength_);
            return HEADER_FAULT;
        }
        // copy the content that was already read to the new space
        memcpy(response_,body,contentAvail_);
        responseAllocated_ = true;
    }
    else
    {
        responseAllocated_ = false;
        response_ = body;
    }
    response_[contentAvail_] = 0;
    log_info("specified content length is " << contentLength_);

    // a comma is expected to separate the next message
    commaExpected_ = true;

    return HEADER_COMPLETE;
}

} // namespace anyrpc
<commit_msg>Fixed two crash bugs: If the response is NULL for some reasons anyrpc will crashs<commit_after>// Copyright (C) 2015 SRG Technology, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "anyrpc/api.h"
#include "anyrpc/logger.h"
#include "anyrpc/error.h"
#include "anyrpc/value.h"
#include "anyrpc/stream.h"
#include "anyrpc/handler.h"
#include "anyrpc/reader.h"
#include "anyrpc/document.h"
#include "anyrpc/method.h"
#include "anyrpc/socket.h"
#include "anyrpc/client.h"
#include "anyrpc/internal/time.h"

namespace anyrpc
{

#if defined(ANYRPC_THREADING)
std::atomic<unsigned> ClientHandler::nextId_(1);
#else
unsigned ClientHandler::nextId_ = 1;
#endif // defined(ANYRPC_THREADING)

int ClientHandler::GetNextId()
{
    return nextId_++;
}

void ClientHandler::GenerateFaultResult(int errorCode, std::string const& errorMsg, Value& result)
{
    result["code"] = errorCode;
    result["message"] = errorMsg;
}

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

Client::Client(ClientHandler* handler)
{
    handler_ = handler;
    port_ = 0;
    timeout_ = 60000;
    responseAllocated_ = false;
    responseProcessed_ = false;
    ResetReceiveBuffer();
    ResetTransaction();
}

Client::Client(ClientHandler* handler, const char* host, int port)
{
    handler_ = handler;
    host_ = host;
    port_ = port;
    timeout_ = 60000;
    responseAllocated_ = false;
    responseProcessed_ = false;
    ResetReceiveBuffer();
    ResetTransaction();
}

Client::~Client()
{
    if (responseAllocated_)
        free(response_);
    Close();
}

bool Client::Call(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        // continue with the processing
        if (ReadHeader(result) &&
            ReadResponse(result))
        {
            switch (ProcessResponse(result))
            {
                case ProcessResponseSuccess       : return true;
                case ProcessResponseErrorKeepOpen : return false;
            }
        }
    }
    Reset();
    return false;
}

bool Client::Post(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        return true;
    }
    Reset();
    return false;
}

bool Client::GetPostResult(Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    if (responseProcessed_)
    {
        PreserveReceiveBuffer();
        ResetTransaction();
    }

    if (socket_.IsConnected(0) &&
        ReadHeader(result) &&
        ReadResponse(result))
    {
        switch (ProcessResponse(result))
        {
            case ProcessResponseSuccess       : return true;
            case ProcessResponseErrorKeepOpen : return false;
        }
    }

    Reset();
    return false;
}

bool Client::Notify(const char* method, Value& params, Value& result)
{
    log_trace();
    gettimeofday( &startTime_, 0 );
    result.SetInvalid();

    PreserveReceiveBuffer();
    ResetTransaction();

    if (Connect(result) &&
        GenerateRequest(method, params, true) &&
        GenerateHeader())
    {
        if (!WriteRequest(result))
        {
            // retry the connection
            Close();
            if (!Connect(result) ||
                !WriteRequest(result))
            {
                Reset();
                return false;
            }
        }
        // Not all notification require a response
        if (!TransportHasNotifyResponse())
        {
            requestId_.pop_front();
            return true;
        }
        // continue with the processing response
        if (ReadHeader(result) &&
            ReadResponse(result))
        {
            // don't process the response for a notification
            requestId_.pop_front();
            result.SetNull();
            return true;
        }
    }
    Reset();
    return false;
}

void Client::Reset()
{
    Close();
    ResetReceiveBuffer();
    ResetTransaction();
    requestId_.clear();
}

void Client::ResetTransaction()
{
    contentLength_ = 0;
    if (responseAllocated_)
        free(response_);
    response_ = 0;
    responseAllocated_ = false;
    responseProcessed_ = false;
    contentAvail_ = 0;
    header_.Clear();
    request_.Clear();
}

void Client::PreserveReceiveBuffer()
{
    // only need to consider preserving data if we didn't need to allocate a new buffer
    // if a new buffer was allocated, then only the required data would be read
    if (!responseAllocated_)
    {
        if (response_ != 0)
        {
            // a response was processed so there might be data left in the buffer
            if (contentAvail_ > contentLength_)
            {
                // there is data left in the buffer move it to the start of the buffer
                char* responseEnd = response_ + contentLength_;
                size_t dataRemaining = contentAvail_ - contentLength_;
                log_debug("PreserveReceiveBuffer: Preserve data: " << dataRemaining << " bytes");
                memmove(buffer_, responseEnd, dataRemaining);
                bufferLength_ = dataRemaining;
            }
            else
            {
                log_debug("PreserveReceiveBuffer: No data to preserve");
                bufferLength_ = 0;
            }
        }
        else
            log_debug("PreserveReceiveBuffer: Keep any previous data: " << bufferLength_ << " bytes");
    }
    else
    {
        log_debug("PreserveReceiveBuffer: Reset buffer");
        bufferLength_ = 0;
    }
    responseProcessed_ = true;
}

unsigned Client::GetTimeLeft()
{
    struct timeval currentTime;
    gettimeofday( &currentTime, 0 );

    int timeUsed = MilliTimeDiff(currentTime,startTime_);

    int timeLeft = std::max(0,(int)timeout_ - timeUsed);

    log_debug("GetTimeLeft: timeout=" << timeout_ << ", timeLeft=" << timeLeft << ", timeUsed=" << timeUsed);
    return timeLeft;
}

bool Client::Connect(Value& result)
{
    log_trace();
    if (socket_.IsConnected(0))
    {
        log_debug("Already connected");
        return true;
    }
    // Close the connection but keep any data that has been setup for the next message
    Close();
    ResetReceiveBuffer();

    log_debug("Create a new connection");
    socket_.Create();
    socket_.SetNonBlocking();

    socket_.Connect(host_.c_str(), port_);

    socket_.SetKeepAlive();
    socket_.SetTcpNoDelay();

    if (!socket_.IsConnected(GetTimeLeft()))
    {
        socket_.Close();
        return false;
    }
    return true;
}

bool Client::GenerateRequest(const char* method, Value& params, bool notification)
{
    int requestId;

    bool result = handler_->GenerateRequest(method,params,request_,requestId,notification);
    requestId_.push_back(requestId);
    return result;
}

bool Client::WriteRequest(Value& result)
{
    log_trace();

    size_t bytesWritten;
    size_t bytesToSend;

    // write the header - it make be in several segments
    size_t headerBytesWritten = 0;
    while (headerBytesWritten < header_.Length())
    {
        const char* buffer = header_.GetBuffer(headerBytesWritten, bytesToSend);
        if (!socket_.Send(buffer, bytesToSend, bytesWritten, GetTimeLeft()))
            return false;

        headerBytesWritten += bytesWritten;

        if (bytesToSend < bytesWritten)
            return false;   // timeout
    }

    // write the request - it make be in several segments
    size_t requestBytesWritten = 0;
    while (requestBytesWritten < request_.Length())
    {
        const char* buffer = request_.GetBuffer(requestBytesWritten, bytesToSend);
        if (!socket_.Send(buffer, bytesToSend, bytesWritten, GetTimeLeft()))
            return false;

        requestBytesWritten += bytesWritten;

        if (bytesToSend < bytesWritten)
            return false;   // timeout
    }

    return true;
}

bool Client::ReadHeader(Value& result)
{
    log_trace();
    // Read available data
    socket_.SetTimeout(0);
    while (true)
    {
        int bytesRead;
        bool eof;
        socket_.Receive(buffer_+bufferLength_, MaxBufferLength-bufferLength_, bytesRead, eof, 0);
        if (socket_.FatalError())
        {
            log_warn("error while reading header: " << socket_.GetLastError() << ", bytesRead=" << bytesRead);
            return false;
        }
        bufferLength_ += bytesRead;
        log_info("read=" << bytesRead << ", total=" << bufferLength_);

        switch (ProcessHeader(eof))
        {
            case HEADER_COMPLETE : return true;
            case HEADER_FAULT : return false;
        }
        unsigned timeLeft = GetTimeLeft();
        if (timeLeft == 0)
        {
            handler_->GenerateFaultResult(AnyRpcErrorTransportError,"Timeout reading response header",result);
            break;
        }
        socket_.WaitReadable(timeLeft);
    }
    return false;
}

bool Client::ReadResponse(Value& result)
{
    log_trace();
    if (contentAvail_ >= contentLength_)
        return true;

    int bytesRead;
    bool eof;
    bool receiveResult = socket_.Receive(response_+contentAvail_, contentLength_-contentAvail_, bytesRead, eof, GetTimeLeft());
    contentAvail_ += bytesRead;
    if(response_)
    	response_[contentAvail_] = 0;
    if (!receiveResult)
        handler_->GenerateFaultResult(AnyRpcErrorTransportError,"Failed reading response",result);
    return receiveResult;
}

ProcessResponseEnum Client::ProcessResponse(Value& result, bool notification)
{
    int requestId = requestId_.front();
    if(!requestId_.empty())
    	requestId_.pop_front();
    responseProcessed_ = true;
    return handler_->ProcessResponse(response_,contentLength_,result,requestId,notification);
}

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

bool HttpClient::GenerateHeader()
{
    log_trace();
    header_ << "POST /RPC2 HTTP/1.1\r\n";
    header_ << "User-Agent: " << ANYRPC_APP_NAME << " v" << ANYRPC_VERSION_STRING << "\r\n";
    header_ << "Host: " << host_ << ":" << port_ << "\r\n";
    header_ << "Content-Type: " << contentType_ << "\r\n";
    header_ << "Accept: " << contentType_ << "\r\n";
    header_ << "Content-length: " << request_.Length() << "\r\n";
    header_ << "\r\n";

    return true;
}

int HttpClient::ProcessHeader(bool eof)
{
    log_trace();
    switch (httpResponseState_.ProcessHeaderData(buffer_, bufferLength_, eof))
    {
        case internal::HttpHeader::HEADER_FAULT         : return HEADER_FAULT;
        case internal::HttpHeader::HEADER_INCOMPLETE    : return HEADER_INCOMPLETE;
    }

    size_t bodyStartPos = httpResponseState_.GetBodyStartPos();
    size_t bufferSpaceAvail = MaxBufferLength - bodyStartPos;

    contentLength_ = httpResponseState_.GetContentLength();
    contentAvail_ = bufferLength_ - bodyStartPos;
    //keepAlive_ = httpResponseState_.GetKeepAlive();

    if (contentLength_ > MaxContentLength)
    {
        log_warn("Content-length too large=" << contentLength_ << ", max allowed=" << MaxContentLength);
        return HEADER_FAULT;
    }
    if (contentLength_ > (int)bufferSpaceAvail)
    {
        // try to malloc the buffer space needed
        response_ = static_cast<char*>(malloc(contentLength_+1));
        if (response_ == 0)
        {
            log_warn("Could not allocate space=" << contentLength_);
            return HEADER_FAULT;
        }
        // copy the content that was already read to the new space
        memcpy(response_,buffer_+bodyStartPos,contentAvail_);
        responseAllocated_ = true;
    }
    else
    {
        responseAllocated_ = false;
        response_ = buffer_ + bodyStartPos;
    }
    response_[contentAvail_] = 0;

    log_info("specified content length is " << contentLength_);

    return HEADER_COMPLETE;
}

ProcessResponseEnum HttpClient::ProcessResponse(Value& result, bool notification)
{
    log_trace();
    int requestId = requestId_.front();
    requestId_.pop_front();
    responseProcessed_ = true;
    ProcessResponseEnum processResult = handler_->ProcessResponse(response_,contentLength_,result,requestId,notification);
    if (!httpResponseState_.GetKeepAlive())
    {
        log_info("Http response header indicates to close connection");
        Close();
    }
    return processResult;
}

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

bool TcpClient::GenerateHeader()
{
    log_trace();
    header_ << request_.Length() << ":";
    log_debug("Request length=" << request_.Length());

    // add the comma separator to the request buffer
    request_ << ',';

    return true;
}

int TcpClient::ProcessHeader(bool eof)
{
    // search for the length/body separator, ':'
    char* body = 0;
    char* header = buffer_;
    char* end = buffer_ + bufferLength_;
    for (char* current = buffer_; current < end; current++)
    {
        if (*current == ':')
        {
            body = current + 1;
            break;
        }
    }

    // If we haven't gotten the entire header yet, return (keep reading)
    if (body == 0)
    {
        // EOF in the middle of a request is an error, otherwise its ok
        if (eof)
        {
            log_warn("EOF while reading header");
            return HEADER_FAULT;
        }
        return HEADER_INCOMPLETE;  // Keep reading
    }

    // check for comma separator
    if (commaExpected_)
    {
        if (*header != ',')
        {
            log_warn("Expected comma to separate messages");
            log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_);
            return HEADER_FAULT;
        }
        header++;
    }

    contentLength_ = atoi(header);
    if (contentLength_ <= 0)
    {
        log_warn("Invalid string length specified " << contentLength_);
        log_warn("bufferLength=" << bufferLength_ << ", buffer=" << buffer_);
        return HEADER_FAULT;
    }

    int bufferSpaceAvail = buffer_ + MaxBufferLength - body;
    contentAvail_ = end - body;

    if (contentLength_ > MaxContentLength)
    {
        log_warn("String length too large=" << contentLength_ << ", max allowed=" << MaxContentLength);
        return HEADER_FAULT;
    }
    if (contentLength_ > bufferSpaceAvail)
    {
        // try to malloc the buffer space needed
        response_ = static_cast<char*>(malloc(contentLength_+1));
        if (response_ == 0)
        {
            log_warn("Could not allocate space=" << contentLength_);
            return HEADER_FAULT;
        }
        // copy the content that was already read to the new space
        memcpy(response_,body,contentAvail_);
        responseAllocated_ = true;
    }
    else
    {
        responseAllocated_ = false;
        response_ = body;
    }
    response_[contentAvail_] = 0;
    log_info("specified content length is " << contentLength_);

    // a comma is expected to separate the next message
    commaExpected_ = true;

    return HEADER_COMPLETE;
}

} // namespace anyrpc
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct ZinitPass : public Pass {
	ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
	void help() override
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    zinit [options] [selection]\n");
		log("\n");
		log("Add inverters as needed to make all FFs zero-initialized.\n");
		log("\n");
		log("    -all\n");
		log("        also add zero initialization to uninitialized FFs\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
	{
		bool all_mode = false;

		log_header(design, "Executing ZINIT pass (make all FFs zero-initialized).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-all") {
				all_mode = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);
			FfInitVals initvals(&sigmap, module);

			pool<IdString> dff_types = {
								// FIXME: It would appear that supporting
								//    $dffsr/$_DFFSR_* would require a new
								//    cell type where S has priority over R
				ID($ff), ID($dff), ID($dffe), /*ID($dffsr),*/ ID($adff), ID($adffe),
				ID($sdff), ID($sdffe), ID($sdffce),
				ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_),
				/*ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_),
				ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_),*/
				ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
				ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_),
				// Async set/reset
				ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
				ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
				ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
				ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_),
				// Sync set/reset
				ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
				ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_),
				ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
				ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
				ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
				ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_),
				ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
				ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
				ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
				ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)
			};

			for (auto cell : module->selected_cells())
			{
				if (!dff_types.count(cell->type))
					continue;

				SigSpec sig_d = sigmap(cell->getPort(ID::D));
				SigSpec sig_q = sigmap(cell->getPort(ID::Q));

				if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1)
					continue;

				Const initval = initvals(sig_q);
				Const newval = initval;
				initvals.remove_init(sig_q);

				Wire *initwire = module->addWire(NEW_ID, GetSize(sig_q));

				for (int i = 0; i < GetSize(initwire); i++)
					if (initval[i] == State::S1)
					{
						sig_d[i] = module->NotGate(NEW_ID, sig_d[i]);
						module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]);
						newval[i] = State::S0;
					}
					else
					{
						module->connect(sig_q[i], SigSpec(initwire, i));
						if (all_mode)
							newval[i] = State::S0;
					}

				initvals.set_init(initwire, newval);

				log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
						log_signal(sig_q), log_signal(initval));

				cell->setPort(ID::D, sig_d);
				cell->setPort(ID::Q, initwire);

				if (cell->type.in(ID($adff), ID($adffe))) {
					auto val = cell->getParam(ID::ARST_VALUE);
					for (int i = 0; i < GetSize(initwire); i++)
						if (initval[i] == State::S1)
							val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
					cell->setParam(ID::ARST_VALUE, std::move(val));
				}
				else if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
					auto val = cell->getParam(ID::SRST_VALUE);
					for (int i = 0; i < GetSize(initwire); i++)
						if (initval[i] == State::S1)
							val[i] = (val[i] == State::S1 ? State::S0 : State::S1);
					cell->setParam(ID::SRST_VALUE, std::move(val));
				}
				else if (initval == State::S1) {
					std::string t = cell->type.str();
					if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_),
								ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_)))
					{
						t[8] = (t[8] == '0' ? '1' : '0');
					}
					else if (cell->type.in(ID($_SDFF_NN0_), ID($_SDFF_NN1_), ID($_SDFF_NP0_), ID($_SDFF_NP1_),
								ID($_SDFF_PN0_), ID($_SDFF_PN1_), ID($_SDFF_PP0_), ID($_SDFF_PP1_)))
					{
						t[9] = (t[9] == '0' ? '1' : '0');
					}
					else if (cell->type.in(ID($_DFFE_NN0P_), ID($_DFFE_NN1P_), ID($_DFFE_NP0P_), ID($_DFFE_NP1P_),
								ID($_DFFE_PN0P_), ID($_DFFE_PN1P_), ID($_DFFE_PP0P_), ID($_DFFE_PP1P_),
								ID($_DFFE_NN0N_), ID($_DFFE_NN1N_), ID($_DFFE_NP0N_), ID($_DFFE_NP1N_),
								ID($_DFFE_PN0N_), ID($_DFFE_PN1N_), ID($_DFFE_PP0N_), ID($_DFFE_PP1N_)))
					{
						t[9] = (t[9] == '0' ? '1' : '0');
					}
					else if (cell->type.in(ID($_SDFFE_NN0P_), ID($_SDFFE_NN1P_), ID($_SDFFE_NP0P_), ID($_SDFFE_NP1P_),
								ID($_SDFFE_PN0P_), ID($_SDFFE_PN1P_), ID($_SDFFE_PP0P_), ID($_SDFFE_PP1P_),
								ID($_SDFFE_NN0N_), ID($_SDFFE_NN1N_), ID($_SDFFE_NP0N_), ID($_SDFFE_NP1N_),
								ID($_SDFFE_PN0N_), ID($_SDFFE_PN1N_), ID($_SDFFE_PP0N_), ID($_SDFFE_PP1N_)))
					{
						t[10] = (t[10] == '0' ? '1' : '0');
					}
					else if (cell->type.in(ID($_SDFFCE_NN0P_), ID($_SDFFCE_NN1P_), ID($_SDFFCE_NP0P_), ID($_SDFFCE_NP1P_),
								ID($_SDFFCE_PN0P_), ID($_SDFFCE_PN1P_), ID($_SDFFCE_PP0P_), ID($_SDFFCE_PP1P_),
								ID($_SDFFCE_NN0N_), ID($_SDFFCE_NN1N_), ID($_SDFFCE_NP0N_), ID($_SDFFCE_NP1N_),
								ID($_SDFFCE_PN0N_), ID($_SDFFCE_PN1N_), ID($_SDFFCE_PP0N_), ID($_SDFFCE_PP1N_)))
					{
						t[11] = (t[11] == '0' ? '1' : '0');
					}
					cell->type = t;
				}
			}
		}
	}
} ZinitPass;

PRIVATE_NAMESPACE_END
<commit_msg>zinit: Refactor to use FfData.<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Claire Xenia Wolf <claire@yosyshq.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/ffinit.h"
#include "kernel/ff.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

State invert(State s) {
	switch (s) {
		case State::S0: return State::S1;
		case State::S1: return State::S0;
		default: return s;
	}
}

struct ZinitPass : public Pass {
	ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { }
	void help() override
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    zinit [options] [selection]\n");
		log("\n");
		log("Add inverters as needed to make all FFs zero-initialized.\n");
		log("\n");
		log("    -all\n");
		log("        also add zero initialization to uninitialized FFs\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) override
	{
		bool all_mode = false;

		log_header(design, "Executing ZINIT pass (make all FFs zero-initialized).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-all") {
				all_mode = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		for (auto module : design->selected_modules())
		{
			SigMap sigmap(module);
			FfInitVals initvals(&sigmap, module);

			for (auto cell : module->selected_cells())
			{
				if (!RTLIL::builtin_ff_cell_types().count(cell->type))
					continue;

				FfData ff(&initvals, cell);
				if (!ff.width)
					continue;

				// Supporting those would require a new cell type where S has priority over R.
				if (ff.has_sr)
					continue;

				Wire *new_q = module->addWire(NEW_ID, ff.width);

				log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type),
						log_signal(ff.sig_q), log_signal(ff.val_init));

				IdString name = cell->name;
				module->remove(cell);
				initvals.remove_init(ff.sig_q);

				for (int i = 0; i < ff.width; i++)
					if (ff.val_init[i] == State::S1)
					{
						if (ff.has_clk || ff.has_gclk)
							ff.sig_d[i] = module->NotGate(NEW_ID, ff.sig_d[i]);
						if (ff.has_aload)
							ff.sig_ad[i] = module->NotGate(NEW_ID, ff.sig_ad[i]);
						if (ff.has_arst)
							ff.val_arst[i] = invert(ff.val_arst[i]);
						if (ff.has_srst)
							ff.val_srst[i] = invert(ff.val_srst[i]);
						module->addNotGate(NEW_ID, SigSpec(new_q, i), ff.sig_q[i]);
						ff.val_init[i] = State::S0;
					}
					else
					{
						module->connect(ff.sig_q[i], SigSpec(new_q, i));
						if (all_mode)
							ff.val_init[i] = State::S0;
					}

				ff.sig_q = new_q;
				ff.emit(module, name);
			}
		}
	}
} ZinitPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong.html
 *
 */

#include "client.h"

client::client(thread_cfg *_cfg, string_server *_str_server):
    cfg(_cfg), str_server(_str_server), parser(_str_server) { }

void
client::send(request_or_reply &req)
{
    assert(req.pid != -1);

    if (req.start_from_index()) {
        int nthread = max(1, min(global_mt_threshold, global_nbewkrs));
        for (int i = 0; i < global_nsrvs; i++) {
            for (int j = 0; j < nthread; j++) {
                req.mt_total_thread = nthread;
                req.mt_current_thread = j;
                SendR(cfg, i, global_nfewkrs + j, req);
            }
        }
        return ;
    }
    req.first_target = mymath::hash_mod(req.cmd_chains[0], global_nsrvs);

    // one-to-one mapping
    //int server_per_client = global_nbewkrs / global_nfewkrs;
    //int mid = global_nfewkrs + server_per_client * cfg->wid + cfg->get_random() % server_per_client;

    // random
    int tid = global_nfewkrs + cfg->get_random() % global_nbewkrs;
    SendR(cfg, req.first_target, tid, req);
}

request_or_reply
client::recv(void)
{
    request_or_reply r = RecvR(cfg);
    if (r.start_from_index()) {
        int nthread = max(1, min(global_mt_threshold, global_nbewkrs));
        for (int count = 0; count < global_nsrvs * nthread - 1 ; count++) {
            request_or_reply r2 = RecvR(cfg);
            r.row_num += r2.row_num;
            int new_size = r.result_table.size() + r2.result_table.size();
            r.result_table.reserve(new_size);
            r.result_table.insert(r.result_table.end(), r2.result_table.begin(), r2.result_table.end());
        }
    }

    return r;
}

void
client::print_result(request_or_reply &r, int row2print)
{
    cout << "The first " << row2print << " rows of results: " << endl;
    for (int i = 0; i < row2print; i++) {
        cout << i + 1 << ":  ";
        for (int c = 0; c < r.get_col_num(); c++) {
            int id = r.get_row_col(i, c);
            if (str_server->id2str.find(id) == str_server->id2str.end()) {
                cout << "NULL  ";
            } else {
                cout << str_server->id2str[r.get_row_col(i, c)] << "  ";
            }
        }
        cout << endl;
    }
}
<commit_msg>refine print<commit_after>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong.html
 *
 */

#include "client.h"

client::client(thread_cfg *_cfg, string_server *_str_server):
    cfg(_cfg), str_server(_str_server), parser(_str_server) { }

void
client::send(request_or_reply &req)
{
    assert(req.pid != -1);

    if (req.start_from_index()) {
        int nthread = max(1, min(global_mt_threshold, global_nbewkrs));
        for (int i = 0; i < global_nsrvs; i++) {
            for (int j = 0; j < nthread; j++) {
                req.mt_total_thread = nthread;
                req.mt_current_thread = j;
                SendR(cfg, i, global_nfewkrs + j, req);
            }
        }
        return ;
    }
    req.first_target = mymath::hash_mod(req.cmd_chains[0], global_nsrvs);

    // one-to-one mapping
    //int server_per_client = global_nbewkrs / global_nfewkrs;
    //int mid = global_nfewkrs + server_per_client * cfg->wid + cfg->get_random() % server_per_client;

    // random
    int tid = global_nfewkrs + cfg->get_random() % global_nbewkrs;
    SendR(cfg, req.first_target, tid, req);
}

request_or_reply
client::recv(void)
{
    request_or_reply r = RecvR(cfg);
    if (r.start_from_index()) {
        int nthread = max(1, min(global_mt_threshold, global_nbewkrs));
        for (int count = 0; count < global_nsrvs * nthread - 1 ; count++) {
            request_or_reply r2 = RecvR(cfg);
            r.row_num += r2.row_num;
            int new_size = r.result_table.size() + r2.result_table.size();
            r.result_table.reserve(new_size);
            r.result_table.insert(r.result_table.end(), r2.result_table.begin(), r2.result_table.end());
        }
    }

    return r;
}

void
client::print_result(request_or_reply &r, int row2print)
{
    cout << "The first " << row2print << " rows of results: " << endl;
    for (int i = 0; i < row2print; i++) {
        cout << i + 1 << ":  ";
        for (int c = 0; c < r.get_col_num(); c++) {
            int id = r.get_row_col(i, c);
            if (str_server->id2str.find(id) == str_server->id2str.end())
                cout << id << "\t";
            else
                cout << str_server->id2str[r.get_row_col(i, c)] << "  ";
        }
        cout << endl;
    }
}
<|endoftext|>


<commit_before>#include "../glm/glm.hpp"

#include "box.h"
#include "../physic/pbox.h"

using namespace glm;

Box::Box(float w, float h, float d)
{
    std::vector<glm::vec3> vertices;
    std::vector<glm::uvec3> indices;

    vertices.push_back(vec3( w / 2, -h / 2, -d / 2));
    vertices.push_back(vec3( w / 2, -h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2, -h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2, -h / 2, -d / 2));
    vertices.push_back(vec3( w / 2,  h / 2, -d / 2));
    vertices.push_back(vec3( w / 2,  h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2,  h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2,  h / 2, -d / 2));

    indices.push_back(uvec3(0, 1, 2));
    indices.push_back(uvec3(0, 2, 3));
    indices.push_back(uvec3(4, 7, 6));
    indices.push_back(uvec3(4, 6, 5));
    indices.push_back(uvec3(0, 4, 5));
    indices.push_back(uvec3(0, 5, 1));
    indices.push_back(uvec3(1, 5, 6));
    indices.push_back(uvec3(1, 6, 2));
    indices.push_back(uvec3(2, 6, 7));
    indices.push_back(uvec3(2, 7, 3));
    indices.push_back(uvec3(4, 0, 3));
    indices.push_back(uvec3(4, 3, 7));

    //m_gObj.load(vertices, indices);
    m_pObj = new PBox(w, h, d);
}

Box::~Box()
{
    delete m_pObj;
}

Object::ObjectType Box::getType()
{
    return Object::Box;
}
<commit_msg>solution temporaire load pour box<commit_after>#include "../glm/glm.hpp"

#include "box.h"
#include "../physic/pbox.h"

using namespace glm;

Box::Box(float w, float h, float d)
{
    std::vector<glm::vec3> vertices;
    std::vector<glm::uvec3> indices;

    vertices.push_back(vec3( w / 2, -h / 2, -d / 2));
    vertices.push_back(vec3( w / 2, -h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2, -h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2, -h / 2, -d / 2));
    vertices.push_back(vec3( w / 2,  h / 2, -d / 2));
    vertices.push_back(vec3( w / 2,  h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2,  h / 2,  d / 2));
    vertices.push_back(vec3(-w / 2,  h / 2, -d / 2));

    indices.push_back(uvec3(0, 1, 2));
    indices.push_back(uvec3(0, 2, 3));
    indices.push_back(uvec3(4, 7, 6));
    indices.push_back(uvec3(4, 6, 5));
    indices.push_back(uvec3(0, 4, 5));
    indices.push_back(uvec3(0, 5, 1));
    indices.push_back(uvec3(1, 5, 6));
    indices.push_back(uvec3(1, 6, 2));
    indices.push_back(uvec3(2, 6, 7));
    indices.push_back(uvec3(2, 7, 3));
    indices.push_back(uvec3(4, 0, 3));
    indices.push_back(uvec3(4, 3, 7));

    //Pas propre, mais ça fonctionne en attendant.
    m_gObj.load(vertices, *((std::vector<unsigned int>*) &indices));
    m_pObj = new PBox(w, h, d);
}

Box::~Box()
{
    delete m_pObj;
}

Object::ObjectType Box::getType()
{
    return Object::Box;
}
<|endoftext|>


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

#include "CppUTest/TestHarness.h"
#include "CppUTest/SimpleString.h"
#include "CppUTest/PlatformSpecificFunctions.h"

#include "CppUTest/MemoryLeakDetector.h" // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!

TEST_GROUP(SimpleString)
{
	void setup()
	{
		MemoryLeakWarningPlugin::getGlobalDetector()->disableAllocationTypeChecking (); // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!
	}

	void teardown()
	{
		MemoryLeakWarningPlugin::getGlobalDetector()->enableAllocationTypeChecking (); // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!
	}
};

TEST(SimpleString, CreateSequence)
{
  SimpleString expected("hellohello");
  SimpleString actual("hello", 2);

  CHECK_EQUAL(expected, actual);
}

TEST(SimpleString, CreateSequenceOfZero)
{
  SimpleString expected("");
  SimpleString actual("hello", 0);

  CHECK_EQUAL(expected, actual);
}

TEST(SimpleString, Copy)
{
  SimpleString s1("hello");
  SimpleString s2(s1);

  CHECK_EQUAL(s1, s2);
}

TEST(SimpleString, Assignment)
{
  SimpleString s1("hello");
  SimpleString s2("goodbye");

  s2 = s1;

  CHECK_EQUAL(s1, s2);
}

TEST(SimpleString, Equality)
{
  SimpleString s1("hello");
  SimpleString s2("hello");

  CHECK(s1 == s2);
}

TEST(SimpleString, InEquality)
{
  SimpleString s1("hello");
  SimpleString s2("goodbye");

  CHECK(s1 != s2);
}

TEST(SimpleString, asCharString)
{
  SimpleString s1("hello");

  STRCMP_EQUAL("hello", s1.asCharString());
}

TEST(SimpleString, Size)
{
  SimpleString s1("hello!");

  LONGS_EQUAL(6, s1.size());
}

TEST(SimpleString, Addition)
{
  SimpleString s1("hello!");
  SimpleString s2("goodbye!");
  SimpleString s3("hello!goodbye!");
  SimpleString s4;
  s4 = s1 + s2;

  CHECK_EQUAL(s3, s4);
}

TEST(SimpleString, Concatenation)
{
  SimpleString s1("hello!");
  SimpleString s2("goodbye!");
  SimpleString s3("hello!goodbye!");
  SimpleString s4;
  s4 += s1;
  s4 += s2;

  CHECK_EQUAL(s3, s4);

  SimpleString s5("hello!goodbye!hello!goodbye!");
  s4 += s4;

  CHECK_EQUAL(s5, s4);
}

TEST(SimpleString, Contains)
{
  SimpleString s("hello!");
  SimpleString empty("");
  SimpleString beginning("hello");
  SimpleString end("lo!");
  SimpleString mid("l");
  SimpleString notPartOfString("xxxx");

  CHECK(s.contains(empty));
  CHECK(s.contains(beginning));
  CHECK(s.contains(end));
  CHECK(s.contains(mid));
  CHECK(!s.contains(notPartOfString));

  CHECK(empty.contains(empty));
  CHECK(!empty.contains(s));
}

TEST(SimpleString, startsWith)
{
	SimpleString hi("Hi you!");
	SimpleString part("Hi");
	SimpleString diff("Hrrm Hi you! ffdsfd");
	CHECK(hi.startsWith(part));
	CHECK(!part.startsWith(hi));
	CHECK(!diff.startsWith(hi));
}

TEST(SimpleString, split)
{
	SimpleString hi("hello\nworld\nhow\ndo\nyou\ndo\n\n");

	SimpleStringCollection collection;
	hi.split("\n", collection);

	LONGS_EQUAL(7, collection.size());
	STRCMP_EQUAL("hello\n", collection[0].asCharString());
	STRCMP_EQUAL("world\n", collection[1].asCharString());
	STRCMP_EQUAL("how\n", collection[2].asCharString());
	STRCMP_EQUAL("do\n", collection[3].asCharString());
	STRCMP_EQUAL("you\n", collection[4].asCharString());
	STRCMP_EQUAL("do\n", collection[5].asCharString());
	STRCMP_EQUAL("\n", collection[6].asCharString());
}

TEST(SimpleString, splitNoTokenOnTheEnd)
{
	SimpleString string("Bah Yah oops");
    SimpleStringCollection collection;

	string.split(" ", collection);
	LONGS_EQUAL(3, collection.size());
	STRCMP_EQUAL("Bah ", collection[0].asCharString());
	STRCMP_EQUAL("Yah ", collection[1].asCharString());
	STRCMP_EQUAL("oops", collection[2].asCharString());
}

TEST(SimpleString, count)
{
	SimpleString str("ha ha ha ha");
	LONGS_EQUAL(4, str.count("ha"));
}

TEST(SimpleString, countTogether)
{
	SimpleString str("hahahaha");
	LONGS_EQUAL(4, str.count("ha"));
}

TEST(SimpleString, endsWith)
{
	SimpleString str("Hello World");
	CHECK(str.endsWith("World"));
	CHECK(!str.endsWith("Worl"));
	CHECK(!str.endsWith("Hello"));
	SimpleString str2("ah");
	CHECK(str2.endsWith("ah"));
	CHECK(!str2.endsWith("baah"));
	SimpleString str3("");
	CHECK(!str3.endsWith("baah"));

	SimpleString str4("ha ha ha ha");
	CHECK(str4.endsWith("ha"));
}

TEST(SimpleString, replaceCharWithChar)
{
	SimpleString str("abcabcabca");
	str.replace('a','b');
	STRCMP_EQUAL("bbcbbcbbcb", str.asCharString());
}

TEST(SimpleString, replaceStringWithString)
{
	SimpleString str("boo baa boo baa boo");
	str.replace("boo","boohoo");
	STRCMP_EQUAL("boohoo baa boohoo baa boohoo", str.asCharString());
}

TEST(SimpleString, ContainsNull)
{
	SimpleString s(0);
	CHECK(!s.contains("something"));
}

TEST(SimpleString, Characters)
{
  SimpleString s(StringFrom('a'));
  SimpleString s2(StringFrom('a'));
  CHECK(s == s2);
}

TEST(SimpleString, Doubles)
{
	SimpleString s(StringFrom(1.2));
	STRCMP_EQUAL("1.200000", s.asCharString());
	s = StringFrom(1.2,2);
	STRCMP_EQUAL("1.20", s.asCharString());
}

TEST(SimpleString, HexStrings)
{
  SimpleString h1 = HexStringFrom(0xffff);
  STRCMP_EQUAL("fffe", h1.asCharString());
}

TEST(SimpleString, StringFromFormat)
{
  SimpleString h1 = StringFromFormat("%s %s! %d", "Hello", "World", 2009);
  STRCMP_EQUAL("Hello World! 2009", h1.asCharString());
}

TEST(SimpleString, StringFromFormatLarge)
{
   const char* s = "ThisIsAPrettyLargeStringAndIfWeAddThisManyTimesToABufferItWillbeFull";
   SimpleString h1 = StringFromFormat("%s%s%s%s%s%s%s%s%s%s", s, s, s, s, s, s, s, s, s, s);
   LONGS_EQUAL(10, h1.count(s));
}

static int WrappedUpVSNPrintf(char* buf, int n, const char* format, ...)
{
   va_list arguments;
   va_start(arguments, format);

   int result = PlatformSpecificVSNprintf(buf, n, format, arguments);
   va_end(arguments);
   return result;
}

TEST(SimpleString, PlatformSpecificSprintf_fits)
{
    char buf[10];

    int count = WrappedUpVSNPrintf(buf, sizeof(buf), "%s", "12345");
    STRCMP_EQUAL("12345", buf);
    LONGS_EQUAL(5, count);
}

TEST(SimpleString, PlatformSpecificSprintf_doesNotFit)
{
    char buf[10];

    int count = WrappedUpVSNPrintf(buf, sizeof(buf), "%s", "12345678901");
    STRCMP_EQUAL("123456789", buf);
    LONGS_EQUAL(11, count);
}

TEST(SimpleString, NullParameters2)
{
	SimpleString* arr = new SimpleString[100];
	delete [] arr;
}

TEST(SimpleString, CollectionMultipleAllocateNoLeaksMemory)
{
   SimpleStringCollection col;
   col.allocate(5);
   col.allocate(5);
   // CHECK no memory leak
}

TEST(SimpleString, CollectionReadOutOfBoundsReturnsEmptyString)
{
   SimpleStringCollection col;
   col.allocate(3);
   STRCMP_EQUAL("", col[3].asCharString());
}

TEST(SimpleString, CollectionWritingToEmptyString)
{
   SimpleStringCollection col;
   col.allocate(3);
   col[3] = SimpleString("HAH");
   STRCMP_EQUAL("", col[3].asCharString());
}
<commit_msg>fixed intentional error to test hudson CI<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "CppUTest/TestHarness.h"
#include "CppUTest/SimpleString.h"
#include "CppUTest/PlatformSpecificFunctions.h"

#include "CppUTest/MemoryLeakDetector.h" // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!

TEST_GROUP(SimpleString)
{
	void setup()
	{
		MemoryLeakWarningPlugin::getGlobalDetector()->disableAllocationTypeChecking (); // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!
	}

	void teardown()
	{
		MemoryLeakWarningPlugin::getGlobalDetector()->enableAllocationTypeChecking (); // REMOVE THIS AFTER THE VC++ EXPRESS IS FIXED!
	}
};

TEST(SimpleString, CreateSequence)
{
  SimpleString expected("hellohello");
  SimpleString actual("hello", 2);

  CHECK_EQUAL(expected, actual);
}

TEST(SimpleString, CreateSequenceOfZero)
{
  SimpleString expected("");
  SimpleString actual("hello", 0);

  CHECK_EQUAL(expected, actual);
}

TEST(SimpleString, Copy)
{
  SimpleString s1("hello");
  SimpleString s2(s1);

  CHECK_EQUAL(s1, s2);
}

TEST(SimpleString, Assignment)
{
  SimpleString s1("hello");
  SimpleString s2("goodbye");

  s2 = s1;

  CHECK_EQUAL(s1, s2);
}

TEST(SimpleString, Equality)
{
  SimpleString s1("hello");
  SimpleString s2("hello");

  CHECK(s1 == s2);
}

TEST(SimpleString, InEquality)
{
  SimpleString s1("hello");
  SimpleString s2("goodbye");

  CHECK(s1 != s2);
}

TEST(SimpleString, asCharString)
{
  SimpleString s1("hello");

  STRCMP_EQUAL("hello", s1.asCharString());
}

TEST(SimpleString, Size)
{
  SimpleString s1("hello!");

  LONGS_EQUAL(6, s1.size());
}

TEST(SimpleString, Addition)
{
  SimpleString s1("hello!");
  SimpleString s2("goodbye!");
  SimpleString s3("hello!goodbye!");
  SimpleString s4;
  s4 = s1 + s2;

  CHECK_EQUAL(s3, s4);
}

TEST(SimpleString, Concatenation)
{
  SimpleString s1("hello!");
  SimpleString s2("goodbye!");
  SimpleString s3("hello!goodbye!");
  SimpleString s4;
  s4 += s1;
  s4 += s2;

  CHECK_EQUAL(s3, s4);

  SimpleString s5("hello!goodbye!hello!goodbye!");
  s4 += s4;

  CHECK_EQUAL(s5, s4);
}

TEST(SimpleString, Contains)
{
  SimpleString s("hello!");
  SimpleString empty("");
  SimpleString beginning("hello");
  SimpleString end("lo!");
  SimpleString mid("l");
  SimpleString notPartOfString("xxxx");

  CHECK(s.contains(empty));
  CHECK(s.contains(beginning));
  CHECK(s.contains(end));
  CHECK(s.contains(mid));
  CHECK(!s.contains(notPartOfString));

  CHECK(empty.contains(empty));
  CHECK(!empty.contains(s));
}

TEST(SimpleString, startsWith)
{
	SimpleString hi("Hi you!");
	SimpleString part("Hi");
	SimpleString diff("Hrrm Hi you! ffdsfd");
	CHECK(hi.startsWith(part));
	CHECK(!part.startsWith(hi));
	CHECK(!diff.startsWith(hi));
}

TEST(SimpleString, split)
{
	SimpleString hi("hello\nworld\nhow\ndo\nyou\ndo\n\n");

	SimpleStringCollection collection;
	hi.split("\n", collection);

	LONGS_EQUAL(7, collection.size());
	STRCMP_EQUAL("hello\n", collection[0].asCharString());
	STRCMP_EQUAL("world\n", collection[1].asCharString());
	STRCMP_EQUAL("how\n", collection[2].asCharString());
	STRCMP_EQUAL("do\n", collection[3].asCharString());
	STRCMP_EQUAL("you\n", collection[4].asCharString());
	STRCMP_EQUAL("do\n", collection[5].asCharString());
	STRCMP_EQUAL("\n", collection[6].asCharString());
}

TEST(SimpleString, splitNoTokenOnTheEnd)
{
	SimpleString string("Bah Yah oops");
    SimpleStringCollection collection;

	string.split(" ", collection);
	LONGS_EQUAL(3, collection.size());
	STRCMP_EQUAL("Bah ", collection[0].asCharString());
	STRCMP_EQUAL("Yah ", collection[1].asCharString());
	STRCMP_EQUAL("oops", collection[2].asCharString());
}

TEST(SimpleString, count)
{
	SimpleString str("ha ha ha ha");
	LONGS_EQUAL(4, str.count("ha"));
}

TEST(SimpleString, countTogether)
{
	SimpleString str("hahahaha");
	LONGS_EQUAL(4, str.count("ha"));
}

TEST(SimpleString, endsWith)
{
	SimpleString str("Hello World");
	CHECK(str.endsWith("World"));
	CHECK(!str.endsWith("Worl"));
	CHECK(!str.endsWith("Hello"));
	SimpleString str2("ah");
	CHECK(str2.endsWith("ah"));
	CHECK(!str2.endsWith("baah"));
	SimpleString str3("");
	CHECK(!str3.endsWith("baah"));

	SimpleString str4("ha ha ha ha");
	CHECK(str4.endsWith("ha"));
}

TEST(SimpleString, replaceCharWithChar)
{
	SimpleString str("abcabcabca");
	str.replace('a','b');
	STRCMP_EQUAL("bbcbbcbbcb", str.asCharString());
}

TEST(SimpleString, replaceStringWithString)
{
	SimpleString str("boo baa boo baa boo");
	str.replace("boo","boohoo");
	STRCMP_EQUAL("boohoo baa boohoo baa boohoo", str.asCharString());
}

TEST(SimpleString, ContainsNull)
{
	SimpleString s(0);
	CHECK(!s.contains("something"));
}

TEST(SimpleString, Characters)
{
  SimpleString s(StringFrom('a'));
  SimpleString s2(StringFrom('a'));
  CHECK(s == s2);
}

TEST(SimpleString, Doubles)
{
	SimpleString s(StringFrom(1.2));
	STRCMP_EQUAL("1.200000", s.asCharString());
	s = StringFrom(1.2,2);
	STRCMP_EQUAL("1.20", s.asCharString());
}

TEST(SimpleString, HexStrings)
{
  SimpleString h1 = HexStringFrom(0xffff);
  STRCMP_EQUAL("ffff", h1.asCharString());
}

TEST(SimpleString, StringFromFormat)
{
  SimpleString h1 = StringFromFormat("%s %s! %d", "Hello", "World", 2009);
  STRCMP_EQUAL("Hello World! 2009", h1.asCharString());
}

TEST(SimpleString, StringFromFormatLarge)
{
   const char* s = "ThisIsAPrettyLargeStringAndIfWeAddThisManyTimesToABufferItWillbeFull";
   SimpleString h1 = StringFromFormat("%s%s%s%s%s%s%s%s%s%s", s, s, s, s, s, s, s, s, s, s);
   LONGS_EQUAL(10, h1.count(s));
}

static int WrappedUpVSNPrintf(char* buf, int n, const char* format, ...)
{
   va_list arguments;
   va_start(arguments, format);

   int result = PlatformSpecificVSNprintf(buf, n, format, arguments);
   va_end(arguments);
   return result;
}

TEST(SimpleString, PlatformSpecificSprintf_fits)
{
    char buf[10];

    int count = WrappedUpVSNPrintf(buf, sizeof(buf), "%s", "12345");
    STRCMP_EQUAL("12345", buf);
    LONGS_EQUAL(5, count);
}

TEST(SimpleString, PlatformSpecificSprintf_doesNotFit)
{
    char buf[10];

    int count = WrappedUpVSNPrintf(buf, sizeof(buf), "%s", "12345678901");
    STRCMP_EQUAL("123456789", buf);
    LONGS_EQUAL(11, count);
}

TEST(SimpleString, NullParameters2)
{
	SimpleString* arr = new SimpleString[100];
	delete [] arr;
}

TEST(SimpleString, CollectionMultipleAllocateNoLeaksMemory)
{
   SimpleStringCollection col;
   col.allocate(5);
   col.allocate(5);
   // CHECK no memory leak
}

TEST(SimpleString, CollectionReadOutOfBoundsReturnsEmptyString)
{
   SimpleStringCollection col;
   col.allocate(3);
   STRCMP_EQUAL("", col[3].asCharString());
}

TEST(SimpleString, CollectionWritingToEmptyString)
{
   SimpleStringCollection col;
   col.allocate(3);
   col[3] = SimpleString("HAH");
   STRCMP_EQUAL("", col[3].asCharString());
}
<|endoftext|>


<commit_before>#include <TestHarness.hpp>
#include <string>
#include <math.h>

TEST(macro_ASSERT_TRUE, simple_expressions_pass)
{
  ASSERT_TRUE(true);
  ASSERT_TRUE(!false);
  ASSERT_TRUE(1 == 2);
  ASSERT_TRUE(2 != 5);
  ASSERT_TRUE(1 < 10);
  ASSERT_TRUE(100 > 2.34);
  ASSERT_TRUE(10 > 2);
  ASSERT_TRUE(1.123 < 3.14);
  ASSERT_TRUE("foo" == "foo");
  ASSERT_TRUE("ciphertext" != "plaintext");
}

TEST(macro_ASSERT_FALSE, simple_expressions_pass)
{
  ASSERT_FALSE(false);
  ASSERT_FALSE(!true);
  ASSERT_FALSE(1 != 2);
  ASSERT_FALSE(2 == 5);
  ASSERT_FALSE(1 > 10);
  ASSERT_FALSE(100 < 2.34);
  ASSERT_FALSE(10 < 2);
  ASSERT_FALSE(1.123 > 3.14);
  ASSERT_FALSE("foo" != "foo");
  ASSERT_FALSE("ciphertext" == "plaintext");
}

TEST(macro_ASSERT_EQ, strings_test_out_equal)
{
  ASSERT_EQ("", "");
  ASSERT_EQ("a", "a");
  ASSERT_EQ("murrekatt", "murrekatt");
  ASSERT_EQ("this is a longer string with some special chars!@#", "this is a longer string with some special chars!@#");
}

TEST(macro_ASSERT_EQ, string_objects_test_out_equal)
{
  std::string s1;
  std::string s2;
  ASSERT_EQ(s1, s1);
}

TEST(macro_ASSERT_NEQ, string_objects_test_out_not_equal)
{
  std::string s1("foo");
  std::string s2("bar");
  ASSERT_NEQ(s1, s2);
}

TEST(macro_ASSERT_STREQ, conversion_to_string_objects_tests_out_equal)
{
  ASSERT_STREQ("murrekatt", "murrekatt");
}

TEST(macro_ASSERT_NEAR, floats_test_out_to_equal_within_given_epsilon)
{
  ASSERT_NEAR(3.1415, M_PI, 0.0001);
}

namespace
{

struct Example
{
  int value() { return 42; }
};

struct ExampleFixture
{
  Example e_;
};

} // namespace

TEST_F(ExampleFixture, when_doing_this_that_will_happen_as_a_result)
{
  // Arrange
  // Act
  // Assert
  ASSERT_EQ(42, e_.value());
}

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

TEST(Example, simple_test_of_something_that_should_result_in_something)
{
  // Arrange
  Example e;
  // Act
  int value = e.value();
  // Assert
  ASSERT_EQ(42, value);
}
<commit_msg>Minor adjustment in test descriptions.<commit_after>#include <TestHarness.hpp>
#include <string>
#include <math.h>

TEST(macro_ASSERT_TRUE, simple_expressions_equal_true)
{
  ASSERT_TRUE(true);
  ASSERT_TRUE(!false);
  ASSERT_TRUE(1 == 2);
  ASSERT_TRUE(2 != 5);
  ASSERT_TRUE(1 < 10);
  ASSERT_TRUE(100 > 2.34);
  ASSERT_TRUE(10 > 2);
  ASSERT_TRUE(1.123 < 3.14);
  ASSERT_TRUE("foo" == "foo");
  ASSERT_TRUE("ciphertext" != "plaintext");
}

TEST(macro_ASSERT_FALSE, simple_expressions_equal_false)
{
  ASSERT_FALSE(false);
  ASSERT_FALSE(!true);
  ASSERT_FALSE(1 != 2);
  ASSERT_FALSE(2 == 5);
  ASSERT_FALSE(1 > 10);
  ASSERT_FALSE(100 < 2.34);
  ASSERT_FALSE(10 < 2);
  ASSERT_FALSE(1.123 > 3.14);
  ASSERT_FALSE("foo" != "foo");
  ASSERT_FALSE("ciphertext" == "plaintext");
}

TEST(macro_ASSERT_EQ, strings_test_out_equal)
{
  ASSERT_EQ("", "");
  ASSERT_EQ("a", "a");
  ASSERT_EQ("murrekatt", "murrekatt");
  ASSERT_EQ("this is a longer string with some special chars!@#", "this is a longer string with some special chars!@#");
}

TEST(macro_ASSERT_EQ, string_objects_test_out_equal)
{
  std::string s1;
  std::string s2;
  ASSERT_EQ(s1, s1);
}

TEST(macro_ASSERT_NEQ, string_objects_test_out_not_equal)
{
  std::string s1("foo");
  std::string s2("bar");
  ASSERT_NEQ(s1, s2);
}

TEST(macro_ASSERT_STREQ, conversion_to_string_objects_tests_out_equal)
{
  ASSERT_STREQ("murrekatt", "murrekatt");
}

TEST(macro_ASSERT_NEAR, floats_test_out_to_equal_within_given_epsilon)
{
  ASSERT_NEAR(3.1415, M_PI, 0.0001);
}

namespace
{

struct Example
{
  int value() { return 42; }
};

struct ExampleFixture
{
  Example e_;
};

} // namespace

TEST_F(ExampleFixture, when_doing_this_that_will_happen_as_a_result)
{
  // Arrange
  // Act
  // Assert
  ASSERT_EQ(42, e_.value());
}

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

TEST(Example, simple_test_of_something_that_should_result_in_something)
{
  // Arrange
  Example e;
  // Act
  int value = e.value();
  // Assert
  ASSERT_EQ(42, value);
}
<|endoftext|>


<commit_before>/* RMSDCalculator.C
*
* Copyright (C) 2011 Marcel Schumann
*
* This program 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 3 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, see <http://www.gnu.org/licenses/>.
*/

// ----------------------------------------------------
// $Maintainer: Marcel Schumann $
// $Authors: Marcel Schumann $
// ----------------------------------------------------

#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/molFileFactory.h>
#include <BALL/FORMAT/commandlineParser.h>
#include <BALL/DATATYPE/options.h>
#include <BALL/KERNEL/PTE.h>
#include <BALL/DOCKING/COMMON/flexibleMolecule.h>
#include "version.h"

using namespace BALL;
using namespace std;

int main(int argc, char* argv[])
{
	CommandlineParser parpars("RMSDCalculator", "calculate RMSD between poses", VERSION, String(__DATE__), "Analysis");
	parpars.registerParameter("i", "input molecule file", INFILE, true);
	parpars.registerParameter("org", "molecule file containing the original ('true') poses", INFILE, true);
	parpars.registerParameter("o", "output molecule file", OUTFILE);
	parpars.registerFlag("quiet", "by quiet, i.e. do not print progress information");
	String man = "This tool calculates the RMSD between different conformations of the same molecule.\n\nTherefore this tool can for example be used to evaluate the different between ligands taken from co-crystal structures and their poses generated by a docking.\nMolecules may be sorted differently in the two input files; a topology hashkey will be used to match molecules to each other.\n\nOutput of this tool is a molecule file which will for each molecule contain a property-tag 'RMSD' holding the calculated RMSD value.";
	parpars.setToolManual(man);
	parpars.setSupportedFormats("i",MolFileFactory::getSupportedFormats());
	parpars.setSupportedFormats("org",MolFileFactory::getSupportedFormats());
	parpars.setSupportedFormats("o","mol2,sdf,drf");
	parpars.setOutputFormatSource("o","i");
	parpars.parse(argc, argv);

	// Retrieve coordinates of original poses
	GenericMolFile* original = MolFileFactory::open(parpars.get("org"));
	HashMap<String, list<Vector3> > original_poses;
	for (Molecule* mol = original->read(); mol; delete mol, mol = original->read())
	{
		String topology_hash;
		FlexibleMolecule::generateTopologyHash(mol, topology_hash, true);
		if (original_poses.find(topology_hash) != original_poses.end())
		{
			Log<<"[Warning:] more than one 'original' conformation for a molecule detected. Will use only the first conformation and ignore all other."<<endl;
		}
		else
		{
			list<Vector3> l;
			HashMap<String, list<Vector3> >::iterator map_it = original_poses.insert(make_pair(topology_hash, l)).first;

			for (AtomConstIterator it = mol->beginAtom(); +it; it++)
			{
				if (it->getElement().getSymbol() != "H")
				{
					map_it->second.push_back(it->getPosition());
				}
			}
		}
	}
	delete original;

	// Retrieve coordinates of input poses and calculate RMSDs
	GenericMolFile* input = MolFileFactory::open(parpars.get("i"));
	GenericMolFile* output = 0;
	String filename = parpars.get("o");
	if (filename != CommandlineParser::NOT_FOUND)
	{
		output = MolFileFactory::open(filename, ios::out, input);
	}

	double average_RMSD = 0;
	int no_mols = 0;
	int no_valid_rmsds = 0;
	bool quiet = (parpars.get("quiet")!=CommandlineParser::NOT_FOUND);

	for (Molecule* mol = input->read(); mol; delete mol, mol = input->read())
	{
		no_mols++;
		String topology_hash;
		FlexibleMolecule::generateTopologyHash(mol, topology_hash, true);

		HashMap<String, list<Vector3> >::iterator map_it = original_poses.find(topology_hash);
		if (map_it == original_poses.end())
		{
			Log<<"[Warning:] no original pose for molecule '"<<mol->getName()<<"' found, its RMSD can thus not be computed."<<endl;
			mol->setProperty("RMSD", "N/A");
		}
		else
		{
			double RMSD = 0;
			list<Vector3>::iterator list_it = map_it->second.begin();
			int no_heavy_atoms = 0;
			AtomConstIterator it = mol->beginAtom();
			for (; +it ; it++)
			{
				if (it->getElement().getSymbol() != "H" && list_it != map_it->second.end())
				{
					RMSD += pow(it->getPosition().getDistance(*list_it), 2);
					no_heavy_atoms++;
					list_it++;
				}
			}
			if (it != mol->endAtom() || list_it != map_it->second.end())
			{
				Log.error()<<"[Error:] Number of heavy atoms of input pose do not match number of heavy atoms of original pose!!"<<endl;
				return 1;
			}
			RMSD = sqrt(RMSD/no_heavy_atoms);
			mol->setProperty("RMSD", RMSD);
			average_RMSD += RMSD;
			no_valid_rmsds++;

			if (!quiet) Log << "RMSD for molecule "<<no_mols<<", '"<<mol->getName()<<"' = "<<RMSD<<endl;
		}

		if (output) *output << *mol;
	}

	average_RMSD /= no_valid_rmsds;

	Log <<endl<<"average RMSD = "<<average_RMSD<<endl<<endl;

	delete input;
	delete output;
	return 0;
}
<commit_msg>Removed the inaccurate license<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//

#include <BALL/FORMAT/PDBFile.h>
#include <BALL/FORMAT/molFileFactory.h>
#include <BALL/FORMAT/commandlineParser.h>
#include <BALL/DATATYPE/options.h>
#include <BALL/KERNEL/PTE.h>
#include <BALL/DOCKING/COMMON/flexibleMolecule.h>
#include "version.h"

using namespace BALL;
using namespace std;

int main(int argc, char* argv[])
{
	CommandlineParser parpars("RMSDCalculator", "calculate RMSD between poses", VERSION, String(__DATE__), "Analysis");
	parpars.registerParameter("i", "input molecule file", INFILE, true);
	parpars.registerParameter("org", "molecule file containing the original ('true') poses", INFILE, true);
	parpars.registerParameter("o", "output molecule file", OUTFILE);
	parpars.registerFlag("quiet", "by quiet, i.e. do not print progress information");
	String man = "This tool calculates the RMSD between different conformations of the same molecule.\n\nTherefore this tool can for example be used to evaluate the different between ligands taken from co-crystal structures and their poses generated by a docking.\nMolecules may be sorted differently in the two input files; a topology hashkey will be used to match molecules to each other.\n\nOutput of this tool is a molecule file which will for each molecule contain a property-tag 'RMSD' holding the calculated RMSD value.";
	parpars.setToolManual(man);
	parpars.setSupportedFormats("i",MolFileFactory::getSupportedFormats());
	parpars.setSupportedFormats("org",MolFileFactory::getSupportedFormats());
	parpars.setSupportedFormats("o","mol2,sdf,drf");
	parpars.setOutputFormatSource("o","i");
	parpars.parse(argc, argv);

	// Retrieve coordinates of original poses
	GenericMolFile* original = MolFileFactory::open(parpars.get("org"));
	HashMap<String, list<Vector3> > original_poses;
	for (Molecule* mol = original->read(); mol; delete mol, mol = original->read())
	{
		String topology_hash;
		FlexibleMolecule::generateTopologyHash(mol, topology_hash, true);
		if (original_poses.find(topology_hash) != original_poses.end())
		{
			Log<<"[Warning:] more than one 'original' conformation for a molecule detected. Will use only the first conformation and ignore all other."<<endl;
		}
		else
		{
			list<Vector3> l;
			HashMap<String, list<Vector3> >::iterator map_it = original_poses.insert(make_pair(topology_hash, l)).first;

			for (AtomConstIterator it = mol->beginAtom(); +it; it++)
			{
				if (it->getElement().getSymbol() != "H")
				{
					map_it->second.push_back(it->getPosition());
				}
			}
		}
	}
	delete original;

	// Retrieve coordinates of input poses and calculate RMSDs
	GenericMolFile* input = MolFileFactory::open(parpars.get("i"));
	GenericMolFile* output = 0;
	String filename = parpars.get("o");
	if (filename != CommandlineParser::NOT_FOUND)
	{
		output = MolFileFactory::open(filename, ios::out, input);
	}

	double average_RMSD = 0;
	int no_mols = 0;
	int no_valid_rmsds = 0;
	bool quiet = (parpars.get("quiet")!=CommandlineParser::NOT_FOUND);

	for (Molecule* mol = input->read(); mol; delete mol, mol = input->read())
	{
		no_mols++;
		String topology_hash;
		FlexibleMolecule::generateTopologyHash(mol, topology_hash, true);

		HashMap<String, list<Vector3> >::iterator map_it = original_poses.find(topology_hash);
		if (map_it == original_poses.end())
		{
			Log<<"[Warning:] no original pose for molecule '"<<mol->getName()<<"' found, its RMSD can thus not be computed."<<endl;
			mol->setProperty("RMSD", "N/A");
		}
		else
		{
			double RMSD = 0;
			list<Vector3>::iterator list_it = map_it->second.begin();
			int no_heavy_atoms = 0;
			AtomConstIterator it = mol->beginAtom();
			for (; +it ; it++)
			{
				if (it->getElement().getSymbol() != "H" && list_it != map_it->second.end())
				{
					RMSD += pow(it->getPosition().getDistance(*list_it), 2);
					no_heavy_atoms++;
					list_it++;
				}
			}
			if (it != mol->endAtom() || list_it != map_it->second.end())
			{
				Log.error()<<"[Error:] Number of heavy atoms of input pose do not match number of heavy atoms of original pose!!"<<endl;
				return 1;
			}
			RMSD = sqrt(RMSD/no_heavy_atoms);
			mol->setProperty("RMSD", RMSD);
			average_RMSD += RMSD;
			no_valid_rmsds++;

			if (!quiet) Log << "RMSD for molecule "<<no_mols<<", '"<<mol->getName()<<"' = "<<RMSD<<endl;
		}

		if (output) *output << *mol;
	}

	average_RMSD /= no_valid_rmsds;

	Log <<endl<<"average RMSD = "<<average_RMSD<<endl<<endl;

	delete input;
	delete output;
	return 0;
}
<|endoftext|>


<commit_before>//===-- ProcessLauncherLinux.cpp --------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/linux/ProcessLauncherLinux.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Target/ProcessLaunchInfo.h"

#include <limits.h>
#include <sys/personality.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <sstream>

using namespace lldb;
using namespace lldb_private;

static void FixupEnvironment(Args &env) {
#ifdef __ANDROID_NDK__
  // If there is no PATH variable specified inside the environment then set the
  // path to /system/bin. It is required because the default path used by
  // execve() is wrong on android.
  static const char *path = "PATH=";
  for (auto &entry : entries) {
    if (entry.ref.startswith(path))
      return;
  }
  env.AppendArgument(llvm::StringRef("PATH=/system/bin"));
#endif
}

static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
                                                  const char *operation) {
  std::ostringstream os;
  os << operation << " failed: " << strerror(errno);
  write(error_fd, os.str().data(), os.str().size());
  close(error_fd);
  _exit(1);
}

static void DupDescriptor(int error_fd, const FileSpec &file_spec, int fd,
                          int flags) {
  int target_fd = ::open(file_spec.GetCString(), flags, 0666);

  if (target_fd == -1)
    ExitWithError(error_fd, "DupDescriptor-open");

  if (target_fd == fd)
    return;

  if (::dup2(target_fd, fd) == -1)
    ExitWithError(error_fd, "DupDescriptor-dup2");

  ::close(target_fd);
  return;
}

static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
                                              const ProcessLaunchInfo &info) {
  // First, make sure we disable all logging. If we are logging to stdout, our
  // logs can be
  // mistaken for inferior output.
  Log::DisableAllLogChannels(nullptr);

  // Do not inherit setgid powers.
  if (setgid(getgid()) != 0)
    ExitWithError(error_fd, "setgid");

  if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
    if (setpgid(0, 0) != 0)
      ExitWithError(error_fd, "setpgid");
  }

  for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
    const FileAction &action = *info.GetFileActionAtIndex(i);
    switch (action.GetAction()) {
    case FileAction::eFileActionClose:
      if (close(action.GetFD()) != 0)
        ExitWithError(error_fd, "close");
      break;
    case FileAction::eFileActionDuplicate:
      if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
        ExitWithError(error_fd, "dup2");
      break;
    case FileAction::eFileActionOpen:
      DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
                    action.GetActionArgument());
      break;
    case FileAction::eFileActionNone:
      break;
    }
  }

  const char **argv = info.GetArguments().GetConstArgumentVector();

  // Change working directory
  if (info.GetWorkingDirectory() &&
      0 != ::chdir(info.GetWorkingDirectory().GetCString()))
    ExitWithError(error_fd, "chdir");

  // Disable ASLR if requested.
  if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
    const unsigned long personality_get_current = 0xffffffff;
    int value = personality(personality_get_current);
    if (value == -1)
      ExitWithError(error_fd, "personality get");

    value = personality(ADDR_NO_RANDOMIZE | value);
    if (value == -1)
      ExitWithError(error_fd, "personality set");
  }

  Args env = info.GetEnvironmentEntries();
  FixupEnvironment(env);
  const char **envp = env.GetConstArgumentVector();

  // Clear the signal mask to prevent the child from being affected by
  // any masking done by the parent.
  sigset_t set;
  if (sigemptyset(&set) != 0 ||
      pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
    ExitWithError(error_fd, "pthread_sigmask");

  if (info.GetFlags().Test(eLaunchFlagDebug)) {
    // HACK:
    // Close everything besides stdin, stdout, and stderr that has no file
    // action to avoid leaking. Only do this when debugging, as elsewhere we
    // actually rely on
    // passing open descriptors to child processes.
    for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
      if (!info.GetFileActionForFD(fd) && fd != error_fd)
        close(fd);

    // Start tracing this child that is about to exec.
    if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
      ExitWithError(error_fd, "ptrace");
  }

  // Execute.  We should never return...
  execve(argv[0], const_cast<char *const *>(argv),
         const_cast<char *const *>(envp));

  if (errno == ETXTBSY) {
    // On android M and earlier we can get this error because the adb deamon can
    // hold a write
    // handle on the executable even after it has finished uploading it. This
    // state lasts
    // only a short time and happens only when there are many concurrent adb
    // commands being
    // issued, such as when running the test suite. (The file remains open when
    // someone does
    // an "adb shell" command in the fork() child before it has had a chance to
    // exec.) Since
    // this state should clear up quickly, wait a while and then give it one
    // more go.
    usleep(50000);
    execve(argv[0], const_cast<char *const *>(argv),
           const_cast<char *const *>(envp));
  }

  // ...unless exec fails.  In which case we definitely need to end the child
  // here.
  ExitWithError(error_fd, "execve");
}

HostProcess
ProcessLauncherLinux::LaunchProcess(const ProcessLaunchInfo &launch_info,
                                    Error &error) {
  char exe_path[PATH_MAX];
  launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));

  // A pipe used by the child process to report errors.
  PipePosix pipe;
  const bool child_processes_inherit = false;
  error = pipe.CreateNew(child_processes_inherit);
  if (error.Fail())
    return HostProcess();

  ::pid_t pid = ::fork();
  if (pid == -1) {
    // Fork failed
    error.SetErrorStringWithFormat("Fork failed with error message: %s",
                                   strerror(errno));
    return HostProcess(LLDB_INVALID_PROCESS_ID);
  }
  if (pid == 0) {
    // child process
    pipe.CloseReadFileDescriptor();
    ChildFunc(pipe.ReleaseWriteFileDescriptor(), launch_info);
  }

  // parent process

  pipe.CloseWriteFileDescriptor();
  char buf[1000];
  int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);

  if (r == 0)
    return HostProcess(pid); // No error. We're done.

  error.SetErrorString(buf);

  waitpid(pid, nullptr, 0);

  return HostProcess();
}
<commit_msg>Fix build error on Android again.<commit_after>//===-- ProcessLauncherLinux.cpp --------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Host/linux/ProcessLauncherLinux.h"
#include "lldb/Core/Log.h"
#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Target/ProcessLaunchInfo.h"

#include <limits.h>
#include <sys/personality.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

#include <sstream>

using namespace lldb;
using namespace lldb_private;

static void FixupEnvironment(Args &env) {
#ifdef __ANDROID_NDK__
  // If there is no PATH variable specified inside the environment then set the
  // path to /system/bin. It is required because the default path used by
  // execve() is wrong on android.
  static const char *path = "PATH=";
  for (auto &entry : env.entries()) {
    if (entry.ref.startswith(path))
      return;
  }
  env.AppendArgument(llvm::StringRef("PATH=/system/bin"));
#endif
}

static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
                                                  const char *operation) {
  std::ostringstream os;
  os << operation << " failed: " << strerror(errno);
  write(error_fd, os.str().data(), os.str().size());
  close(error_fd);
  _exit(1);
}

static void DupDescriptor(int error_fd, const FileSpec &file_spec, int fd,
                          int flags) {
  int target_fd = ::open(file_spec.GetCString(), flags, 0666);

  if (target_fd == -1)
    ExitWithError(error_fd, "DupDescriptor-open");

  if (target_fd == fd)
    return;

  if (::dup2(target_fd, fd) == -1)
    ExitWithError(error_fd, "DupDescriptor-dup2");

  ::close(target_fd);
  return;
}

static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
                                              const ProcessLaunchInfo &info) {
  // First, make sure we disable all logging. If we are logging to stdout, our
  // logs can be
  // mistaken for inferior output.
  Log::DisableAllLogChannels(nullptr);

  // Do not inherit setgid powers.
  if (setgid(getgid()) != 0)
    ExitWithError(error_fd, "setgid");

  if (info.GetFlags().Test(eLaunchFlagLaunchInSeparateProcessGroup)) {
    if (setpgid(0, 0) != 0)
      ExitWithError(error_fd, "setpgid");
  }

  for (size_t i = 0; i < info.GetNumFileActions(); ++i) {
    const FileAction &action = *info.GetFileActionAtIndex(i);
    switch (action.GetAction()) {
    case FileAction::eFileActionClose:
      if (close(action.GetFD()) != 0)
        ExitWithError(error_fd, "close");
      break;
    case FileAction::eFileActionDuplicate:
      if (dup2(action.GetFD(), action.GetActionArgument()) == -1)
        ExitWithError(error_fd, "dup2");
      break;
    case FileAction::eFileActionOpen:
      DupDescriptor(error_fd, action.GetFileSpec(), action.GetFD(),
                    action.GetActionArgument());
      break;
    case FileAction::eFileActionNone:
      break;
    }
  }

  const char **argv = info.GetArguments().GetConstArgumentVector();

  // Change working directory
  if (info.GetWorkingDirectory() &&
      0 != ::chdir(info.GetWorkingDirectory().GetCString()))
    ExitWithError(error_fd, "chdir");

  // Disable ASLR if requested.
  if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) {
    const unsigned long personality_get_current = 0xffffffff;
    int value = personality(personality_get_current);
    if (value == -1)
      ExitWithError(error_fd, "personality get");

    value = personality(ADDR_NO_RANDOMIZE | value);
    if (value == -1)
      ExitWithError(error_fd, "personality set");
  }

  Args env = info.GetEnvironmentEntries();
  FixupEnvironment(env);
  const char **envp = env.GetConstArgumentVector();

  // Clear the signal mask to prevent the child from being affected by
  // any masking done by the parent.
  sigset_t set;
  if (sigemptyset(&set) != 0 ||
      pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0)
    ExitWithError(error_fd, "pthread_sigmask");

  if (info.GetFlags().Test(eLaunchFlagDebug)) {
    // HACK:
    // Close everything besides stdin, stdout, and stderr that has no file
    // action to avoid leaking. Only do this when debugging, as elsewhere we
    // actually rely on
    // passing open descriptors to child processes.
    for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd)
      if (!info.GetFileActionForFD(fd) && fd != error_fd)
        close(fd);

    // Start tracing this child that is about to exec.
    if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
      ExitWithError(error_fd, "ptrace");
  }

  // Execute.  We should never return...
  execve(argv[0], const_cast<char *const *>(argv),
         const_cast<char *const *>(envp));

  if (errno == ETXTBSY) {
    // On android M and earlier we can get this error because the adb deamon can
    // hold a write
    // handle on the executable even after it has finished uploading it. This
    // state lasts
    // only a short time and happens only when there are many concurrent adb
    // commands being
    // issued, such as when running the test suite. (The file remains open when
    // someone does
    // an "adb shell" command in the fork() child before it has had a chance to
    // exec.) Since
    // this state should clear up quickly, wait a while and then give it one
    // more go.
    usleep(50000);
    execve(argv[0], const_cast<char *const *>(argv),
           const_cast<char *const *>(envp));
  }

  // ...unless exec fails.  In which case we definitely need to end the child
  // here.
  ExitWithError(error_fd, "execve");
}

HostProcess
ProcessLauncherLinux::LaunchProcess(const ProcessLaunchInfo &launch_info,
                                    Error &error) {
  char exe_path[PATH_MAX];
  launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));

  // A pipe used by the child process to report errors.
  PipePosix pipe;
  const bool child_processes_inherit = false;
  error = pipe.CreateNew(child_processes_inherit);
  if (error.Fail())
    return HostProcess();

  ::pid_t pid = ::fork();
  if (pid == -1) {
    // Fork failed
    error.SetErrorStringWithFormat("Fork failed with error message: %s",
                                   strerror(errno));
    return HostProcess(LLDB_INVALID_PROCESS_ID);
  }
  if (pid == 0) {
    // child process
    pipe.CloseReadFileDescriptor();
    ChildFunc(pipe.ReleaseWriteFileDescriptor(), launch_info);
  }

  // parent process

  pipe.CloseWriteFileDescriptor();
  char buf[1000];
  int r = read(pipe.GetReadFileDescriptor(), buf, sizeof buf);

  if (r == 0)
    return HostProcess(pid); // No error. We're done.

  error.SetErrorString(buf);

  waitpid(pid, nullptr, 0);

  return HostProcess();
}
<|endoftext|>