<commit_before>/**
 * The MIT License
 *
 * Copyright (C) 2017 Kiyofumi Kondoh
 *
 * 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.
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "kk-win-lib-checker-memory-operation-mismatch-hook-util.h"

#include <assert.h>

namespace kk
{

namespace checker
{

namespace hookutil
{

static
LPVOID
getAlignedPage( LPVOID pAddr, const DWORD pageSize )
{
    LPVOID result = NULL;

    if ( 0 == pageSize )
    {
        assert( 0 != pageSize );
        return NULL;
    }

    assert( sizeof(size_t) == sizeof(LPVOID) );

    const size_t p = reinterpret_cast<size_t>(pAddr);

    const size_t count = p / pageSize;
    const size_t addr = count * pageSize;

    result = reinterpret_cast<LPVOID>(addr);

    return result;
}

const DWORD
getPageSize(void)
{
    DWORD   result = 4*1024;

    SYSTEM_INFO     info;
    {
        ::GetSystemInfo( &info );
        if ( 0 != info.dwPageSize )
        {
            result = info.dwPageSize;
        }
    }

    return result;
}

bool
trampolinePageDeallocate( LPVOID pTrampolinePage )
{
    bool result = true;

    {
        const DWORD dwFreeType = MEM_RELEASE;

        const BOOL BRet = ::VirtualFree( pTrampolinePage, 0, dwFreeType );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
            result = false;
        }
    }

    return result;
}

bool
tranpolinePageDropWriteOperation( LPVOID pTrampolinePage, const DWORD changeSize )
{
    bool result = true;

    const size_t size = static_cast<const size_t>(changeSize);
    {
        DWORD dwProtect = 0;

        const BOOL BRet = ::VirtualProtect( (LPVOID)pTrampolinePage, size, PAGE_EXECUTE_READ, &dwProtect );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
            result = false;
        }
    }

    {
        HANDLE hProcess = ::GetCurrentProcess();
        const BOOL BRet = ::FlushInstructionCache( hProcess, pTrampolinePage, size );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
        }
    }

    return result;
}

LPVOID
trampolinePageAllocate( LPVOID minAddr, LPVOID maxAddr )
{
    LPVOID pTrampolinePage = NULL;

    const DWORD pageSize = getPageSize();

    {
        const DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
        const DWORD flProtect = PAGE_READWRITE;

        // todo: x64 limit -2G to +2G
        {
            const DWORD64 pAddrStart = reinterpret_cast<DWORD64>(getAlignedPage(maxAddr,pageSize));
            const DWORD64 pAddrEnd = pageSize;

            for (
                DWORD64 pAddr = pAddrStart - pageSize;
                pAddrEnd < pAddr;
                pAddr -= pageSize
            )
            {
                LPVOID p = ::VirtualAlloc( (LPVOID)pAddr, (size_t)pageSize, flAllocationType, flProtect );
                if ( NULL != p )
                {
                    pTrampolinePage = p;
                    break;
                }
            }
        }
        if ( NULL == pTrampolinePage )
        {
            const DWORD64 pAddrStart = reinterpret_cast<DWORD64>(getAlignedPage(minAddr,pageSize));
            const DWORD64 pAddrEnd = (-1)-pageSize;
            for (
                DWORD64 pAddr = pAddrStart + pageSize*16;
                pAddr < pAddrEnd;
                pAddr += pageSize
            )
            {
                LPVOID p = ::VirtualAlloc( (LPVOID)pAddr, (size_t)pageSize, flAllocationType, flProtect );
                if ( NULL != p )
                {
                    pTrampolinePage = p;
                    break;
                }
            }
        }
    }

    return pTrampolinePage;
}

} // namespace hookutil

} // namespace checker

} // namespace kk

<commit_msg>support x64 limit to range of rel32<commit_after>/**
 * The MIT License
 *
 * Copyright (C) 2017 Kiyofumi Kondoh
 *
 * 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.
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include "kk-win-lib-checker-memory-operation-mismatch-hook-util.h"

#include <assert.h>

namespace kk
{

namespace checker
{

namespace hookutil
{

static
LPVOID
getAlignedPage( LPVOID pAddr, const DWORD pageSize )
{
    LPVOID result = NULL;

    if ( 0 == pageSize )
    {
        assert( 0 != pageSize );
        return NULL;
    }

    assert( sizeof(size_t) == sizeof(LPVOID) );

    const size_t p = reinterpret_cast<size_t>(pAddr);

    const size_t count = p / pageSize;
    const size_t addr = count * pageSize;

    result = reinterpret_cast<LPVOID>(addr);

    return result;
}

static const DWORD64 limit31bit = 0x000000007fffffffULL;
static const DWORD64 limit32bit = 0x00000000ffffffffULL;
static const DWORD64 limit64bit = 0xffffffffffffffffULL;

static
const DWORD64
getLimitPageBackword( const DWORD64 pAddr, const DWORD64 pageSize )
{
    DWORD64 addr = 0;

#if defined(_M_IX86)
    addr = pageSize;
#endif // defined(_M_IX86)

#if defined(_M_X64)
    if ( pAddr < limit31bit )
    {
        addr = pageSize;
    }
    else
    {
        addr = (pAddr+pageSize)-limit31bit;
    }
#endif // defined(_M_X64)

    addr = (size_t)getAlignedPage( (LPVOID)addr, (const DWORD)pageSize );

    return addr;
}

static
const DWORD64
getLimitPageForward( const DWORD64 pAddr, const DWORD64 pageSize )
{
    DWORD64 addr = 0;

#if defined(_M_IX86)
    addr = limit32bit-pageSize;
#endif // defined(_M_IX86)

#if defined(_M_X64)
    if ( (limit64bit-limit31bit) < pAddr )
    {
        addr = limit64bit-pageSize;
    }
    else
    {
        addr = pAddr + limit31bit;
    }
#endif // defined(_M_X64)

    addr = (size_t)getAlignedPage( (LPVOID)addr, (const DWORD)pageSize );

    return addr;
}

const DWORD
getPageSize(void)
{
    DWORD   result = 4*1024;

    SYSTEM_INFO     info;
    {
        ::GetSystemInfo( &info );
        if ( 0 != info.dwPageSize )
        {
            result = info.dwPageSize;
        }
    }

    return result;
}

bool
trampolinePageDeallocate( LPVOID pTrampolinePage )
{
    bool result = true;

    {
        const DWORD dwFreeType = MEM_RELEASE;

        const BOOL BRet = ::VirtualFree( pTrampolinePage, 0, dwFreeType );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
            result = false;
        }
    }

    return result;
}

bool
tranpolinePageDropWriteOperation( LPVOID pTrampolinePage, const DWORD changeSize )
{
    bool result = true;

    const size_t size = static_cast<const size_t>(changeSize);
    {
        DWORD dwProtect = 0;

        const BOOL BRet = ::VirtualProtect( (LPVOID)pTrampolinePage, size, PAGE_EXECUTE_READ, &dwProtect );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
            result = false;
        }
    }

    {
        HANDLE hProcess = ::GetCurrentProcess();
        const BOOL BRet = ::FlushInstructionCache( hProcess, pTrampolinePage, size );
        if ( !BRet )
        {
            const DWORD dwErr = ::GetLastError();
        }
    }

    return result;
}

LPVOID
trampolinePageAllocate( LPVOID minAddr, LPVOID maxAddr )
{
    LPVOID pTrampolinePage = NULL;

    const DWORD pageSize = getPageSize();

    {
        const DWORD flAllocationType = MEM_COMMIT | MEM_RESERVE;
        const DWORD flProtect = PAGE_READWRITE;

        {
            const DWORD64 pAddrStart = reinterpret_cast<DWORD64>(getAlignedPage(maxAddr,pageSize));
            const DWORD64 pAddrEnd = getLimitPageBackword(pAddrStart, pageSize);

            for (
                DWORD64 pAddr = pAddrStart - pageSize;
                pAddrEnd < pAddr;
                pAddr -= pageSize
            )
            {
                LPVOID p = ::VirtualAlloc( (LPVOID)pAddr, (size_t)pageSize, flAllocationType, flProtect );
                if ( NULL != p )
                {
                    pTrampolinePage = p;
                    break;
                }
            }
        }

        if ( NULL == pTrampolinePage )
        {
            const DWORD64 pAddrStart = reinterpret_cast<DWORD64>(getAlignedPage(minAddr,pageSize));
            const DWORD64 pAddrEnd = getLimitPageForward(pAddrStart, pageSize);

            for (
                DWORD64 pAddr = pAddrStart + pageSize*16;
                pAddr < pAddrEnd;
                pAddr += pageSize
            )
            {
                LPVOID p = ::VirtualAlloc( (LPVOID)pAddr, (size_t)pageSize, flAllocationType, flProtect );
                if ( NULL != p )
                {
                    pTrampolinePage = p;
                    break;
                }
            }
        }
    }

    return pTrampolinePage;
}

} // namespace hookutil

} // namespace checker

} // namespace kk

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "addressfinder.h"

#include <QComboBox>
#include <QDateTime>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QListWidget>
#include <QPushButton>
#include <QTimer>
#include <QDebug>

AddressFinder::AddressFinder(QWidget *parent, Qt::WindowFlags flags)
    : QWidget(parent, flags),
      includePeriod(0),
      excludePeriod(0),
      searchButton(0),
      addressList(0),
      messageList(0)
{
    setWindowTitle(tr("Keep In Touch"));

    excludePeriod = new QComboBox;
    excludePeriod ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    includePeriod = new QComboBox;
    excludePeriod ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    includePeriod->addItem(tr("Year"));
    includePeriod->addItem(tr("9 Months"));
    includePeriod->addItem(tr("6 Months"));
    includePeriod->addItem(tr("3 Months"));
    includePeriod->addItem(tr("Month"));

    includePeriodChanged(0);

    connect(includePeriod, SIGNAL(currentIndexChanged(int)), this, SLOT(includePeriodChanged(int)));

    QLabel *includeLabel = new QLabel(tr("Contacted within the last"));

    QLabel *excludeLabel = new QLabel(tr("But not the last"));

    QGridLayout *filterLayout = new QGridLayout;
    filterLayout->addWidget(includeLabel, 0, 0);
    filterLayout->setAlignment(includeLabel, Qt::AlignRight);
    filterLayout->addWidget(excludeLabel, 1, 0);
    filterLayout->setAlignment(excludeLabel, Qt::AlignRight);
    filterLayout->addWidget(includePeriod, 0, 1);
    filterLayout->addWidget(excludePeriod, 1, 1);

    QGroupBox *inputGroup = new QGroupBox(tr("Find addresses"));
    inputGroup->setLayout(filterLayout);
    inputGroup->setAlignment(Qt::AlignLeft);

    searchButton = new QPushButton(tr("Search"));
    searchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    connect(searchButton, SIGNAL(clicked()), this, SLOT(searchMessages()), Qt::QueuedConnection);

    QHBoxLayout *inputLayout = new QHBoxLayout;
    inputLayout->addWidget(inputGroup);
    inputLayout->setStretchFactor(inputGroup, 2);
    inputLayout->addWidget(searchButton);
    inputLayout->setStretchFactor(searchButton, 1);
    inputLayout->setAlignment(searchButton, Qt::AlignLeft | Qt::AlignBottom);
    inputLayout->addStretch(1);

    addressList = new QListWidget;
    addressList ->setSelectionMode(QAbstractItemView::SingleSelection);

    connect(addressList, SIGNAL(currentTextChanged(QString)), this, SLOT(addressSelected(QString)));

    QGroupBox *addressGroup = new QGroupBox(tr("Address"));
    addressGroup->setAlignment(Qt::AlignLeft);
    addressGroup->setLayout(new QHBoxLayout);
    addressGroup->layout()->addWidget(addressList);

    messageList = new QListWidget;
    messageList->setSelectionMode(QAbstractItemView::NoSelection);

    QGroupBox *messageGroup = new QGroupBox(tr("Messages"));
    messageGroup->setAlignment(Qt::AlignLeft);
    messageGroup->setLayout(new QHBoxLayout);
    messageGroup->layout()->addWidget(messageList);

    QHBoxLayout *outputLayout = new QHBoxLayout;
    outputLayout->addWidget(addressGroup);
    outputLayout->addWidget(messageGroup);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(inputLayout);
    mainLayout->addLayout(outputLayout);
}

AddressFinder::~AddressFinder()
{
}

void AddressFinder::includePeriodChanged(int selected)
{
    // Only allow smaller periods to be excluded
    excludePeriod->clear();

    switch (selected) {
        case 0: excludePeriod->insertItem(0, "9 Months"); // fall through:
        case 1: excludePeriod->insertItem(0, "6 Months");
        case 2: excludePeriod->insertItem(0, "3 Months");
        case 3: excludePeriod->insertItem(0, "Month");
        case 4: excludePeriod->insertItem(0, "Week");
        default: break;
    }

    excludePeriod->setCurrentIndex(0);
}

void AddressFinder::addressSelected(const QString &address)
{
    messageList->clear();

    foreach (const QString &message, addressMessages[address]) {
        messageList->addItem(new QListWidgetItem(message));
    }
}

void AddressFinder::searchMessages()
{
    searchButton->setEnabled(false);

    // TODO: make this unnecessary:
    QMessageStore::instance();

    addressList->clear();
    messageList->clear();
    addressMessages.clear();

    QDateTime now(QDateTime::currentDateTime());

    QDateTime minimumDate(now);
    switch (includePeriod->currentIndex()) {
        case 0: minimumDate = minimumDate.addMonths(-12); break;
        case 1: minimumDate = minimumDate.addMonths(-9); break;
        case 2: minimumDate = minimumDate.addMonths(-6); break;
        case 3: minimumDate = minimumDate.addMonths(-3); break;
        case 4: minimumDate = minimumDate.addMonths(-1); break;
        default: break;
    }

    QDateTime maximumDate(now);
    switch (excludePeriod->currentIndex()) {
        case 0: maximumDate = maximumDate.addDays(-7); break;
        case 1: maximumDate = maximumDate.addMonths(-1); break;
        case 2: maximumDate = maximumDate.addMonths(-3); break;
        case 3: maximumDate = maximumDate.addMonths(-6); break;
        case 4: maximumDate = maximumDate.addMonths(-9); break;
        default: break;
    }

    QMessageFilterKey includeFilter(QMessageFilterKey::timeStamp(minimumDate, QMessageDataComparator::GreaterThanEqual));
    QMessageFilterKey excludeFilter(QMessageFilterKey::timeStamp(maximumDate, QMessageDataComparator::GreaterThanEqual));
    QMessageFilterKey outgoingFilter(QMessageFilterKey::status(QMessage::Incoming, QMessageDataComparator::Includes));

    // Find all outgoing messages that are within the exclusion range
    exclusionMessages = QMessageStore::instance()->queryMessages(~outgoingFilter & excludeFilter);

    // Find all outgoing messages that are within the inclusion range
    inclusionMessages = QMessageStore::instance()->queryMessages(~outgoingFilter & includeFilter & ~excludeFilter);

    if (!exclusionMessages.isEmpty() || !inclusionMessages.isEmpty()) {
        QTimer::singleShot(0, this, SLOT(continueSearch()));
    } else {
        searchButton->setEnabled(true);
    }
}

void AddressFinder::continueSearch()
{
    if (!exclusionMessages.isEmpty()) {
        QMessageId id(exclusionMessages.takeFirst());
        const QMessage message(id);

        // All recipient addresses are to be excluded
        foreach (const QMessageAddress &address, message.to()) {
            excludedAddresses.insert(address.recipient());
        }
    } else if (!inclusionMessages.isEmpty()) {
        QMessageId id(inclusionMessages.takeFirst());
        const QMessage message(id);

        // Determine the properties of the message
        QString details(QString("[%1] %2").arg(message.date().toString("d MMM")).arg(message.subject()));

        foreach (const QMessageAddress &address, message.to()) {
            QString recipient(address.recipient());
            if (!excludedAddresses.contains(recipient)) {
                // Link this message to this address
                QStringList &messages = addressMessages[recipient];
                if (messages.isEmpty()) {
                    addressList->addItem(recipient);
                }
                messages.append(details);
            }
        }
    }

    if (!exclusionMessages.isEmpty() || !inclusionMessages.isEmpty()) {
        QTimer::singleShot(0, this, SLOT(continueSearch()));
    } else {
        searchButton->setEnabled(true);
    }
}

<commit_msg>Minor cleanups.<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "addressfinder.h"

#include <QComboBox>
#include <QDateTime>
#include <QGroupBox>
#include <QLabel>
#include <QLayout>
#include <QListWidget>
#include <QPushButton>
#include <QTimer>
#include <QDebug>

AddressFinder::AddressFinder(QWidget *parent, Qt::WindowFlags flags)
    : QWidget(parent, flags),
      includePeriod(0),
      excludePeriod(0),
      searchButton(0),
      addressList(0),
      messageList(0)
{
    setWindowTitle(tr("Keep In Touch"));

    excludePeriod = new QComboBox;
    excludePeriod ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    includePeriod = new QComboBox;
    excludePeriod ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    includePeriod->addItem(tr("Year"));
    includePeriod->addItem(tr("9 Months"));
    includePeriod->addItem(tr("6 Months"));
    includePeriod->addItem(tr("3 Months"));
    includePeriod->addItem(tr("Month"));

    includePeriodChanged(0);

    connect(includePeriod, SIGNAL(currentIndexChanged(int)), this, SLOT(includePeriodChanged(int)));

    QLabel *includeLabel = new QLabel(tr("Contacted within the last"));

    QLabel *excludeLabel = new QLabel(tr("But not the last"));

    QGridLayout *filterLayout = new QGridLayout;
    filterLayout->addWidget(includeLabel, 0, 0);
    filterLayout->setAlignment(includeLabel, Qt::AlignRight);
    filterLayout->addWidget(excludeLabel, 1, 0);
    filterLayout->setAlignment(excludeLabel, Qt::AlignRight);
    filterLayout->addWidget(includePeriod, 0, 1);
    filterLayout->addWidget(excludePeriod, 1, 1);

    QGroupBox *inputGroup = new QGroupBox(tr("Find addresses"));
    inputGroup->setLayout(filterLayout);
    inputGroup->setAlignment(Qt::AlignLeft);

    searchButton = new QPushButton(tr("Search"));
    searchButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    connect(searchButton, SIGNAL(clicked()), this, SLOT(searchMessages()), Qt::QueuedConnection);

    QHBoxLayout *inputLayout = new QHBoxLayout;
    inputLayout->addWidget(inputGroup);
    inputLayout->setStretchFactor(inputGroup, 2);
    inputLayout->addWidget(searchButton);
    inputLayout->setStretchFactor(searchButton, 1);
    inputLayout->setAlignment(searchButton, Qt::AlignLeft | Qt::AlignBottom);
    inputLayout->addStretch(1);

    addressList = new QListWidget;
    addressList ->setSelectionMode(QAbstractItemView::SingleSelection);

    connect(addressList, SIGNAL(currentTextChanged(QString)), this, SLOT(addressSelected(QString)));

    QGroupBox *addressGroup = new QGroupBox(tr("Address"));
    addressGroup->setAlignment(Qt::AlignLeft);
    addressGroup->setLayout(new QHBoxLayout);
    addressGroup->layout()->addWidget(addressList);

    messageList = new QListWidget;
    messageList->setSelectionMode(QAbstractItemView::NoSelection);

    QGroupBox *messageGroup = new QGroupBox(tr("Messages"));
    messageGroup->setAlignment(Qt::AlignLeft);
    messageGroup->setLayout(new QHBoxLayout);
    messageGroup->layout()->addWidget(messageList);

    QHBoxLayout *outputLayout = new QHBoxLayout;
    outputLayout->addWidget(addressGroup);
    outputLayout->addWidget(messageGroup);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addLayout(inputLayout);
    mainLayout->addLayout(outputLayout);
}

AddressFinder::~AddressFinder()
{
}

void AddressFinder::includePeriodChanged(int selected)
{
    // Only allow smaller periods to be excluded
    excludePeriod->clear();

    switch (selected) {
        case 0: excludePeriod->insertItem(0, "9 Months"); // fall through:
        case 1: excludePeriod->insertItem(0, "6 Months");
        case 2: excludePeriod->insertItem(0, "3 Months");
        case 3: excludePeriod->insertItem(0, "Month");
        case 4: excludePeriod->insertItem(0, "Week");
        default: break;
    }

    excludePeriod->setCurrentIndex(0);
}

void AddressFinder::addressSelected(const QString &address)
{
    messageList->clear();

    foreach (const QString &message, addressMessages[address]) {
        messageList->addItem(new QListWidgetItem(message));
    }
}

void AddressFinder::searchMessages()
{
    searchButton->setEnabled(false);

    // TODO: make this unnecessary:
    QMessageStore::instance();

    addressList->clear();
    messageList->clear();
    excludedAddresses.clear();
    addressMessages.clear();

    QDateTime now(QDateTime::currentDateTime());

    QDateTime minimumDate(now);
    switch (includePeriod->currentIndex()) {
        case 0: minimumDate = minimumDate.addMonths(-12); break;
        case 1: minimumDate = minimumDate.addMonths(-9); break;
        case 2: minimumDate = minimumDate.addMonths(-6); break;
        case 3: minimumDate = minimumDate.addMonths(-3); break;
        case 4: minimumDate = minimumDate.addMonths(-1); break;
        default: break;
    }

    QDateTime maximumDate(now);
    switch (excludePeriod->currentIndex()) {
        case 0: maximumDate = maximumDate.addDays(-7); break;
        case 1: maximumDate = maximumDate.addMonths(-1); break;
        case 2: maximumDate = maximumDate.addMonths(-3); break;
        case 3: maximumDate = maximumDate.addMonths(-6); break;
        case 4: maximumDate = maximumDate.addMonths(-9); break;
        default: break;
    }

    QMessageFilterKey includeFilter(QMessageFilterKey::timeStamp(minimumDate, QMessageDataComparator::GreaterThanEqual));
    QMessageFilterKey excludeFilter(QMessageFilterKey::timeStamp(maximumDate, QMessageDataComparator::GreaterThanEqual));
    QMessageFilterKey outgoingFilter(QMessageFilterKey::status(QMessage::Incoming, QMessageDataComparator::Excludes));

    // Find all outgoing messages that are within the exclusion range
    exclusionMessages = QMessageStore::instance()->queryMessages(outgoingFilter & excludeFilter);

    // Find all outgoing messages that are within the inclusion range
    inclusionMessages = QMessageStore::instance()->queryMessages(outgoingFilter & includeFilter & ~excludeFilter);

    if (!inclusionMessages.isEmpty()) {
        QTimer::singleShot(0, this, SLOT(continueSearch()));
    } else {
        searchButton->setEnabled(true);
    }
}

void AddressFinder::continueSearch()
{
    if (!exclusionMessages.isEmpty()) {
        QMessageId id(exclusionMessages.takeFirst());
        const QMessage message(id);

        // All recipient addresses are to be excluded
        foreach (const QMessageAddress &address, message.to()) {
            excludedAddresses.insert(address.recipient());
        }
    } else if (!inclusionMessages.isEmpty()) {
        QMessageId id(inclusionMessages.takeFirst());
        const QMessage message(id);

        // Determine the properties of the message
        QString details(QString("[%1] %2").arg(message.date().toString("d MMM")).arg(message.subject()));

        foreach (const QMessageAddress &address, message.to()) {
            QString recipient(address.recipient());
            if (!excludedAddresses.contains(recipient)) {
                // Link this message to this address
                QStringList &messages = addressMessages[recipient];
                if (messages.isEmpty()) {
                    addressList->addItem(recipient);
                }
                messages.append(details);
            }
        }
    }

    if (!exclusionMessages.isEmpty() || !inclusionMessages.isEmpty()) {
        QTimer::singleShot(0, this, SLOT(continueSearch()));
    } else {
        searchButton->setEnabled(true);
    }
}

<|endoftext|>


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

#include "third_party/javaprofiler/display.h"
#include "third_party/javaprofiler/stacktrace_fixer.h"
#include "third_party/javaprofiler/profile_proto_builder.h"

using std::unique_ptr;

namespace google {
namespace javaprofiler {

const int kCount = 0;
const int kMetric = 1;

ProfileProtoBuilder::ProfileProtoBuilder(JNIEnv *jni_env, jvmtiEnv *jvmti_env,
                                         ProfileFrameCache *native_cache,
                                         int64 sampling_rate,
                                         const SampleType &count_type,
                                         const SampleType &metric_type)
    : sampling_rate_(sampling_rate),
      jni_env_(jni_env),
      jvmti_env_(jvmti_env),
      native_cache_(native_cache),
      location_builder_(&builder_) {
  AddSampleType(count_type);
  AddSampleType(metric_type);
  SetPeriodType(metric_type);
}

void ProfileProtoBuilder::AddTraces(const ProfileStackTrace *traces,
                                    int num_traces) {
  if (native_cache_) {
    native_cache_->ProcessTraces(traces, num_traces);
  }

  for (int i = 0; i < num_traces; ++i) {
    AddTrace(traces[i], 1);
  }
}

void ProfileProtoBuilder::AddTraces(const ProfileStackTrace *traces,
                                    const int32 *counts,
                                    int num_traces) {
  if (native_cache_) {
    native_cache_->ProcessTraces(traces, num_traces);
  }

  for (int i = 0; i < num_traces; ++i) {
    AddTrace(traces[i], counts[i]);
  }
}

void ProfileProtoBuilder::AddArtificialTrace(const string& name, int count,
    int sampling_rate) {
  perftools::profiles::Location *location = location_builder_.LocationFor(
      name, name, "", -1);

  auto profile = builder_.mutable_profile();
  auto sample = profile->add_sample();
  sample->add_location_id(location->id());
  // Move count * sampling rate to 64-bit.
  InitSampleValues(sample, count, static_cast<int64>(count) * sampling_rate);
}

void ProfileProtoBuilder::UnsampleMetrics() {
  auto profile = builder_.mutable_profile();

  for (int i = 0; i < profile->sample_size(); ++i) {
    auto sample = profile->mutable_sample(i);

    auto count = sample->value(kCount);
    auto metric_value = sample->value(kMetric);
    double ratio = CalculateSamplingRatio(sampling_rate_, count, metric_value);

    sample->set_value(kCount, static_cast<double>(count) * ratio);
    sample->set_value(kMetric, static_cast<double>(metric_value) * ratio);
  }
}

unique_ptr<perftools::profiles::Profile>
    ProfileProtoBuilder::CreateSampledProto() {
  builder_.Finalize();
  return unique_ptr<perftools::profiles::Profile>(builder_.Consume());
}

unique_ptr<perftools::profiles::Profile>
    ProfileProtoBuilder::CreateUnsampledProto() {
  UnsampleMetrics();
  builder_.Finalize();
  return unique_ptr<perftools::profiles::Profile>(builder_.Consume());
}

void ProfileProtoBuilder::AddSampleType(const SampleType &sample_type) {
  auto sample_type_proto = builder_.mutable_profile()->add_sample_type();
  sample_type_proto->set_type(builder_.StringId(sample_type.type.c_str()));
  sample_type_proto->set_unit(builder_.StringId(sample_type.unit.c_str()));
}

void ProfileProtoBuilder::SetPeriodType(const SampleType &metric_type) {
  auto period_type = builder_.mutable_profile()->mutable_period_type();
  period_type->set_type(builder_.StringId(metric_type.type.c_str()));
  period_type->set_unit(builder_.StringId(metric_type.unit.c_str()));
}

void ProfileProtoBuilder::UpdateSampleValues(
    perftools::profiles::Sample *sample, int64 count, int64 size) {
  sample->set_value(kCount, sample->value(kCount) + count);
  sample->set_value(kMetric, sample->value(kMetric) + size);
}

void ProfileProtoBuilder::InitSampleValues(
    perftools::profiles::Sample *sample, int64 metric) {
  InitSampleValues(sample, 1, metric);
}

void ProfileProtoBuilder::InitSampleValues(
    perftools::profiles::Sample *sample, int64 count, int64 metric) {
  sample->add_value(count);
  sample->add_value(metric);
}

void ProfileProtoBuilder::AddTrace(const ProfileStackTrace &trace,
                                   int32 count) {
  auto sample = trace_samples_.SampleFor(*trace.trace);

  if (sample != nullptr) {
    UpdateSampleValues(sample, count, trace.metric_value);
    return;
  }

  auto profile = builder_.mutable_profile();
  sample = profile->add_sample();

  trace_samples_.Add(*trace.trace, sample);

  InitSampleValues(sample, count, trace.metric_value);

  int first_frame = SkipTopNativeFrames(*trace.trace);

  StackState stack_state;

  for (int i = first_frame; i < trace.trace->num_frames; ++i) {
    auto &jvm_frame = trace.trace->frames[i];

    if (jvm_frame.lineno == kNativeFrameLineNum) {
      AddNativeInfo(jvm_frame, profile, sample, &stack_state);
    } else {
      AddJavaInfo(jvm_frame, profile, sample, &stack_state);
    }
  }
}

void ProfileProtoBuilder::AddJavaInfo(
    const JVMPI_CallFrame &jvm_frame,
    perftools::profiles::Profile *profile,
    perftools::profiles::Sample *sample,
    StackState *stack_state) {
  stack_state->JavaFrame();

  if (!jvm_frame.method_id) {
    perftools::profiles::Location *location = location_builder_.LocationFor(
        "", "[Unknown method]", "", 0);
    sample->add_location_id(location->id());
    return;
  }

  MethodInfo *method_info = Method(jvm_frame.method_id);
  sample->add_location_id(Location(method_info, jvm_frame));
}

int64 ProfileProtoBuilder::Location(MethodInfo *method,
                                       const JVMPI_CallFrame &frame) {
  // lineno is actually the BCI of the frame.
  int bci = frame.lineno;

  int64 location_id = method->Location(bci);

  // Non-zero as a location id is a valid location ID.
  if (location_id != MethodInfo::kInvalidLocationId) {
    return location_id;
  }

  int line_number = GetLineNumber(jvmti_env_, frame.method_id, bci);

  perftools::profiles::Location *location =
      location_builder_.LocationFor(method->ClassName(),
                                    method->MethodName(),
                                    method->FileName(),
                                    line_number);

  method->AddLocation(bci, location->id());
  return location->id();
}

MethodInfo *ProfileProtoBuilder::Method(jmethodID method_id) {
  auto it = methods_.find(method_id);
  if (it != methods_.end()) {
    return it->second.get();
  }

  string file_name;
  string class_name;
  string method_name;
  string signature;

  // Ignore lineno since we pass nullptr anyway.
  JVMPI_CallFrame jvm_frame = { 0, method_id };
  GetStackFrameElements(jni_env_, jvmti_env_, jvm_frame, &file_name,
                        &class_name, &method_name, &signature, nullptr);

  FixMethodParameters(&signature);
  string full_method_name = class_name + "." + method_name + signature;

  std::unique_ptr<MethodInfo> unique_method(
      new MethodInfo(full_method_name, class_name, file_name));

  auto method_ptr = unique_method.get();
  methods_[method_id] = std::move(unique_method);
  return method_ptr;
}

void ProfileProtoBuilder::AddNativeInfo(const JVMPI_CallFrame &jvm_frame,
                                        perftools::profiles::Profile *profile,
                                        perftools::profiles::Sample *sample,
                                        StackState *stack_state) {
  if (!native_cache_) {
    perftools::profiles::Location *location = location_builder_.LocationFor(
        "", "[Unknown non-Java frame]", "", 0);
    sample->add_location_id(location->id());
    return;
  }

  string function_name = native_cache_->GetFunctionName(jvm_frame);
  perftools::profiles::Location *location =
    native_cache_->GetLocation(jvm_frame,
                               &location_builder_);

  stack_state->NativeFrame(function_name);

  if (!stack_state->SkipFrame()) {
    location->set_address(reinterpret_cast<uint64>(jvm_frame.method_id));
    sample->add_location_id(location->id());
  }
}

void ContentionProfileProtoBuilder::MultiplyBySamplingRate() {
  auto profile = builder_.mutable_profile();

  for (int i = 0; i < profile->sample_size(); ++i) {
    auto sample = profile->mutable_sample(i);

    auto count = sample->value(kCount);
    auto metric_value = sample->value(kMetric);

    sample->set_value(kCount, static_cast<double>(count) * sampling_rate_);
    sample->set_value(kMetric,
                      static_cast<double>(metric_value) * sampling_rate_);
  }
}

size_t LocationBuilder::LocationInfoHash::operator()(
    const LocationInfo &info) const {

  unsigned int h = 1;

  hash<string> hash_string;
  hash<int> hash_int;

  h = 31U * h + hash_string(info.class_name);
  h = 31U * h + hash_string(info.function_name);
  h = 31U * h + hash_string(info.file_name);
  h = 31U * h + hash_int(info.line_number);

  return h;
}

bool LocationBuilder::LocationInfoEquals::operator()(
    const LocationInfo &info1, const LocationInfo &info2) const {
  return info1.class_name == info2.class_name &&
      info1.function_name == info2.function_name &&
      info1.file_name == info2.file_name &&
      info1.line_number == info2.line_number;
}

perftools::profiles::Location *LocationBuilder::LocationFor(
      const string &class_name,
      const string &function_name,
      const string &file_name,
      int line_number) {
  auto profile = builder_->mutable_profile();

  LocationInfo info{ class_name, function_name, file_name, line_number };

  if (locations_.count(info) > 0) {
    return locations_.find(info)->second;
  }

  auto location_id = profile->location_size() + 1;
  perftools::profiles::Location *location = profile->add_location();
  location->set_id(location_id);

  locations_[info] = location;

  auto line = location->add_line();

  string simplified_name = function_name;
  SimplifyFunctionName(&simplified_name);
  auto function_id = builder_->FunctionId(
      simplified_name.c_str(), function_name.c_str(), file_name.c_str(), 0);

  line->set_function_id(function_id);
  line->set_line(line_number);

  return location;
}

size_t TraceSamples::TraceHash::operator()(const JVMPI_CallTrace *trace) const {
  unsigned int h = 1;
  for (int f = 0; f < trace->num_frames; f++) {
    {
      int len = sizeof(jint);
      char *arr = reinterpret_cast<char *>(&trace->frames[f].lineno);
      for (int i = 0; i < len; i++) {
        h = 31U * h + arr[i];
      }
    }
    {
      int len = sizeof(jmethodID);
      char *arr = reinterpret_cast<char *>(&trace->frames[f].method_id);
      for (int i = 0; i < len; i++) {
        h = 31U * h + arr[i];
      }
    }
  }
  return h;
}

bool TraceSamples::TraceEquals::operator()(
    const JVMPI_CallTrace *trace1, const JVMPI_CallTrace *trace2) const {
  if (trace1->num_frames != trace2->num_frames) {
    return false;
  }

  for (int i = 0; i < trace1->num_frames; ++i) {
    if (trace1->frames[i].method_id != trace2->frames[i].method_id) {
      return false;
    }

    if (trace1->frames[i].lineno != trace2->frames[i].lineno) {
      return false;
    }
  }

  return true;
}

perftools::profiles::Sample *TraceSamples::SampleFor(
    const JVMPI_CallTrace &trace) const {
  auto found = traces_.find(&trace);
  if (found == traces_.end()) {
    return nullptr;
  }

  return found->second;
}

void TraceSamples::Add(const JVMPI_CallTrace &trace,
                       perftools::profiles::Sample *sample) {
  traces_[&trace] = sample;
}

double CalculateSamplingRatio(int64 rate, int64 count, int64 metric_value) {
  if (rate <= 1) {
    return 1.0;
  }

  if (count < 1) {
    return 1.0;
  }

  double m = static_cast<double>(metric_value);
  double c = static_cast<double>(count);
  double r = static_cast<double>(rate);

  double size = m / c;

  return 1 / (1 - exp(-size / r));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForHeap(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  // Cache can be nullptr because the heap sampler can be using a JVMTI
  // Java-only stackframe gatherer.
  return std::unique_ptr<ProfileProtoBuilder>(
      new HeapProfileProtoBuilder(jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForNativeHeap(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  assert(cache != nullptr);
  return std::unique_ptr<ProfileProtoBuilder>(new NativeHeapProfileProtoBuilder(
      jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForCpu(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  CHECK (cache != nullptr)
      << "CPU profiles may have native frames, cache must be provided";
  return std::unique_ptr<ProfileProtoBuilder>(
      new CpuProfileProtoBuilder(jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForContention(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  CHECK (cache != nullptr)
      << "Contention profiles may have native frames, cache must be provided";
  return std::unique_ptr<ProfileProtoBuilder>(new ContentionProfileProtoBuilder(
      jni_env, jvmti_env, sampling_rate, cache));
}

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

#include "third_party/javaprofiler/display.h"
#include "third_party/javaprofiler/stacktrace_fixer.h"
#include "third_party/javaprofiler/profile_proto_builder.h"

using std::unique_ptr;

namespace google {
namespace javaprofiler {

const int kCount = 0;
const int kMetric = 1;

ProfileProtoBuilder::ProfileProtoBuilder(JNIEnv *jni_env, jvmtiEnv *jvmti_env,
                                         ProfileFrameCache *native_cache,
                                         int64 sampling_rate,
                                         const SampleType &count_type,
                                         const SampleType &metric_type)
    : sampling_rate_(sampling_rate),
      jni_env_(jni_env),
      jvmti_env_(jvmti_env),
      native_cache_(native_cache),
      location_builder_(&builder_) {
  AddSampleType(count_type);
  AddSampleType(metric_type);
  SetPeriodType(metric_type);
}

void ProfileProtoBuilder::AddTraces(const ProfileStackTrace *traces,
                                    int num_traces) {
  if (native_cache_) {
    native_cache_->ProcessTraces(traces, num_traces);
  }

  for (int i = 0; i < num_traces; ++i) {
    AddTrace(traces[i], 1);
  }
}

void ProfileProtoBuilder::AddTraces(const ProfileStackTrace *traces,
                                    const int32 *counts,
                                    int num_traces) {
  if (native_cache_) {
    native_cache_->ProcessTraces(traces, num_traces);
  }

  for (int i = 0; i < num_traces; ++i) {
    AddTrace(traces[i], counts[i]);
  }
}

void ProfileProtoBuilder::AddArtificialTrace(const string& name, int count,
    int sampling_rate) {
  perftools::profiles::Location *location = location_builder_.LocationFor(
      name, name, "", -1);

  auto profile = builder_.mutable_profile();
  auto sample = profile->add_sample();
  sample->add_location_id(location->id());
  // Move count * sampling rate to 64-bit.
  InitSampleValues(sample, count, static_cast<int64>(count) * sampling_rate);
}

void ProfileProtoBuilder::UnsampleMetrics() {
  auto profile = builder_.mutable_profile();

  for (int i = 0; i < profile->sample_size(); ++i) {
    auto sample = profile->mutable_sample(i);

    auto count = sample->value(kCount);
    auto metric_value = sample->value(kMetric);
    double ratio = CalculateSamplingRatio(sampling_rate_, count, metric_value);

    sample->set_value(kCount, static_cast<double>(count) * ratio);
    sample->set_value(kMetric, static_cast<double>(metric_value) * ratio);
  }
}

unique_ptr<perftools::profiles::Profile>
    ProfileProtoBuilder::CreateSampledProto() {
  builder_.Finalize();
  return unique_ptr<perftools::profiles::Profile>(builder_.Consume());
}

unique_ptr<perftools::profiles::Profile>
    ProfileProtoBuilder::CreateUnsampledProto() {
  UnsampleMetrics();
  builder_.Finalize();
  return unique_ptr<perftools::profiles::Profile>(builder_.Consume());
}

void ProfileProtoBuilder::AddSampleType(const SampleType &sample_type) {
  auto sample_type_proto = builder_.mutable_profile()->add_sample_type();
  sample_type_proto->set_type(builder_.StringId(sample_type.type.c_str()));
  sample_type_proto->set_unit(builder_.StringId(sample_type.unit.c_str()));
}

void ProfileProtoBuilder::SetPeriodType(const SampleType &metric_type) {
  auto period_type = builder_.mutable_profile()->mutable_period_type();
  period_type->set_type(builder_.StringId(metric_type.type.c_str()));
  period_type->set_unit(builder_.StringId(metric_type.unit.c_str()));
}

void ProfileProtoBuilder::UpdateSampleValues(
    perftools::profiles::Sample *sample, int64 count, int64 size) {
  sample->set_value(kCount, sample->value(kCount) + count);
  sample->set_value(kMetric, sample->value(kMetric) + size);
}

void ProfileProtoBuilder::InitSampleValues(
    perftools::profiles::Sample *sample, int64 metric) {
  InitSampleValues(sample, 1, metric);
}

void ProfileProtoBuilder::InitSampleValues(
    perftools::profiles::Sample *sample, int64 count, int64 metric) {
  sample->add_value(count);
  sample->add_value(metric);
}

void ProfileProtoBuilder::AddTrace(const ProfileStackTrace &trace,
                                   int32 count) {
  auto sample = trace_samples_.SampleFor(*trace.trace);

  if (sample != nullptr) {
    UpdateSampleValues(sample, count, trace.metric_value);
    return;
  }

  auto profile = builder_.mutable_profile();
  sample = profile->add_sample();

  trace_samples_.Add(*trace.trace, sample);

  InitSampleValues(sample, count, trace.metric_value);

  int first_frame = SkipTopNativeFrames(*trace.trace);

  StackState stack_state;

  for (int i = first_frame; i < trace.trace->num_frames; ++i) {
    auto &jvm_frame = trace.trace->frames[i];

    if (jvm_frame.lineno == kNativeFrameLineNum) {
      AddNativeInfo(jvm_frame, profile, sample, &stack_state);
    } else {
      AddJavaInfo(jvm_frame, profile, sample, &stack_state);
    }
  }
}

void ProfileProtoBuilder::AddJavaInfo(
    const JVMPI_CallFrame &jvm_frame,
    perftools::profiles::Profile *profile,
    perftools::profiles::Sample *sample,
    StackState *stack_state) {
  stack_state->JavaFrame();

  if (!jvm_frame.method_id) {
    perftools::profiles::Location *location = location_builder_.LocationFor(
        "", "[Unknown method]", "", 0);
    sample->add_location_id(location->id());
    return;
  }

  MethodInfo *method_info = Method(jvm_frame.method_id);
  sample->add_location_id(Location(method_info, jvm_frame));
}

int64 ProfileProtoBuilder::Location(MethodInfo *method,
                                       const JVMPI_CallFrame &frame) {
  // lineno is actually the BCI of the frame.
  int bci = frame.lineno;

  int64 location_id = method->Location(bci);

  // Non-zero as a location id is a valid location ID.
  if (location_id != MethodInfo::kInvalidLocationId) {
    return location_id;
  }

  int line_number = GetLineNumber(jvmti_env_, frame.method_id, bci);

  perftools::profiles::Location *location =
      location_builder_.LocationFor(method->ClassName(),
                                    method->MethodName(),
                                    method->FileName(),
                                    line_number);

  method->AddLocation(bci, location->id());
  return location->id();
}

MethodInfo *ProfileProtoBuilder::Method(jmethodID method_id) {
  auto it = methods_.find(method_id);
  if (it != methods_.end()) {
    return it->second.get();
  }

  string file_name;
  string class_name;
  string method_name;
  string signature;

  // Ignore lineno since we pass nullptr anyway.
  JVMPI_CallFrame jvm_frame = { 0, method_id };
  GetStackFrameElements(jni_env_, jvmti_env_, jvm_frame, &file_name,
                        &class_name, &method_name, &signature, nullptr);

  FixMethodParameters(&signature);
  string full_method_name = class_name + "." + method_name + signature;

  std::unique_ptr<MethodInfo> unique_method(
      new MethodInfo(full_method_name, class_name, file_name));

  auto method_ptr = unique_method.get();
  methods_[method_id] = std::move(unique_method);
  return method_ptr;
}

void ProfileProtoBuilder::AddNativeInfo(const JVMPI_CallFrame &jvm_frame,
                                        perftools::profiles::Profile *profile,
                                        perftools::profiles::Sample *sample,
                                        StackState *stack_state) {
  if (!native_cache_) {
    perftools::profiles::Location *location = location_builder_.LocationFor(
        "", "[Unknown non-Java frame]", "", 0);
    sample->add_location_id(location->id());
    return;
  }

  string function_name = native_cache_->GetFunctionName(jvm_frame);
  perftools::profiles::Location *location =
    native_cache_->GetLocation(jvm_frame,
                               &location_builder_);

  stack_state->NativeFrame(function_name);

  if (!stack_state->SkipFrame()) {
    location->set_address(reinterpret_cast<uint64>(jvm_frame.method_id));
    sample->add_location_id(location->id());
  }
}

void ContentionProfileProtoBuilder::MultiplyBySamplingRate() {
  auto profile = builder_.mutable_profile();

  for (int i = 0; i < profile->sample_size(); ++i) {
    auto sample = profile->mutable_sample(i);

    auto count = sample->value(kCount);
    auto metric_value = sample->value(kMetric);

    sample->set_value(kCount, static_cast<double>(count) * sampling_rate_);
    sample->set_value(kMetric,
                      static_cast<double>(metric_value) * sampling_rate_);
  }
}

size_t LocationBuilder::LocationInfoHash::operator()(
    const LocationInfo &info) const {

  unsigned int h = 1;

  hash<string> hash_string;
  hash<int> hash_int;

  h = 31U * h + hash_string(info.class_name);
  h = 31U * h + hash_string(info.function_name);
  h = 31U * h + hash_string(info.file_name);
  h = 31U * h + hash_int(info.line_number);

  return h;
}

bool LocationBuilder::LocationInfoEquals::operator()(
    const LocationInfo &info1, const LocationInfo &info2) const {
  return info1.class_name == info2.class_name &&
      info1.function_name == info2.function_name &&
      info1.file_name == info2.file_name &&
      info1.line_number == info2.line_number;
}

perftools::profiles::Location *LocationBuilder::LocationFor(
      const string &class_name,
      const string &function_name,
      const string &file_name,
      int line_number) {
  auto profile = builder_->mutable_profile();

  LocationInfo info{ class_name, function_name, file_name, line_number };

  if (locations_.count(info) > 0) {
    return locations_.find(info)->second;
  }

  auto location_id = profile->location_size() + 1;
  perftools::profiles::Location *location = profile->add_location();
  location->set_id(location_id);

  locations_[info] = location;

  auto line = location->add_line();

  string simplified_name = function_name;
  SimplifyFunctionName(&simplified_name);
  auto function_id = builder_->FunctionId(
      simplified_name.c_str(), function_name.c_str(), file_name.c_str(), 0);

  line->set_function_id(function_id);
  line->set_line(line_number);

  return location;
}

size_t TraceSamples::TraceHash::operator()(const JVMPI_CallTrace *trace) const {
  unsigned int h = 1;
  for (int f = 0; f < trace->num_frames; f++) {
    {
      int len = sizeof(jint);
      char *arr = reinterpret_cast<char *>(&trace->frames[f].lineno);
      for (int i = 0; i < len; i++) {
        h = 31U * h + arr[i];
      }
    }
    {
      int len = sizeof(jmethodID);
      char *arr = reinterpret_cast<char *>(&trace->frames[f].method_id);
      for (int i = 0; i < len; i++) {
        h = 31U * h + arr[i];
      }
    }
  }
  return h;
}

bool TraceSamples::TraceEquals::operator()(
    const JVMPI_CallTrace *trace1, const JVMPI_CallTrace *trace2) const {
  if (trace1->num_frames != trace2->num_frames) {
    return false;
  }

  for (int i = 0; i < trace1->num_frames; ++i) {
    if (trace1->frames[i].method_id != trace2->frames[i].method_id) {
      return false;
    }

    if (trace1->frames[i].lineno != trace2->frames[i].lineno) {
      return false;
    }
  }

  return true;
}

perftools::profiles::Sample *TraceSamples::SampleFor(
    const JVMPI_CallTrace &trace) const {
  auto found = traces_.find(&trace);
  if (found == traces_.end()) {
    return nullptr;
  }

  return found->second;
}

void TraceSamples::Add(const JVMPI_CallTrace &trace,
                       perftools::profiles::Sample *sample) {
  traces_[&trace] = sample;
}

double CalculateSamplingRatio(int64 rate, int64 count, int64 metric_value) {
  if (rate <= 1 || count < 1 || metric_value < 1) {
    return 1.0;
  }

  double m = static_cast<double>(metric_value);
  double c = static_cast<double>(count);
  double r = static_cast<double>(rate);

  double size = m / c;

  return 1 / (1 - exp(-size / r));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForHeap(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  // Cache can be nullptr because the heap sampler can be using a JVMTI
  // Java-only stackframe gatherer.
  return std::unique_ptr<ProfileProtoBuilder>(
      new HeapProfileProtoBuilder(jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForNativeHeap(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  assert(cache != nullptr);
  return std::unique_ptr<ProfileProtoBuilder>(new NativeHeapProfileProtoBuilder(
      jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForCpu(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  CHECK (cache != nullptr)
      << "CPU profiles may have native frames, cache must be provided";
  return std::unique_ptr<ProfileProtoBuilder>(
      new CpuProfileProtoBuilder(jni_env, jvmti_env, sampling_rate, cache));
}

std::unique_ptr<ProfileProtoBuilder> ProfileProtoBuilder::ForContention(
    JNIEnv *jni_env, jvmtiEnv *jvmti_env, int64 sampling_rate,
    ProfileFrameCache *cache) {
  CHECK (cache != nullptr)
      << "Contention profiles may have native frames, cache must be provided";
  return std::unique_ptr<ProfileProtoBuilder>(new ContentionProfileProtoBuilder(
      jni_env, jvmti_env, sampling_rate, cache));
}

}  // namespace javaprofiler
}  // namespace google
<|endoftext|>


<commit_before>#include "http_server.h"

#include "evpp/libevent.h"
#include "evpp/event_watcher.h"
#include "evpp/event_loop.h"
#include "evpp/event_loop_thread.h"
#include "evpp/event_loop_thread_pool.h"
#include "evpp/utility.h"

#include <future>

namespace evpp {
namespace http {

Server::Server(uint32_t thread_num) {
    DLOG_TRACE;
    tpool_.reset(new EventLoopThreadPool(nullptr, thread_num));
}

Server::~Server() {
    DLOG_TRACE;
    if (!listen_threads_.empty()) {
        for (auto& lt : listen_threads_) {
            lt.thread->Join();
        }
        listen_threads_.clear();
    }

    if (tpool_) {
        assert(tpool_->IsStopped());
        tpool_->Join();
        tpool_.reset();
    }
}

bool Server::Init(int listen_port) {
    status_.store(kInitializing);
    ListenThread lt;
    lt.thread = std::make_shared<EventLoopThread>();
    lt.thread->set_name(std::string("StandaloneHTTPServer-Main-") + std::to_string(listen_port));

    lt.hservice = std::make_shared<Service>(lt.thread->loop());
    if (!lt.hservice->Listen(listen_port)) {
        int serrno = errno;
        LOG_ERROR << "this=" << this << " http server listen at port " << listen_port << " failed. errno=" << serrno << " " << strerror(serrno);
        lt.hservice->Stop();
        return false;
    }
    listen_threads_.push_back(lt);
    status_.store(kInitialized);
    return true;
}

bool Server::Init(const std::vector<int>& listen_ports) {
    status_.store(kInitializing);
    bool rc = true;
    for (auto lp : listen_ports) {
        rc = rc && Init(lp);
    }
    if (rc) {
        status_.store(kInitialized);
    } else {
        status_.store(kInitializing);
    }
    return rc;
}

bool Server::Init(const std::string& listen_ports/*"80,8080,443"*/) {
    status_.store(kInitializing);
    std::vector<std::string> vec;
    StringSplit(listen_ports, ",", 0, vec);

    std::vector<int> v;
    for (auto& s : vec) {
        int i = std::atoi(s.c_str());
        if (i <= 0) {
            LOG_ERROR << "this=" << this << " Cannot convert [" << s << "] to a integer. 'listen_ports' format wrong.";
            return false;
        }
        v.push_back(i);
    }

    auto rc = Init(v);
    if (rc) {
        status_.store(kInitialized);
    } else {
        status_.store(kInitializing);
    }
    return rc;
}

void Server::AfterFork() {
    for (auto& lt : listen_threads_) {
        lt.thread->loop()->AfterFork();
    }
    tpool_->AfterFork();
}

bool Server::Start() {
    assert(status_.load() == kInitialized);
    status_.store(kStarting);
    bool rc = tpool_->Start(true);
    if (!rc) {
        LOG_ERROR << "this=" << this << " start thread pool failed.";
        return false;
    }

    for (auto& lt : listen_threads_) {
        auto& hservice = lt.hservice;
        auto& lthread = lt.thread;
        auto http_close_fn = [hservice, this]() {
            hservice->Stop();
            DLOG_TRACE << "http service at 0.0.0.0:" << hservice->port() << " has stopped.";
            return EventLoopThread::kOK;
        };
        rc = lthread->Start(true,
                            EventLoopThread::Functor(),
                            http_close_fn);
        if (!rc) {
            LOG_ERROR << "this=" << this << " start listening thread failed.";
            return false;
        }

        using namespace std::placeholders;
        assert(lthread->IsRunning());
        for (auto& c : callbacks_) {
            auto cb = std::bind(&Server::Dispatch, this, _1, _2, _3, c.second);
            hservice->RegisterHandler(c.first, cb);
        }
        auto cb = std::bind(&Server::Dispatch, this, _1, _2, _3, default_callback_);
        hservice->RegisterDefaultHandler(cb);
    }

    assert(rc);

    auto is_running = [this]() {
        if (listen_threads_.empty()) {
            return false;
        }

        if (!tpool_->IsRunning()) {
            return false;
        }

        for (auto& lt : listen_threads_) {
            if (!lt.thread->IsRunning()) {
                return false;
            }
        }
        return true;
    };

    while (!is_running()) {
        usleep(1);
    }
    DLOG_TRACE << "http server is running" ;
    status_.store(kRunning);
    return true;
}

void Server::Stop() {
    assert(IsRunning());
    DLOG_TRACE << "http server is stopping";

    status_.store(kStopping);

    std::promise<void> promise;
    std::atomic<int> count(0);

    // Firstly we pause all the listening threads to accept new requests.
    substatus_.store(kStoppingListener);
    for (auto& lt : listen_threads_) {
        std::shared_ptr<Service>& hs = lt.hservice;
        auto fn = [&count, &promise, this, hs]() {
            hs->Pause();
            if (count.fetch_add(1) + 1 == static_cast<int>(listen_threads_.size())) {
                promise.set_value();
            }
        };
        lt.thread->loop()->RunInLoop(fn);
    }
    promise.get_future().wait();

    // Secondly we stop thread pool
    substatus_.store(kStoppingThreadPool);
    tpool_->Stop(true);

    // Thirdly we stop the listening threads
    for (auto& lt : listen_threads_) {
        // Service::Stop will be called automatically when listen_thread_ is existing
        lt.thread->Stop(true);
    }

    status_.store(kStopped);

    // Lastly
    // Make sure all the working threads totally stopped.
    tpool_->Join();
    tpool_.reset();

    // Make sure all the listening threads totally stopped.
    for (auto& lt : listen_threads_) {
        lt.thread->Join();
    }
    listen_threads_.clear();

    DLOG_TRACE << "http server stopped";
}

void Server::Pause() {
    DLOG_TRACE << "http server pause";
    for (auto& lt : listen_threads_) {
        EventLoop* loop = lt.thread->loop();
        std::shared_ptr<Service>& hs = lt.hservice;
        auto f = [hs]() {
            hs->Pause();
        };
        loop->RunInLoop(f);
    }
}

void Server::Continue() {
    DLOG_TRACE << "http server continue";
    for (auto& lt : listen_threads_) {
        EventLoop* loop = lt.thread->loop();
        std::shared_ptr<Service>& hs = lt.hservice;
        auto f = [hs]() {
            hs->Continue();
        };
        loop->RunInLoop(f);
    }
}

void Server::RegisterHandler(const std::string& uri, HTTPRequestCallback callback) {
    assert(!IsRunning());
    callbacks_[uri] = callback;
}

void Server::RegisterDefaultHandler(HTTPRequestCallback callback) {
    assert(!IsRunning());
    default_callback_ = callback;
}

void Server::Dispatch(EventLoop* listening_loop,
                      const ContextPtr& ctx,
                      const HTTPSendResponseCallback& response_callback,
                      const HTTPRequestCallback& user_callback) {
    // Make sure it is running in the HTTP listening thread
    assert(listening_loop->IsInLoopThread());
    DLOG_TRACE << "dispatch request " << ctx->req() << " url=" << ctx->original_uri() << " in main thread. status=" << StatusToString();
    if (!IsRunning()) {
        LOG_WARN << "The listening thread is not running, may be it is stopping now.";
        //TODO gracefully shutdown.
        return;
    }

    EventLoop* loop = nullptr;
    loop = GetNextLoop(listening_loop, ctx);

    // Forward this HTTP request to a worker thread to process
    auto f = [loop, ctx, response_callback, user_callback, this]() {
        DLOG_TRACE << "process request " << ctx->req()
            << " url=" << ctx->original_uri()
            << " in working thread. status=" << StatusToString();

        if (!IsRunning()) {
            LOG_WARN << "The listening thread is not running, may be it is stopping now.";
            //TODO gracefully shutdown.
            return;
        }

        // This is in the worker thread.
        // Invoke user layer handler to process this HTTP process.
        // After the user layer finished processing,
        // the user layer has responsibility to invoke response_cb
        // to send the result back to framework,
        // that actually comes back to Service::SendReply method.
        assert(loop->IsInLoopThread());
        user_callback(loop, ctx, response_callback);
    };

    loop->RunInLoop(f);
}

EventLoop* Server::GetNextLoop(EventLoop* default_loop, const ContextPtr& ctx) {
    if (tpool_->thread_num() == 0) {
        return default_loop;
    }

    if (IsRoundRobin()) {
        return tpool_->GetNextLoop();
    }

#if LIBEVENT_VERSION_NUMBER >= 0x02010500
    const sockaddr*  sa = evhttp_connection_get_addr(ctx->req()->evcon);
    if (sa) {
        const sockaddr_in* r = sock::sockaddr_in_cast(sa);
        LOG_INFO << "http remote address " << sock::ToIPPort(r);
        return tpool_->GetNextLoopWithHash(r->sin_addr.s_addr);
    } else {
        uint64_t hash = std::hash<std::string>()(ctx->remote_ip());
        return tpool_->GetNextLoopWithHash(hash);
    }
#else
    uint64_t hash = std::hash<std::string>()(ctx->remote_ip());
    return tpool_->GetNextLoopWithHash(hash);
#endif
}

Service* Server::service(int index) const {
    if (index < int(listen_threads_.size())) {
        return listen_threads_[index].hservice.get();
    }

    return nullptr;
}
}
}
<commit_msg>Fix bug : http server crash when no registering default handler. See https://github.com/Qihoo360/evpp/issues/113<commit_after>#include "http_server.h"

#include "evpp/libevent.h"
#include "evpp/event_watcher.h"
#include "evpp/event_loop.h"
#include "evpp/event_loop_thread.h"
#include "evpp/event_loop_thread_pool.h"
#include "evpp/utility.h"

#include <future>

namespace evpp {
namespace http {

Server::Server(uint32_t thread_num) {
    DLOG_TRACE;
    tpool_.reset(new EventLoopThreadPool(nullptr, thread_num));
}

Server::~Server() {
    DLOG_TRACE;
    if (!listen_threads_.empty()) {
        for (auto& lt : listen_threads_) {
            lt.thread->Join();
        }
        listen_threads_.clear();
    }

    if (tpool_) {
        assert(tpool_->IsStopped());
        tpool_->Join();
        tpool_.reset();
    }
}

bool Server::Init(int listen_port) {
    status_.store(kInitializing);
    ListenThread lt;
    lt.thread = std::make_shared<EventLoopThread>();
    lt.thread->set_name(std::string("StandaloneHTTPServer-Main-") + std::to_string(listen_port));

    lt.hservice = std::make_shared<Service>(lt.thread->loop());
    if (!lt.hservice->Listen(listen_port)) {
        int serrno = errno;
        LOG_ERROR << "this=" << this << " http server listen at port " << listen_port << " failed. errno=" << serrno << " " << strerror(serrno);
        lt.hservice->Stop();
        return false;
    }
    listen_threads_.push_back(lt);
    status_.store(kInitialized);
    return true;
}

bool Server::Init(const std::vector<int>& listen_ports) {
    status_.store(kInitializing);
    bool rc = true;
    for (auto lp : listen_ports) {
        rc = rc && Init(lp);
    }
    if (rc) {
        status_.store(kInitialized);
    } else {
        status_.store(kInitializing);
    }
    return rc;
}

bool Server::Init(const std::string& listen_ports/*"80,8080,443"*/) {
    status_.store(kInitializing);
    std::vector<std::string> vec;
    StringSplit(listen_ports, ",", 0, vec);

    std::vector<int> v;
    for (auto& s : vec) {
        int i = std::atoi(s.c_str());
        if (i <= 0) {
            LOG_ERROR << "this=" << this << " Cannot convert [" << s << "] to a integer. 'listen_ports' format wrong.";
            return false;
        }
        v.push_back(i);
    }

    auto rc = Init(v);
    if (rc) {
        status_.store(kInitialized);
    } else {
        status_.store(kInitializing);
    }
    return rc;
}

void Server::AfterFork() {
    for (auto& lt : listen_threads_) {
        lt.thread->loop()->AfterFork();
    }
    tpool_->AfterFork();
}

bool Server::Start() {
    assert(status_.load() == kInitialized);
    status_.store(kStarting);
    bool rc = tpool_->Start(true);
    if (!rc) {
        LOG_ERROR << "this=" << this << " start thread pool failed.";
        return false;
    }

    for (auto& lt : listen_threads_) {
        auto& hservice = lt.hservice;
        auto& lthread = lt.thread;
        auto http_close_fn = [hservice, this]() {
            hservice->Stop();
            DLOG_TRACE << "http service at 0.0.0.0:" << hservice->port() << " has stopped.";
            return EventLoopThread::kOK;
        };
        rc = lthread->Start(true,
                            EventLoopThread::Functor(),
                            http_close_fn);
        if (!rc) {
            LOG_ERROR << "this=" << this << " start listening thread failed.";
            return false;
        }

        using namespace std::placeholders;
        assert(lthread->IsRunning());
        for (auto& c : callbacks_) {
            auto cb = std::bind(&Server::Dispatch, this, _1, _2, _3, c.second);
            hservice->RegisterHandler(c.first, cb);
        }

        if (default_callback_) {
            auto cb = std::bind(&Server::Dispatch, this, _1, _2, _3, default_callback_);
            hservice->RegisterDefaultHandler(cb);
        }
    }

    assert(rc);

    auto is_running = [this]() {
        if (listen_threads_.empty()) {
            return false;
        }

        if (!tpool_->IsRunning()) {
            return false;
        }

        for (auto& lt : listen_threads_) {
            if (!lt.thread->IsRunning()) {
                return false;
            }
        }
        return true;
    };

    while (!is_running()) {
        usleep(1);
    }
    DLOG_TRACE << "http server is running" ;
    status_.store(kRunning);
    return true;
}

void Server::Stop() {
    assert(IsRunning());
    DLOG_TRACE << "http server is stopping";

    status_.store(kStopping);

    std::promise<void> promise;
    std::atomic<int> count(0);

    // Firstly we pause all the listening threads to accept new requests.
    substatus_.store(kStoppingListener);
    for (auto& lt : listen_threads_) {
        std::shared_ptr<Service>& hs = lt.hservice;
        auto fn = [&count, &promise, this, hs]() {
            hs->Pause();
            if (count.fetch_add(1) + 1 == static_cast<int>(listen_threads_.size())) {
                promise.set_value();
            }
        };
        lt.thread->loop()->RunInLoop(fn);
    }
    promise.get_future().wait();

    // Secondly we stop thread pool
    substatus_.store(kStoppingThreadPool);
    tpool_->Stop(true);

    // Thirdly we stop the listening threads
    for (auto& lt : listen_threads_) {
        // Service::Stop will be called automatically when listen_thread_ is existing
        lt.thread->Stop(true);
    }

    status_.store(kStopped);

    // Lastly
    // Make sure all the working threads totally stopped.
    tpool_->Join();
    tpool_.reset();

    // Make sure all the listening threads totally stopped.
    for (auto& lt : listen_threads_) {
        lt.thread->Join();
    }
    listen_threads_.clear();

    DLOG_TRACE << "http server stopped";
}

void Server::Pause() {
    DLOG_TRACE << "http server pause";
    for (auto& lt : listen_threads_) {
        EventLoop* loop = lt.thread->loop();
        std::shared_ptr<Service>& hs = lt.hservice;
        auto f = [hs]() {
            hs->Pause();
        };
        loop->RunInLoop(f);
    }
}

void Server::Continue() {
    DLOG_TRACE << "http server continue";
    for (auto& lt : listen_threads_) {
        EventLoop* loop = lt.thread->loop();
        std::shared_ptr<Service>& hs = lt.hservice;
        auto f = [hs]() {
            hs->Continue();
        };
        loop->RunInLoop(f);
    }
}

void Server::RegisterHandler(const std::string& uri, HTTPRequestCallback callback) {
    assert(!IsRunning());
    callbacks_[uri] = callback;
}

void Server::RegisterDefaultHandler(HTTPRequestCallback callback) {
    assert(!IsRunning());
    default_callback_ = callback;
}

void Server::Dispatch(EventLoop* listening_loop,
                      const ContextPtr& ctx,
                      const HTTPSendResponseCallback& response_callback,
                      const HTTPRequestCallback& user_callback) {
    // Make sure it is running in the HTTP listening thread
    assert(listening_loop->IsInLoopThread());
    DLOG_TRACE << "dispatch request " << ctx->req() << " url=" << ctx->original_uri() << " in main thread. status=" << StatusToString();
    if (!IsRunning()) {
        LOG_WARN << "The listening thread is not running, may be it is stopping now.";
        //TODO gracefully shutdown.
        return;
    }

    EventLoop* loop = nullptr;
    loop = GetNextLoop(listening_loop, ctx);

    // Forward this HTTP request to a worker thread to process
    auto f = [loop, ctx, response_callback, user_callback, this]() {
        DLOG_TRACE << "process request " << ctx->req()
            << " url=" << ctx->original_uri()
            << " in working thread. status=" << StatusToString();

        if (!IsRunning()) {
            LOG_WARN << "The listening thread is not running, may be it is stopping now.";
            //TODO gracefully shutdown.
            return;
        }

        // This is in the worker thread.
        // Invoke user layer handler to process this HTTP process.
        // After the user layer finished processing,
        // the user layer has responsibility to invoke response_cb
        // to send the result back to framework,
        // that actually comes back to Service::SendReply method.
        assert(loop->IsInLoopThread());
        user_callback(loop, ctx, response_callback);
    };

    loop->RunInLoop(f);
}

EventLoop* Server::GetNextLoop(EventLoop* default_loop, const ContextPtr& ctx) {
    if (tpool_->thread_num() == 0) {
        return default_loop;
    }

    if (IsRoundRobin()) {
        return tpool_->GetNextLoop();
    }

#if LIBEVENT_VERSION_NUMBER >= 0x02010500
    const sockaddr*  sa = evhttp_connection_get_addr(ctx->req()->evcon);
    if (sa) {
        const sockaddr_in* r = sock::sockaddr_in_cast(sa);
        LOG_INFO << "http remote address " << sock::ToIPPort(r);
        return tpool_->GetNextLoopWithHash(r->sin_addr.s_addr);
    } else {
        uint64_t hash = std::hash<std::string>()(ctx->remote_ip());
        return tpool_->GetNextLoopWithHash(hash);
    }
#else
    uint64_t hash = std::hash<std::string>()(ctx->remote_ip());
    return tpool_->GetNextLoopWithHash(hash);
#endif
}

Service* Server::service(int index) const {
    if (index < int(listen_threads_.size())) {
        return listen_threads_[index].hservice.get();
    }

    return nullptr;
}
}
}
<|endoftext|>


<commit_before><commit_msg>add pcmphos low b rbin cut pp 13 tev<commit_after><|endoftext|>


<commit_before>Bool_t ConfigPhiLeadingPb(
 AliRsnMiniAnalysisTask *task,
 Bool_t isMC = kFALSE,
 Bool_t isPP = kFALSE,
 Double_t nSigmaPart1TPC = -1,
 Double_t nSigmaPart2TPC = -1,
 Double_t nSigmaPart1TOF = -1,
 Double_t nSigmaPart2TOF = -1,
 Int_t                   customQualityCutsID=AliRsnCutSetDaughterParticle::kDisableCustom,
 Int_t                    aodFilterBit=0
 )
{
    // -- Values ------------------------------------------------------------------------------------
    /* invariant mass   */ Int_t imID = task->CreateValue(AliRsnMiniValue::kInvMass, kFALSE);
    /* transv. momentum */ Int_t ptID = task->CreateValue(AliRsnMiniValue::kPt, kFALSE);
    /* angel to leading */ Int_t alID = task->CreateValue(AliRsnMiniValue::kAngleLeading, kFALSE);
    /* pt of leading    */ Int_t ptlID = task->CreateValue(AliRsnMiniValue::kLeadingPt, kFALSE);
    /* multiplicity     */ Int_t multID = task->CreateValue(AliRsnMiniValue::kMult,kFALSE);
    /* delta eta        */ Int_t detaID  = task->CreateValue(AliRsnMiniValue::kDeltaEta, kFALSE);
   /* phi of leading    */ Int_t philID = task->CreateValue(AliRsnMiniValue::kLeadingPhi, kFALSE);
   /* phi angle         */ Int_t phiID = task->CreateValue(AliRsnMiniValue::kPhi, kFALSE);

  // Cuts
   AliRsnCutSetDaughterParticle* cutSetK;
   AliRsnCutSetDaughterParticle::ERsnDaughterCutSet cutPiCandidate = AliRsnCutSetDaughterParticle::kTPCpidTOFveto3s;

  AliRsnCutTrackQuality* trkQualityCut= new AliRsnCutTrackQuality("myQualityCut");
  trkQualityCut->SetDefaults2011(kTRUE,kTRUE);

  cout<<"Value of custom quality--------------------"<<customQualityCutsID<<endl;

            if(customQualityCutsID==3){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexXYPtDep("0.0150+0.0500/pt^1.1");}
            else if(customQualityCutsID==4){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexXYPtDep("0.006+0.0200/pt^1.1");}
            else if(customQualityCutsID==5){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(3.);}
            else if(customQualityCutsID==6){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(0.2);}
            else if(customQualityCutsID==7){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterTPC(5.);}
            else if(customQualityCutsID==8){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterTPC(3.);}
            else if(customQualityCutsID==9){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(60);}
            else if(customQualityCutsID==10){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(100);}
            else if(customQualityCutsID==11){trkQualityCut->GetESDtrackCuts()->SetMinRatioCrossedRowsOverFindableClustersTPC(0.7);}
            else if(customQualityCutsID==12){trkQualityCut->GetESDtrackCuts()->SetMinRatioCrossedRowsOverFindableClustersTPC(0.9);}
            else if(customQualityCutsID==13){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(49.);}
            else if(customQualityCutsID==14){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(4.);}
            else if(customQualityCutsID==15){trkQualityCut->GetESDtrackCuts()->SetMaxChi2TPCConstrainedGlobal(49.);}
            else if(customQualityCutsID==16){trkQualityCut->GetESDtrackCuts()->SetMaxChi2TPCConstrainedGlobal(25.);}
            else if(customQualityCutsID==17){trkQualityCut->GetESDtrackCuts()->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kOff);}
            else if(customQualityCutsID==56){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(1.);}
            else if(customQualityCutsID==60){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(80);}
            else if(customQualityCutsID==64){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(25.);}

    cutSetK=new AliRsnCutSetDaughterParticle(Form("cutK%i_%2.1fsigma_%2.1fsigmaTOF",cutPiCandidate, nSigmaPart2TPC,nSigmaPart2TOF),trkQualityCut,cutPiCandidate,AliPID::kKaon,nSigmaPart2TPC,nSigmaPart2TOF);

  Int_t iCutK  = task->AddTrackCuts(cutSetK);

    // Defining output objects
    const Int_t dims = 6;
    Int_t useIM[dims] = {1, 1, 0, 0, isMC, isMC};
    TString name[dims] = {"Unlike", "Mixing", "LikePP", "LikeMM", "True", "Mother"};
    TString comp[dims] = {"PAIR", "MIX", "PAIR", "PAIR", "TRUE", "MOTHER"};
    TString output[dims] = {"SPARSE", "SPARSE", "SPARSE", "SPARSE", "SPARSE", "SPARSE"};
    Char_t charge1[dims] = {'+', '+', '+', '-', '+', '+'};
    Char_t charge2[dims] = {'-', '-', '+', '-', '-', '-'};
    Int_t pdgCode[dims] = {333, 333, 333, 333, 333, 333};
    Double_t motherMass[dims] = {1.019461, 1.019461, 1.019461, 1.019461, 1.019461, 1.019461};

    for (Int_t i = 0; i < dims; i++)
    {
        if (!useIM[i])
            continue;
        AliRsnMiniOutput *out = task->CreateOutput(name[i].Data(), output[i].Data(), comp[i].Data());
        out->SetCutID(0, iCutK);
        out->SetCutID(1, iCutK);
        out->SetDaughter(0, AliRsnDaughter::kKaon);
        out->SetDaughter(1, AliRsnDaughter::kKaon);
        out->SetCharge(0, charge1[i]);
        out->SetCharge(1, charge2[i]);
        out->SetMotherPDG(pdgCode[i]);
        out->SetMotherMass(motherMass[i]);

        out->AddAxis(imID, 95, 0.985, 1.08);
        out->AddAxis(ptID, 10, 0., 10.);
        if(!isPP ) out->AddAxis(multID,10,0.,100.);
        else out->AddAxis(multID, 10, 0., 100.);

       out->AddAxis(alID, 36, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());
        out->AddAxis(ptlID, 15, 0., 30.);
         out->AddAxis(detaID, 16, -1.6, 1.6);
       // out->AddAxis(philID, 18, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());
       // out->AddAxis(phiID, 18, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());

    }
    return kTRUE;
}

<commit_msg>Update ConfigPhiLeadingPb.C<commit_after>Bool_t ConfigPhiLeadingPb(
 AliRsnMiniAnalysisTask *task,
 Bool_t isMC = kFALSE,
 Bool_t isPP = kFALSE,
 Double_t nSigmaPart1TPC = -1,
 Double_t nSigmaPart2TPC = -1,
 Double_t nSigmaPart1TOF = -1,
 Double_t nSigmaPart2TOF = -1,
 Int_t                   customQualityCutsID=AliRsnCutSetDaughterParticle::kDisableCustom,
 Int_t                    aodFilterBit=0
 )
{
    // -- Values ------------------------------------------------------------------------------------
    /* invariant mass   */ Int_t imID = task->CreateValue(AliRsnMiniValue::kInvMass, kFALSE);
    /* transv. momentum */ Int_t ptID = task->CreateValue(AliRsnMiniValue::kPt, kFALSE);
    /* angel to leading */ Int_t alID = task->CreateValue(AliRsnMiniValue::kAngleLeading, kFALSE);
    /* pt of leading    */ Int_t ptlID = task->CreateValue(AliRsnMiniValue::kLeadingPt, kFALSE);
    /* multiplicity     */ Int_t multID = task->CreateValue(AliRsnMiniValue::kMult,kFALSE);
    /* delta eta        */ Int_t detaID  = task->CreateValue(AliRsnMiniValue::kDeltaEta, kFALSE);
   /* phi of leading    */ Int_t philID = task->CreateValue(AliRsnMiniValue::kLeadingPhi, kFALSE);
   /* phi angle         */ Int_t phiID = task->CreateValue(AliRsnMiniValue::kPhi, kFALSE);

  // Cuts
   AliRsnCutSetDaughterParticle* cutSetK;
   AliRsnCutSetDaughterParticle::ERsnDaughterCutSet cutPiCandidate = AliRsnCutSetDaughterParticle::kTPCpidTOFveto3s;

  AliRsnCutTrackQuality* trkQualityCut= new AliRsnCutTrackQuality("myQualityCut");
  trkQualityCut->SetDefaults2011(kTRUE,kTRUE);

  cout<<"Value of custom quality--------------------"<<customQualityCutsID<<endl;

            if(customQualityCutsID==3){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexXYPtDep("0.0150+0.0500/pt^1.1");}
            else if(customQualityCutsID==4){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexXYPtDep("0.006+0.0200/pt^1.1");}
            else if(customQualityCutsID==5){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(3.);}
            else if(customQualityCutsID==6){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(0.2);}
            else if(customQualityCutsID==7){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterTPC(5.);}
            else if(customQualityCutsID==8){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterTPC(3.);}
            else if(customQualityCutsID==9){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(60);}
            else if(customQualityCutsID==10){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(100);}
            else if(customQualityCutsID==11){trkQualityCut->GetESDtrackCuts()->SetMinRatioCrossedRowsOverFindableClustersTPC(0.7);}
            else if(customQualityCutsID==12){trkQualityCut->GetESDtrackCuts()->SetMinRatioCrossedRowsOverFindableClustersTPC(0.9);}
            else if(customQualityCutsID==13){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(49.);}
            else if(customQualityCutsID==14){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(4.);}
            else if(customQualityCutsID==15){trkQualityCut->GetESDtrackCuts()->SetMaxChi2TPCConstrainedGlobal(49.);}
            else if(customQualityCutsID==16){trkQualityCut->GetESDtrackCuts()->SetMaxChi2TPCConstrainedGlobal(25.);}
            else if(customQualityCutsID==17){trkQualityCut->GetESDtrackCuts()->SetClusterRequirementITS(AliESDtrackCuts::kSPD,AliESDtrackCuts::kOff);}
            else if(customQualityCutsID==56){trkQualityCut->GetESDtrackCuts()->SetMaxDCAToVertexZ(1.);}
            else if(customQualityCutsID==60){trkQualityCut->GetESDtrackCuts()->SetMinNCrossedRowsTPC(80);}
            else if(customQualityCutsID==64){trkQualityCut->GetESDtrackCuts()->SetMaxChi2PerClusterITS(25.);}

    cutSetK=new AliRsnCutSetDaughterParticle(Form("cutK%i_%2.1fsigma_%2.1fsigmaTOF",cutPiCandidate, nSigmaPart2TPC,nSigmaPart2TOF),trkQualityCut,cutPiCandidate,AliPID::kKaon,nSigmaPart2TPC,nSigmaPart2TOF);

  Int_t iCutK  = task->AddTrackCuts(cutSetK);

    // Defining output objects
    const Int_t dims = 6;
    Int_t useIM[dims] = {1, 0, 0, 0, isMC, isMC};
    TString name[dims] = {"Unlike", "Mixing", "LikePP", "LikeMM", "True", "Mother"};
    TString comp[dims] = {"PAIR", "MIX", "PAIR", "PAIR", "TRUE", "MOTHER"};
    TString output[dims] = {"SPARSE", "SPARSE", "SPARSE", "SPARSE", "SPARSE", "SPARSE"};
    Char_t charge1[dims] = {'+', '+', '+', '-', '+', '+'};
    Char_t charge2[dims] = {'-', '-', '+', '-', '-', '-'};
    Int_t pdgCode[dims] = {333, 333, 333, 333, 333, 333};
    Double_t motherMass[dims] = {1.019461, 1.019461, 1.019461, 1.019461, 1.019461, 1.019461};

    for (Int_t i = 0; i < dims; i++)
    {
        if (!useIM[i])
            continue;
        AliRsnMiniOutput *out = task->CreateOutput(name[i].Data(), output[i].Data(), comp[i].Data());
        out->SetCutID(0, iCutK);
        out->SetCutID(1, iCutK);
        out->SetDaughter(0, AliRsnDaughter::kKaon);
        out->SetDaughter(1, AliRsnDaughter::kKaon);
        out->SetCharge(0, charge1[i]);
        out->SetCharge(1, charge2[i]);
        out->SetMotherPDG(pdgCode[i]);
        out->SetMotherMass(motherMass[i]);

        out->AddAxis(imID, 95, 0.985, 1.08);
        out->AddAxis(ptID, 1, 6., 10.);
       // if(!isPP ) out->AddAxis(multID,10,0.,100.);
       // else out->AddAxis(multID, 10, 0., 100.);

       out->AddAxis(alID, 72, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());
      //  out->AddAxis(ptlID, 15, 0., 30.);
         out->AddAxis(detaID, 64, -1.6, 1.6);
       // out->AddAxis(philID, 18, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());
       // out->AddAxis(phiID, 18, -0.5 * TMath::Pi(), 1.5 * TMath::Pi());

    }
    return kTRUE;
}

<|endoftext|>