<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Creator.
**
** $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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemoruncontrol.h"

#include "maemopackagecreationstep.h"
#include "maemosshthread.h"
#include "maemorunconfiguration.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <debugger/debuggermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFuture>
#include <QtCore/QProcess>
#include <QtCore/QStringBuilder>

#include <QtGui/QMessageBox>

namespace Qt4ProjectManager {
namespace Internal {

using ProjectExplorer::RunConfiguration;
using ProjectExplorer::ToolChain;

AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
    : RunControl(rc)
    , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
    , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
{
}

AbstractMaemoRunControl::~AbstractMaemoRunControl()
{
}

void AbstractMaemoRunControl::start()
{
    m_stoppedByUser = false;
    if (!m_devConfig.isValid()) {
        handleError(tr("No device configuration set for run configuration."));
    } else {
        emit started();
        startInitialCleanup();
    }
}

void AbstractMaemoRunControl::startInitialCleanup()
{
    emit appendMessage(this, tr("Cleaning up remote leftovers first ..."), false);
    const QStringList appsToKill
        = QStringList() << executableFileName() << QLatin1String("gdbserver");
    killRemoteProcesses(appsToKill, true);
}

void AbstractMaemoRunControl::stop()
{
    m_stoppedByUser = true;
    if (isCleaning())
        m_initialCleaner->stop();
    else if (isDeploying())
        m_sshDeployer->stop();
    else
        stopInternal();
}

void AbstractMaemoRunControl::handleInitialCleanupFinished()
{
    if (m_stoppedByUser) {
        emit appendMessage(this, tr("Initial cleanup canceled by user."), false);
        emit finished();
    } else if (m_initialCleaner->hasError()) {
        handleError(tr("Error running initial cleanup: %1.")
                    .arg(m_initialCleaner->error()));
        emit finished();
    } else {
        emit appendMessage(this, tr("Initial cleanup done."), false);
        startInternal();
    }
}

void AbstractMaemoRunControl::startDeployment(bool forDebugging)
{
    QTC_ASSERT(m_runConfig, return);

    if (m_stoppedByUser) {
        emit finished();
    } else {
        m_deployables.clear();
        if (m_runConfig->currentlyNeedsDeployment(m_devConfig.server.host)) {
            m_deployables.append(Deployable(packageFileName(),
                QFileInfo(executableOnHost()).canonicalPath(),
                &MaemoRunConfiguration::wasDeployed));
            m_needsInstall = true;
        } else {
            m_needsInstall = false;
        }
        if (forDebugging
            && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) {
            const QFileInfo &info(m_runConfig->dumperLib());
            m_deployables.append(Deployable(info.fileName(), info.canonicalPath(),
                &MaemoRunConfiguration::debuggingHelpersDeployed));
        }

        deploy();
    }
}

void AbstractMaemoRunControl::deploy()
{
    Core::ICore::instance()->progressManager()
        ->addTask(m_progress.future(), tr("Deploying"),
                  QLatin1String("Maemo.Deploy"));
    if (!m_deployables.isEmpty()) {
        QList<Core::SftpTransferInfo> deploySpecs;
        QStringList files;
        foreach (const Deployable &deployable, m_deployables) {
            const QString srcFilePath
                = deployable.dir % QDir::separator() % deployable.fileName;
            const QString tgtFilePath
                = remoteDir() % QDir::separator() % deployable.fileName;
            files << srcFilePath;
            deploySpecs << Core::SftpTransferInfo(srcFilePath,
                               tgtFilePath.toUtf8(), Core::SftpTransferInfo::Upload);
        }
        emit appendMessage(this, tr("Files to deploy: %1.").arg(files.join(" ")), false);
        m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig.server, deploySpecs));
        connect(m_sshDeployer.data(), SIGNAL(finished()),
                this, SLOT(handleDeployThreadFinished()));
        connect(m_sshDeployer.data(), SIGNAL(fileCopied(QString)),
                this, SLOT(handleFileCopied()));
        m_progress.setProgressRange(0, m_deployables.count());
        m_progress.setProgressValue(0);
        m_progress.reportStarted();
        m_sshDeployer->start();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleFileCopied()
{
    Deployable deployable = m_deployables.takeFirst();
    (m_runConfig->*deployable.updateTimestamp)(m_devConfig.server.host);
    m_progress.setProgressValue(m_progress.progressValue() + 1);
}

bool AbstractMaemoRunControl::isDeploying() const
{
    return m_sshDeployer && m_sshDeployer->isRunning();
}

QString AbstractMaemoRunControl::packageFileName() const
{
    return QFileInfo(packageFilePath()).fileName();
}

QString AbstractMaemoRunControl::packageFilePath() const
{
    return m_runConfig->packageStep()->packageFilePath();
}

QString AbstractMaemoRunControl::executableFilePathOnTarget() const
{
    return m_runConfig->packageStep()->remoteExecutableFilePath();
}

bool AbstractMaemoRunControl::isCleaning() const
{
    return m_initialCleaner && m_initialCleaner->isRunning();
}

void AbstractMaemoRunControl::startExecution()
{
    m_sshRunner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall()));
    connect(m_sshRunner.data(), SIGNAL(finished()),
            this, SLOT(handleRunThreadFinished()));
    connect(m_sshRunner.data(), SIGNAL(remoteOutput(QString)),
            this, SLOT(handleRemoteOutput(QString)));
    emit appendMessage(this, tr("Starting remote application."), false);
    m_sshRunner->start();
}

bool AbstractMaemoRunControl::isRunning() const
{
    return isDeploying() || (m_sshRunner && m_sshRunner->isRunning());
}

void AbstractMaemoRunControl::stopRunning(bool forDebugging)
{
    if (m_sshRunner && m_sshRunner->isRunning()) {
        m_sshRunner->stop();
        QStringList apps(executableFileName());
        if (forDebugging)
            apps << QLatin1String("gdbserver");
        killRemoteProcesses(apps, false);
    }
}

void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps,
                                                  bool initialCleanup)
{
    QString niceKill;
    QString brutalKill;
    foreach (const QString &app, apps) {
        niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(app);
        brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(app);
    }
    QString remoteCall = niceKill + QLatin1String("sleep 1; ") + brutalKill;
    remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon.
    QScopedPointer<MaemoSshRunner> &runner
        = initialCleanup ? m_initialCleaner : m_sshStopper;
    runner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall));
    if (initialCleanup)
        connect(runner.data(), SIGNAL(finished()),
                this, SLOT(handleInitialCleanupFinished()));
    runner->start();
}

void AbstractMaemoRunControl::handleDeployThreadFinished()
{
    bool cancel;
    if (m_stoppedByUser) {
        emit appendMessage(this, tr("Deployment canceled by user."), false);
        cancel = true;
    } else if (m_sshDeployer->hasError()) {
        handleError(tr("Deployment failed: %1").arg(m_sshDeployer->error()));
        cancel = true;
    } else {
        emit appendMessage(this, tr("Deployment finished."), false);
        cancel = false;
    }

    if (cancel) {
        m_progress.reportCanceled();
        m_progress.reportFinished();
        emit finished();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleRunThreadFinished()
{
    if (m_stoppedByUser) {
        emit appendMessage(this,
                 tr("Remote execution canceled due to user request."),
                 false);
    } else if (m_sshRunner->hasError()) {
        emit appendMessage(this, tr("Error running remote process: %1")
                                         .arg(m_sshRunner->error()),
                               true);
    } else {
        emit appendMessage(this, tr("Finished running remote process."),
                               false);
    }
    emit finished();
}

const QString AbstractMaemoRunControl::executableOnHost() const
{
    return m_runConfig->executable();
}

const QString AbstractMaemoRunControl::executableFileName() const
{
    return QFileInfo(executableOnHost()).fileName();
}

const QString AbstractMaemoRunControl::remoteDir() const
{
    return homeDirOnDevice(m_devConfig.server.uname);
}

QString AbstractMaemoRunControl::remoteSudo() const
{
    return QLatin1String("/usr/lib/mad-developer/devrootsh");
}

QString AbstractMaemoRunControl::remoteInstallCommand() const
{
    return QString::fromLocal8Bit("%1 dpkg -i %2").arg(remoteSudo())
        .arg(packageFileName());
}

const QString AbstractMaemoRunControl::targetCmdLinePrefix() const
{
    const QString &installPrefix = m_needsInstall
        ? remoteInstallCommand() + QLatin1String(" && ")
        : QString();
    return QString::fromLocal8Bit("%1%2 chmod u+x %3 && source /etc/profile && ")
        .arg(installPrefix).arg(remoteSudo()).arg(executableFilePathOnTarget());
}

QString AbstractMaemoRunControl::targetCmdLineSuffix() const
{
    return m_runConfig->arguments().join(" ");
}

void AbstractMaemoRunControl::handleError(const QString &errString)
{
    QMessageBox::critical(0, tr("Remote Execution Failure"), errString);
    emit appendMessage(this, errString, true);
}

MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
{
}

MaemoRunControl::~MaemoRunControl()
{
    stop();
}

void MaemoRunControl::startInternal()
{
    startDeployment(false);
}

QString MaemoRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 %2 %3").arg(targetCmdLinePrefix())
        .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
}

void MaemoRunControl::stopInternal()
{
    AbstractMaemoRunControl::stopRunning(false);
}

void MaemoRunControl::handleRemoteOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output, false);
}

MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
    , m_debuggerManager(ExtensionSystem::PluginManager::instance()
                      ->getObject<Debugger::DebuggerManager>())
    , m_startParams(new Debugger::DebuggerStartParameters)
{
    QTC_ASSERT(m_debuggerManager != 0, return);
    m_startParams->startMode = Debugger::StartRemote;
    m_startParams->executable = executableOnHost();
    m_startParams->remoteChannel
        = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort();
    m_startParams->remoteArchitecture = QLatin1String("arm");
    m_startParams->sysRoot = m_runConfig->sysRoot();
    m_startParams->toolChainType = ToolChain::GCC_MAEMO;
    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
    m_startParams->dumperLibrary = m_runConfig->dumperLib();
    m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
        .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());

    connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
        SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString, bool)),
        this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
}

MaemoDebugRunControl::~MaemoDebugRunControl()
{
    disconnect(SIGNAL(addToOutputWindow(RunControl*,QString, bool)));
    disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString, bool)));
    stop();
    debuggingFinished();
}

void MaemoDebugRunControl::startInternal()
{
    m_debuggingStarted = false;
    startDeployment(true);
}

QString MaemoDebugRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4")
        .arg(targetCmdLinePrefix()).arg(gdbServerPort())
        .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
}

void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
{
    if (!m_debuggingStarted) {
        m_debuggingStarted = true;
        startDebugging();
    }
    emit addToOutputWindowInline(this, output, false);
}

void MaemoDebugRunControl::startDebugging()
{
    m_debuggerManager->startNewDebugger(m_startParams);
}

void MaemoDebugRunControl::stopInternal()
{
    m_debuggerManager->exitDebugger();
}

bool MaemoDebugRunControl::isRunning() const
{
    return AbstractMaemoRunControl::isRunning()
        || m_debuggerManager->state() != Debugger::DebuggerNotReady;
}

void MaemoDebugRunControl::debuggingFinished()
{
    AbstractMaemoRunControl::stopRunning(true);
}

void MaemoDebugRunControl::debuggerOutput(const QString &output)
{
    emit appendMessage(this, QLatin1String("[gdb says:] ") + output, true);
}

QString MaemoDebugRunControl::gdbServerPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.gdbServerPort)
        : m_runConfig->simulatorGdbServerPort();
}

} // namespace Internal
} // namespace Qt4ProjectManager
<commit_msg>Maemo: Set DISPLAY variable before running remote executable.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Creator.
**
** $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.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemoruncontrol.h"

#include "maemopackagecreationstep.h"
#include "maemosshthread.h"
#include "maemorunconfiguration.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <debugger/debuggermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFuture>
#include <QtCore/QProcess>
#include <QtCore/QStringBuilder>

#include <QtGui/QMessageBox>

namespace Qt4ProjectManager {
namespace Internal {

using ProjectExplorer::RunConfiguration;
using ProjectExplorer::ToolChain;

AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
    : RunControl(rc)
    , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
    , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
{
}

AbstractMaemoRunControl::~AbstractMaemoRunControl()
{
}

void AbstractMaemoRunControl::start()
{
    m_stoppedByUser = false;
    if (!m_devConfig.isValid()) {
        handleError(tr("No device configuration set for run configuration."));
    } else {
        emit started();
        startInitialCleanup();
    }
}

void AbstractMaemoRunControl::startInitialCleanup()
{
    emit appendMessage(this, tr("Cleaning up remote leftovers first ..."), false);
    const QStringList appsToKill
        = QStringList() << executableFileName() << QLatin1String("gdbserver");
    killRemoteProcesses(appsToKill, true);
}

void AbstractMaemoRunControl::stop()
{
    m_stoppedByUser = true;
    if (isCleaning())
        m_initialCleaner->stop();
    else if (isDeploying())
        m_sshDeployer->stop();
    else
        stopInternal();
}

void AbstractMaemoRunControl::handleInitialCleanupFinished()
{
    if (m_stoppedByUser) {
        emit appendMessage(this, tr("Initial cleanup canceled by user."), false);
        emit finished();
    } else if (m_initialCleaner->hasError()) {
        handleError(tr("Error running initial cleanup: %1.")
                    .arg(m_initialCleaner->error()));
        emit finished();
    } else {
        emit appendMessage(this, tr("Initial cleanup done."), false);
        startInternal();
    }
}

void AbstractMaemoRunControl::startDeployment(bool forDebugging)
{
    QTC_ASSERT(m_runConfig, return);

    if (m_stoppedByUser) {
        emit finished();
    } else {
        m_deployables.clear();
        if (m_runConfig->currentlyNeedsDeployment(m_devConfig.server.host)) {
            m_deployables.append(Deployable(packageFileName(),
                QFileInfo(executableOnHost()).canonicalPath(),
                &MaemoRunConfiguration::wasDeployed));
            m_needsInstall = true;
        } else {
            m_needsInstall = false;
        }
        if (forDebugging
            && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.server.host)) {
            const QFileInfo &info(m_runConfig->dumperLib());
            m_deployables.append(Deployable(info.fileName(), info.canonicalPath(),
                &MaemoRunConfiguration::debuggingHelpersDeployed));
        }

        deploy();
    }
}

void AbstractMaemoRunControl::deploy()
{
    Core::ICore::instance()->progressManager()
        ->addTask(m_progress.future(), tr("Deploying"),
                  QLatin1String("Maemo.Deploy"));
    if (!m_deployables.isEmpty()) {
        QList<Core::SftpTransferInfo> deploySpecs;
        QStringList files;
        foreach (const Deployable &deployable, m_deployables) {
            const QString srcFilePath
                = deployable.dir % QDir::separator() % deployable.fileName;
            const QString tgtFilePath
                = remoteDir() % QDir::separator() % deployable.fileName;
            files << srcFilePath;
            deploySpecs << Core::SftpTransferInfo(srcFilePath,
                               tgtFilePath.toUtf8(), Core::SftpTransferInfo::Upload);
        }
        emit appendMessage(this, tr("Files to deploy: %1.").arg(files.join(" ")), false);
        m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig.server, deploySpecs));
        connect(m_sshDeployer.data(), SIGNAL(finished()),
                this, SLOT(handleDeployThreadFinished()));
        connect(m_sshDeployer.data(), SIGNAL(fileCopied(QString)),
                this, SLOT(handleFileCopied()));
        m_progress.setProgressRange(0, m_deployables.count());
        m_progress.setProgressValue(0);
        m_progress.reportStarted();
        m_sshDeployer->start();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleFileCopied()
{
    Deployable deployable = m_deployables.takeFirst();
    (m_runConfig->*deployable.updateTimestamp)(m_devConfig.server.host);
    m_progress.setProgressValue(m_progress.progressValue() + 1);
}

bool AbstractMaemoRunControl::isDeploying() const
{
    return m_sshDeployer && m_sshDeployer->isRunning();
}

QString AbstractMaemoRunControl::packageFileName() const
{
    return QFileInfo(packageFilePath()).fileName();
}

QString AbstractMaemoRunControl::packageFilePath() const
{
    return m_runConfig->packageStep()->packageFilePath();
}

QString AbstractMaemoRunControl::executableFilePathOnTarget() const
{
    return m_runConfig->packageStep()->remoteExecutableFilePath();
}

bool AbstractMaemoRunControl::isCleaning() const
{
    return m_initialCleaner && m_initialCleaner->isRunning();
}

void AbstractMaemoRunControl::startExecution()
{
    m_sshRunner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall()));
    connect(m_sshRunner.data(), SIGNAL(finished()),
            this, SLOT(handleRunThreadFinished()));
    connect(m_sshRunner.data(), SIGNAL(remoteOutput(QString)),
            this, SLOT(handleRemoteOutput(QString)));
    emit appendMessage(this, tr("Starting remote application."), false);
    m_sshRunner->start();
}

bool AbstractMaemoRunControl::isRunning() const
{
    return isDeploying() || (m_sshRunner && m_sshRunner->isRunning());
}

void AbstractMaemoRunControl::stopRunning(bool forDebugging)
{
    if (m_sshRunner && m_sshRunner->isRunning()) {
        m_sshRunner->stop();
        QStringList apps(executableFileName());
        if (forDebugging)
            apps << QLatin1String("gdbserver");
        killRemoteProcesses(apps, false);
    }
}

void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps,
                                                  bool initialCleanup)
{
    QString niceKill;
    QString brutalKill;
    foreach (const QString &app, apps) {
        niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(app);
        brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(app);
    }
    QString remoteCall = niceKill + QLatin1String("sleep 1; ") + brutalKill;
    remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon.
    QScopedPointer<MaemoSshRunner> &runner
        = initialCleanup ? m_initialCleaner : m_sshStopper;
    runner.reset(new MaemoSshRunner(m_devConfig.server, remoteCall));
    if (initialCleanup)
        connect(runner.data(), SIGNAL(finished()),
                this, SLOT(handleInitialCleanupFinished()));
    runner->start();
}

void AbstractMaemoRunControl::handleDeployThreadFinished()
{
    bool cancel;
    if (m_stoppedByUser) {
        emit appendMessage(this, tr("Deployment canceled by user."), false);
        cancel = true;
    } else if (m_sshDeployer->hasError()) {
        handleError(tr("Deployment failed: %1").arg(m_sshDeployer->error()));
        cancel = true;
    } else {
        emit appendMessage(this, tr("Deployment finished."), false);
        cancel = false;
    }

    if (cancel) {
        m_progress.reportCanceled();
        m_progress.reportFinished();
        emit finished();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleRunThreadFinished()
{
    if (m_stoppedByUser) {
        emit appendMessage(this,
                 tr("Remote execution canceled due to user request."),
                 false);
    } else if (m_sshRunner->hasError()) {
        emit appendMessage(this, tr("Error running remote process: %1")
                                         .arg(m_sshRunner->error()),
                               true);
    } else {
        emit appendMessage(this, tr("Finished running remote process."),
                               false);
    }
    emit finished();
}

const QString AbstractMaemoRunControl::executableOnHost() const
{
    return m_runConfig->executable();
}

const QString AbstractMaemoRunControl::executableFileName() const
{
    return QFileInfo(executableOnHost()).fileName();
}

const QString AbstractMaemoRunControl::remoteDir() const
{
    return homeDirOnDevice(m_devConfig.server.uname);
}

QString AbstractMaemoRunControl::remoteSudo() const
{
    return QLatin1String("/usr/lib/mad-developer/devrootsh");
}

QString AbstractMaemoRunControl::remoteInstallCommand() const
{
    return QString::fromLocal8Bit("%1 dpkg -i %2").arg(remoteSudo())
        .arg(packageFileName());
}

const QString AbstractMaemoRunControl::targetCmdLinePrefix() const
{
    const QString &installPrefix = m_needsInstall
        ? remoteInstallCommand() + QLatin1String(" && ")
        : QString();
    return QString::fromLocal8Bit("%1%2 chmod a+x %3 && source /etc/profile && DISPLAY=:0.0 ")
        .arg(installPrefix).arg(remoteSudo()).arg(executableFilePathOnTarget());
}

QString AbstractMaemoRunControl::targetCmdLineSuffix() const
{
    return m_runConfig->arguments().join(" ");
}

void AbstractMaemoRunControl::handleError(const QString &errString)
{
    QMessageBox::critical(0, tr("Remote Execution Failure"), errString);
    emit appendMessage(this, errString, true);
}

MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
{
}

MaemoRunControl::~MaemoRunControl()
{
    stop();
}

void MaemoRunControl::startInternal()
{
    startDeployment(false);
}

QString MaemoRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 %2 %3").arg(targetCmdLinePrefix())
        .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
}

void MaemoRunControl::stopInternal()
{
    AbstractMaemoRunControl::stopRunning(false);
}

void MaemoRunControl::handleRemoteOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output, false);
}

MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
    , m_debuggerManager(ExtensionSystem::PluginManager::instance()
                      ->getObject<Debugger::DebuggerManager>())
    , m_startParams(new Debugger::DebuggerStartParameters)
{
    QTC_ASSERT(m_debuggerManager != 0, return);
    m_startParams->startMode = Debugger::StartRemote;
    m_startParams->executable = executableOnHost();
    m_startParams->remoteChannel
        = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort();
    m_startParams->remoteArchitecture = QLatin1String("arm");
    m_startParams->sysRoot = m_runConfig->sysRoot();
    m_startParams->toolChainType = ToolChain::GCC_MAEMO;
    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
    m_startParams->dumperLibrary = m_runConfig->dumperLib();
    m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
        .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());

    connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
        SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString, bool)),
        this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
}

MaemoDebugRunControl::~MaemoDebugRunControl()
{
    disconnect(SIGNAL(addToOutputWindow(RunControl*,QString, bool)));
    disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString, bool)));
    stop();
    debuggingFinished();
}

void MaemoDebugRunControl::startInternal()
{
    m_debuggingStarted = false;
    startDeployment(true);
}

QString MaemoDebugRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4")
        .arg(targetCmdLinePrefix()).arg(gdbServerPort())
        .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix());
}

void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
{
    if (!m_debuggingStarted) {
        m_debuggingStarted = true;
        startDebugging();
    }
    emit addToOutputWindowInline(this, output, false);
}

void MaemoDebugRunControl::startDebugging()
{
    m_debuggerManager->startNewDebugger(m_startParams);
}

void MaemoDebugRunControl::stopInternal()
{
    m_debuggerManager->exitDebugger();
}

bool MaemoDebugRunControl::isRunning() const
{
    return AbstractMaemoRunControl::isRunning()
        || m_debuggerManager->state() != Debugger::DebuggerNotReady;
}

void MaemoDebugRunControl::debuggingFinished()
{
    AbstractMaemoRunControl::stopRunning(true);
}

void MaemoDebugRunControl::debuggerOutput(const QString &output)
{
    emit appendMessage(this, QLatin1String("[gdb says:] ") + output, true);
}

QString MaemoDebugRunControl::gdbServerPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.gdbServerPort)
        : m_runConfig->simulatorGdbServerPort();
}

} // namespace Internal
} // namespace Qt4ProjectManager
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "utils.h"
#include <e32std.h>

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

/*! \class MMF::Utils
  \internal
*/

/*! \class MMF::TTraceContext
  \internal
*/

/*! \class MMF::Utils
  \internal
*/

_LIT(PanicCategory, "Phonon::MMF");

void MMF::Utils::panic(PanicCode code)
{
    User::Panic(PanicCategory, code);
}

static const TInt KMimePrefixLength = 6; // either "audio/" or "video/"
_LIT(KMimePrefixAudio, "audio/");
_LIT(KMimePrefixVideo, "video/");

MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType)
{
    MediaType result = MediaTypeUnknown;

    if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixAudio) == 0) {
        result = MediaTypeAudio;
    } else if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixVideo) == 0) {
        result = MediaTypeVideo;
    }

    return result;
}

#ifdef _DEBUG

#include <hal.h>
#include <hal_data.h>
#include <gdi.h>
#include <eikenv.h>

struct TScreenInfo
{
    int width;
    int height;
    int bpp;
    const char* address;
    int initialOffset;
    int lineOffset;
    TDisplayMode displayMode;
};

static void getScreenInfoL(TScreenInfo& info)
{
    info.displayMode = CEikonEnv::Static()->ScreenDevice()->DisplayMode();

    // Then we must set these as the input parameter
    info.width = info.displayMode;
    info.height = info.displayMode;
    info.initialOffset = info.displayMode;
    info.lineOffset = info.displayMode;
    info.bpp = info.displayMode;

    User::LeaveIfError( HAL::Get(HALData::EDisplayXPixels, info.width) );
    User::LeaveIfError( HAL::Get(HALData::EDisplayYPixels, info.width) );

    int address;
    User::LeaveIfError( HAL::Get(HALData::EDisplayMemoryAddress, address) );
    info.address = reinterpret_cast<const char*>(address);

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetToFirstPixel, info.initialOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetBetweenLines, info.lineOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayBitsPerPixel, info.bpp) );
}

QColor MMF::Utils::getScreenPixel(const QPoint& pos)
{
    TScreenInfo info;
    TRAPD(err, getScreenInfoL(info));
    QColor pixel;
    if(err == KErrNone and pos.x() < info.width and pos.y() < info.height)
    {
        const int bytesPerPixel = info.bpp / 8;
        Q_ASSERT(bytesPerPixel >= 3);

        const int stride = (info.width * bytesPerPixel) + info.lineOffset;

        const char* ptr =
                info.address
            +    info.initialOffset
            +    pos.y() * stride
            +    pos.x() * bytesPerPixel;

        // BGRA
        pixel.setBlue(*ptr++);
        pixel.setGreen(*ptr++);
        pixel.setRed(*ptr++);

        if(bytesPerPixel == 4)
            pixel.setAlpha(*ptr++);
    }
    return pixel;
}

// Debugging: for debugging video visibility
void MMF::Utils::dumpScreenPixelSample()
{
    for(int i=0; i<20; ++i) {
        const QPoint pos(i*10, i*10);
        const QColor pixel = Utils::getScreenPixel(pos);
        RDebug::Printf(
            "Phonon::MMF::Utils::dumpScreenPixelSample %d %d = %d %d %d %d",
            pos.x(), pos.y(), pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()
        );
    }
}

#endif // _DEBUG

QT_END_NAMESPACE

<commit_msg>qdoc: Marked some undocumented Phonon classes internal<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "utils.h"
#include <e32std.h>

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

/*! \namespace MMF::Utils
  \internal
*/

/*! \class MMF::TTraceContext
  \internal
*/

/*! \class MMF::Utils
  \internal
*/

_LIT(PanicCategory, "Phonon::MMF");

void MMF::Utils::panic(PanicCode code)
{
    User::Panic(PanicCategory, code);
}

static const TInt KMimePrefixLength = 6; // either "audio/" or "video/"
_LIT(KMimePrefixAudio, "audio/");
_LIT(KMimePrefixVideo, "video/");

MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType)
{
    MediaType result = MediaTypeUnknown;

    if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixAudio) == 0) {
        result = MediaTypeAudio;
    } else if (mimeType.Left(KMimePrefixLength).Compare(KMimePrefixVideo) == 0) {
        result = MediaTypeVideo;
    }

    return result;
}

#ifdef _DEBUG

#include <hal.h>
#include <hal_data.h>
#include <gdi.h>
#include <eikenv.h>

struct TScreenInfo
{
    int width;
    int height;
    int bpp;
    const char* address;
    int initialOffset;
    int lineOffset;
    TDisplayMode displayMode;
};

static void getScreenInfoL(TScreenInfo& info)
{
    info.displayMode = CEikonEnv::Static()->ScreenDevice()->DisplayMode();

    // Then we must set these as the input parameter
    info.width = info.displayMode;
    info.height = info.displayMode;
    info.initialOffset = info.displayMode;
    info.lineOffset = info.displayMode;
    info.bpp = info.displayMode;

    User::LeaveIfError( HAL::Get(HALData::EDisplayXPixels, info.width) );
    User::LeaveIfError( HAL::Get(HALData::EDisplayYPixels, info.width) );

    int address;
    User::LeaveIfError( HAL::Get(HALData::EDisplayMemoryAddress, address) );
    info.address = reinterpret_cast<const char*>(address);

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetToFirstPixel, info.initialOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayOffsetBetweenLines, info.lineOffset) );

    User::LeaveIfError( HAL::Get(HALData::EDisplayBitsPerPixel, info.bpp) );
}

QColor MMF::Utils::getScreenPixel(const QPoint& pos)
{
    TScreenInfo info;
    TRAPD(err, getScreenInfoL(info));
    QColor pixel;
    if(err == KErrNone and pos.x() < info.width and pos.y() < info.height)
    {
        const int bytesPerPixel = info.bpp / 8;
        Q_ASSERT(bytesPerPixel >= 3);

        const int stride = (info.width * bytesPerPixel) + info.lineOffset;

        const char* ptr =
                info.address
            +    info.initialOffset
            +    pos.y() * stride
            +    pos.x() * bytesPerPixel;

        // BGRA
        pixel.setBlue(*ptr++);
        pixel.setGreen(*ptr++);
        pixel.setRed(*ptr++);

        if(bytesPerPixel == 4)
            pixel.setAlpha(*ptr++);
    }
    return pixel;
}

// Debugging: for debugging video visibility
void MMF::Utils::dumpScreenPixelSample()
{
    for(int i=0; i<20; ++i) {
        const QPoint pos(i*10, i*10);
        const QColor pixel = Utils::getScreenPixel(pos);
        RDebug::Printf(
            "Phonon::MMF::Utils::dumpScreenPixelSample %d %d = %d %d %d %d",
            pos.x(), pos.y(), pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()
        );
    }
}

#endif // _DEBUG

QT_END_NAMESPACE

<|endoftext|>


<commit_before>#ifndef __ACTION_HLS_NVME_MEMCOPY_H__
#define __ACTION_HLS_NVME_MEMCOPY_H__

/*
 * Copyright 2017 International Business Machines
 *
 * 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 <stdint.h>
#include <string.h>
#include <ap_int.h>

#include "hls_snap.H"
#include <action_nvme_memcopy.h> /* Memcopy Job definition */

#define RELEASE_LEVEL         0x00000001

#define MAX_NB_OF_BYTES_READ  (256 * 1024)
#define SSD_BLOCK_SIZE        512
#define SSD_BLOCK_SIZE_SHIFT  9
#define MAX_SSD_BLOCK_XFER    128
//The NVMe subsystem can handle up to 218 read or write requests per drive.

#define CARD_DRAM_SIZE        (1 * 1024 *1024 * 1024)
#define MAX_NB_OF_WORDS_READ    (MAX_NB_OF_BYTES_READ/BPERDW)

#define DRAM_ADDR_TO_SSD   0x00000000
#define DRAM_ADDR_FROM_SSD 0x80000000
//---------------------------------------------------------------------
typedef struct {
    CONTROL Control;    /*  16 bytes */
    nvme_memcopy_job_t Data;    /* 108 bytes */
    uint8_t padding[SNAP_HLS_JOBSIZE - sizeof(nvme_memcopy_job_t)];
} action_reg;

#endif  /* __ACTION_HLS_NVME_MEMCOPY_H__ */
<commit_msg>Delete action_nvme_memcopy.H (#702)<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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 "ez-rpc.h"
#include "rpc-twoparty.h"
#include <capnp/rpc.capnp.h>
#include <kj/async-io.h>
#include <kj/debug.h>
#include <kj/threadlocal.h>
#include <map>

namespace capnp {

KJ_THREADLOCAL_PTR(EzRpcContext) threadEzContext = nullptr;

class EzRpcContext: public kj::Refcounted {
public:
  EzRpcContext(): ioContext(kj::setupAsyncIo()) {
    threadEzContext = this;
  }

  ~EzRpcContext() noexcept(false) {
    KJ_REQUIRE(threadEzContext == this,
               "EzRpcContext destroyed from different thread than it was created.") {
      return;
    }
    threadEzContext = nullptr;
  }

  kj::WaitScope& getWaitScope() {
    return ioContext.waitScope;
  }

  kj::AsyncIoProvider& getIoProvider() {
    return *ioContext.provider;
  }

  kj::LowLevelAsyncIoProvider& getLowLevelIoProvider() {
    return *ioContext.lowLevelProvider;
  }

  static kj::Own<EzRpcContext> getThreadLocal() {
    EzRpcContext* existing = threadEzContext;
    if (existing != nullptr) {
      return kj::addRef(*existing);
    } else {
      return kj::refcounted<EzRpcContext>();
    }
  }

private:
  kj::AsyncIoContext ioContext;
};

// =======================================================================================

struct EzRpcClient::Impl {
  kj::Own<EzRpcContext> context;

  struct ClientContext {
    kj::Own<kj::AsyncIoStream> stream;
    TwoPartyVatNetwork network;
    RpcSystem<rpc::twoparty::VatId> rpcSystem;

    ClientContext(kj::Own<kj::AsyncIoStream>&& stream, ReaderOptions readerOpts)
        : stream(kj::mv(stream)),
          network(*this->stream, rpc::twoparty::Side::CLIENT, readerOpts),
          rpcSystem(makeRpcClient(network)) {}

    Capability::Client getMain() {
      word scratch[4];
      memset(scratch, 0, sizeof(scratch));
      MallocMessageBuilder message(scratch);
      auto hostId = message.getRoot<rpc::twoparty::VatId>();
      hostId.setSide(rpc::twoparty::Side::SERVER);
      return rpcSystem.bootstrap(hostId);
    }

    Capability::Client restore(kj::StringPtr name) {
      word scratch[64];
      memset(scratch, 0, sizeof(scratch));
      MallocMessageBuilder message(scratch);

      auto hostIdOrphan = message.getOrphanage().newOrphan<rpc::twoparty::VatId>();
      auto hostId = hostIdOrphan.get();
      hostId.setSide(rpc::twoparty::Side::SERVER);

      auto objectId = message.getRoot<AnyPointer>();
      objectId.setAs<Text>(name);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
      return rpcSystem.restore(hostId, objectId);
#pragma GCC diagnostic pop
    }
  };

  kj::ForkedPromise<void> setupPromise;

  kj::Maybe<kj::Own<ClientContext>> clientContext;
  // Filled in before `setupPromise` resolves.

  Impl(kj::StringPtr serverAddress, uint defaultPort,
       ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(context->getIoProvider().getNetwork()
            .parseAddress(serverAddress, defaultPort)
            .then([readerOpts](kj::Own<kj::NetworkAddress>&& addr) {
              return addr->connect();
            }).then([this, readerOpts](kj::Own<kj::AsyncIoStream>&& stream) {
              clientContext = kj::heap<ClientContext>(kj::mv(stream),
                                                      readerOpts);
            }).fork()) {}

  Impl(const struct sockaddr* serverAddress, uint addrSize,
       ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(context->getIoProvider().getNetwork()
            .getSockaddr(serverAddress, addrSize)->connect()
            .then([this, readerOpts](kj::Own<kj::AsyncIoStream>&& stream) {
              clientContext = kj::heap<ClientContext>(kj::mv(stream),
                                                      readerOpts);
            }).fork()) {}

  Impl(int socketFd, ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(kj::Promise<void>(kj::READY_NOW).fork()),
        clientContext(kj::heap<ClientContext>(
            context->getLowLevelIoProvider().wrapSocketFd(socketFd),
            readerOpts)) {}
};

EzRpcClient::EzRpcClient(kj::StringPtr serverAddress, uint defaultPort, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(serverAddress, defaultPort, readerOpts)) {}

EzRpcClient::EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(serverAddress, addrSize, readerOpts)) {}

EzRpcClient::EzRpcClient(int socketFd, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(socketFd, readerOpts)) {}

EzRpcClient::~EzRpcClient() noexcept(false) {}

Capability::Client EzRpcClient::getMain() {
  KJ_IF_MAYBE(client, impl->clientContext) {
    return client->get()->getMain();
  } else {
    return impl->setupPromise.addBranch().then([this]() {
      return KJ_ASSERT_NONNULL(impl->clientContext)->getMain();
    });
  }
}

Capability::Client EzRpcClient::importCap(kj::StringPtr name) {
  KJ_IF_MAYBE(client, impl->clientContext) {
    return client->get()->restore(name);
  } else {
    return impl->setupPromise.addBranch().then(kj::mvCapture(kj::heapString(name),
        [this](kj::String&& name) {
      return KJ_ASSERT_NONNULL(impl->clientContext)->restore(name);
    }));
  }
}

kj::WaitScope& EzRpcClient::getWaitScope() {
  return impl->context->getWaitScope();
}

kj::AsyncIoProvider& EzRpcClient::getIoProvider() {
  return impl->context->getIoProvider();
}

kj::LowLevelAsyncIoProvider& EzRpcClient::getLowLevelIoProvider() {
  return impl->context->getLowLevelIoProvider();
}

// =======================================================================================

struct EzRpcServer::Impl final: public SturdyRefRestorer<AnyPointer>,
                                public kj::TaskSet::ErrorHandler {
  Capability::Client mainInterface;
  kj::Own<EzRpcContext> context;

  struct ExportedCap {
    kj::String name;
    Capability::Client cap = nullptr;

    ExportedCap(kj::StringPtr name, Capability::Client cap)
        : name(kj::heapString(name)), cap(cap) {}

    ExportedCap() = default;
    ExportedCap(const ExportedCap&) = delete;
    ExportedCap(ExportedCap&&) = default;
    ExportedCap& operator=(const ExportedCap&) = delete;
    ExportedCap& operator=(ExportedCap&&) = default;
    // Make std::map happy...
  };

  std::map<kj::StringPtr, ExportedCap> exportMap;

  kj::ForkedPromise<uint> portPromise;

  kj::TaskSet tasks;

  struct ServerContext {
    kj::Own<kj::AsyncIoStream> stream;
    TwoPartyVatNetwork network;
    RpcSystem<rpc::twoparty::VatId> rpcSystem;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    ServerContext(kj::Own<kj::AsyncIoStream>&& stream, SturdyRefRestorer<AnyPointer>& restorer,
                  ReaderOptions readerOpts)
        : stream(kj::mv(stream)),
          network(*this->stream, rpc::twoparty::Side::SERVER, readerOpts),
          rpcSystem(makeRpcServer(network, restorer)) {}
#pragma GCC diagnostic pop
  };

  Impl(Capability::Client mainInterface, kj::StringPtr bindAddress, uint defaultPort,
       ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) {
    auto paf = kj::newPromiseAndFulfiller<uint>();
    portPromise = paf.promise.fork();

    tasks.add(context->getIoProvider().getNetwork().parseAddress(bindAddress, defaultPort)
        .then(kj::mvCapture(paf.fulfiller,
          [this, readerOpts](kj::Own<kj::PromiseFulfiller<uint>>&& portFulfiller,
                             kj::Own<kj::NetworkAddress>&& addr) {
      auto listener = addr->listen();
      portFulfiller->fulfill(listener->getPort());
      acceptLoop(kj::mv(listener), readerOpts);
    })));
  }

  Impl(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize,
       ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) {
    auto listener = context->getIoProvider().getNetwork()
        .getSockaddr(bindAddress, addrSize)->listen();
    portPromise = kj::Promise<uint>(listener->getPort()).fork();
    acceptLoop(kj::mv(listener), readerOpts);
  }

  Impl(Capability::Client mainInterface, int socketFd, uint port, ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()),
        portPromise(kj::Promise<uint>(port).fork()),
        tasks(*this) {
    acceptLoop(context->getLowLevelIoProvider().wrapListenSocketFd(socketFd), readerOpts);
  }

  void acceptLoop(kj::Own<kj::ConnectionReceiver>&& listener, ReaderOptions readerOpts) {
    auto ptr = listener.get();
    tasks.add(ptr->accept().then(kj::mvCapture(kj::mv(listener),
        [this, readerOpts](kj::Own<kj::ConnectionReceiver>&& listener,
                           kj::Own<kj::AsyncIoStream>&& connection) {
      acceptLoop(kj::mv(listener), readerOpts);

      auto server = kj::heap<ServerContext>(kj::mv(connection), *this, readerOpts);

      // Arrange to destroy the server context when all references are gone, or when the
      // EzRpcServer is destroyed (which will destroy the TaskSet).
      tasks.add(server->network.onDisconnect().attach(kj::mv(server)));
    })));
  }

  Capability::Client restore(AnyPointer::Reader objectId) override {
    if (objectId.isNull()) {
      return mainInterface;
    } else {
      auto name = objectId.getAs<Text>();
      auto iter = exportMap.find(name);
      if (iter == exportMap.end()) {
        KJ_FAIL_REQUIRE("Server exports no such capability.", name) { break; }
        return nullptr;
      } else {
        return iter->second.cap;
      }
    }
  }

  void taskFailed(kj::Exception&& exception) override {
    kj::throwFatalException(kj::mv(exception));
  }
};

EzRpcServer::EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress,
                         uint defaultPort, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), bindAddress, defaultPort, readerOpts)) {}

EzRpcServer::EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress,
                         uint addrSize, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), bindAddress, addrSize, readerOpts)) {}

EzRpcServer::EzRpcServer(Capability::Client mainInterface, int socketFd, uint port,
                         ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), socketFd, port, readerOpts)) {}

EzRpcServer::EzRpcServer(kj::StringPtr bindAddress, uint defaultPort,
                         ReaderOptions readerOpts)
    : EzRpcServer(nullptr, bindAddress, defaultPort, readerOpts) {}

EzRpcServer::EzRpcServer(struct sockaddr* bindAddress, uint addrSize,
                         ReaderOptions readerOpts)
    : EzRpcServer(nullptr, bindAddress, addrSize, readerOpts) {}

EzRpcServer::EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts)
    : EzRpcServer(nullptr, socketFd, port, readerOpts) {}

EzRpcServer::~EzRpcServer() noexcept(false) {}

void EzRpcServer::exportCap(kj::StringPtr name, Capability::Client cap) {
  Impl::ExportedCap entry(kj::heapString(name), cap);
  impl->exportMap[entry.name] = kj::mv(entry);
}

kj::Promise<uint> EzRpcServer::getPort() {
  return impl->portPromise.addBranch();
}

kj::WaitScope& EzRpcServer::getWaitScope() {
  return impl->context->getWaitScope();
}

kj::AsyncIoProvider& EzRpcServer::getIoProvider() {
  return impl->context->getIoProvider();
}

kj::LowLevelAsyncIoProvider& EzRpcServer::getLowLevelIoProvider() {
  return impl->context->getLowLevelIoProvider();
}

}  // namespace capnp
<commit_msg>Fix bug where EzRpcClient would segfault if the target host resolved to multiple addresses and the connection to the first of those failed.<commit_after>// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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 "ez-rpc.h"
#include "rpc-twoparty.h"
#include <capnp/rpc.capnp.h>
#include <kj/async-io.h>
#include <kj/debug.h>
#include <kj/threadlocal.h>
#include <map>

namespace capnp {

KJ_THREADLOCAL_PTR(EzRpcContext) threadEzContext = nullptr;

class EzRpcContext: public kj::Refcounted {
public:
  EzRpcContext(): ioContext(kj::setupAsyncIo()) {
    threadEzContext = this;
  }

  ~EzRpcContext() noexcept(false) {
    KJ_REQUIRE(threadEzContext == this,
               "EzRpcContext destroyed from different thread than it was created.") {
      return;
    }
    threadEzContext = nullptr;
  }

  kj::WaitScope& getWaitScope() {
    return ioContext.waitScope;
  }

  kj::AsyncIoProvider& getIoProvider() {
    return *ioContext.provider;
  }

  kj::LowLevelAsyncIoProvider& getLowLevelIoProvider() {
    return *ioContext.lowLevelProvider;
  }

  static kj::Own<EzRpcContext> getThreadLocal() {
    EzRpcContext* existing = threadEzContext;
    if (existing != nullptr) {
      return kj::addRef(*existing);
    } else {
      return kj::refcounted<EzRpcContext>();
    }
  }

private:
  kj::AsyncIoContext ioContext;
};

// =======================================================================================

kj::Promise<kj::Own<kj::AsyncIoStream>> connectAttach(kj::Own<kj::NetworkAddress>&& addr) {
  return addr->connect().attach(kj::mv(addr));
}

struct EzRpcClient::Impl {
  kj::Own<EzRpcContext> context;

  struct ClientContext {
    kj::Own<kj::AsyncIoStream> stream;
    TwoPartyVatNetwork network;
    RpcSystem<rpc::twoparty::VatId> rpcSystem;

    ClientContext(kj::Own<kj::AsyncIoStream>&& stream, ReaderOptions readerOpts)
        : stream(kj::mv(stream)),
          network(*this->stream, rpc::twoparty::Side::CLIENT, readerOpts),
          rpcSystem(makeRpcClient(network)) {}

    Capability::Client getMain() {
      word scratch[4];
      memset(scratch, 0, sizeof(scratch));
      MallocMessageBuilder message(scratch);
      auto hostId = message.getRoot<rpc::twoparty::VatId>();
      hostId.setSide(rpc::twoparty::Side::SERVER);
      return rpcSystem.bootstrap(hostId);
    }

    Capability::Client restore(kj::StringPtr name) {
      word scratch[64];
      memset(scratch, 0, sizeof(scratch));
      MallocMessageBuilder message(scratch);

      auto hostIdOrphan = message.getOrphanage().newOrphan<rpc::twoparty::VatId>();
      auto hostId = hostIdOrphan.get();
      hostId.setSide(rpc::twoparty::Side::SERVER);

      auto objectId = message.getRoot<AnyPointer>();
      objectId.setAs<Text>(name);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
      return rpcSystem.restore(hostId, objectId);
#pragma GCC diagnostic pop
    }
  };

  kj::ForkedPromise<void> setupPromise;

  kj::Maybe<kj::Own<ClientContext>> clientContext;
  // Filled in before `setupPromise` resolves.

  Impl(kj::StringPtr serverAddress, uint defaultPort,
       ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(context->getIoProvider().getNetwork()
            .parseAddress(serverAddress, defaultPort)
            .then([readerOpts](kj::Own<kj::NetworkAddress>&& addr) {
              return connectAttach(kj::mv(addr));
            }).then([this, readerOpts](kj::Own<kj::AsyncIoStream>&& stream) {
              clientContext = kj::heap<ClientContext>(kj::mv(stream),
                                                      readerOpts);
            }).fork()) {}

  Impl(const struct sockaddr* serverAddress, uint addrSize,
       ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(
            connectAttach(context->getIoProvider().getNetwork()
                .getSockaddr(serverAddress, addrSize))
            .then([this, readerOpts](kj::Own<kj::AsyncIoStream>&& stream) {
              clientContext = kj::heap<ClientContext>(kj::mv(stream),
                                                      readerOpts);
            }).fork()) {}

  Impl(int socketFd, ReaderOptions readerOpts)
      : context(EzRpcContext::getThreadLocal()),
        setupPromise(kj::Promise<void>(kj::READY_NOW).fork()),
        clientContext(kj::heap<ClientContext>(
            context->getLowLevelIoProvider().wrapSocketFd(socketFd),
            readerOpts)) {}
};

EzRpcClient::EzRpcClient(kj::StringPtr serverAddress, uint defaultPort, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(serverAddress, defaultPort, readerOpts)) {}

EzRpcClient::EzRpcClient(const struct sockaddr* serverAddress, uint addrSize, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(serverAddress, addrSize, readerOpts)) {}

EzRpcClient::EzRpcClient(int socketFd, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(socketFd, readerOpts)) {}

EzRpcClient::~EzRpcClient() noexcept(false) {}

Capability::Client EzRpcClient::getMain() {
  KJ_IF_MAYBE(client, impl->clientContext) {
    return client->get()->getMain();
  } else {
    return impl->setupPromise.addBranch().then([this]() {
      return KJ_ASSERT_NONNULL(impl->clientContext)->getMain();
    });
  }
}

Capability::Client EzRpcClient::importCap(kj::StringPtr name) {
  KJ_IF_MAYBE(client, impl->clientContext) {
    return client->get()->restore(name);
  } else {
    return impl->setupPromise.addBranch().then(kj::mvCapture(kj::heapString(name),
        [this](kj::String&& name) {
      return KJ_ASSERT_NONNULL(impl->clientContext)->restore(name);
    }));
  }
}

kj::WaitScope& EzRpcClient::getWaitScope() {
  return impl->context->getWaitScope();
}

kj::AsyncIoProvider& EzRpcClient::getIoProvider() {
  return impl->context->getIoProvider();
}

kj::LowLevelAsyncIoProvider& EzRpcClient::getLowLevelIoProvider() {
  return impl->context->getLowLevelIoProvider();
}

// =======================================================================================

struct EzRpcServer::Impl final: public SturdyRefRestorer<AnyPointer>,
                                public kj::TaskSet::ErrorHandler {
  Capability::Client mainInterface;
  kj::Own<EzRpcContext> context;

  struct ExportedCap {
    kj::String name;
    Capability::Client cap = nullptr;

    ExportedCap(kj::StringPtr name, Capability::Client cap)
        : name(kj::heapString(name)), cap(cap) {}

    ExportedCap() = default;
    ExportedCap(const ExportedCap&) = delete;
    ExportedCap(ExportedCap&&) = default;
    ExportedCap& operator=(const ExportedCap&) = delete;
    ExportedCap& operator=(ExportedCap&&) = default;
    // Make std::map happy...
  };

  std::map<kj::StringPtr, ExportedCap> exportMap;

  kj::ForkedPromise<uint> portPromise;

  kj::TaskSet tasks;

  struct ServerContext {
    kj::Own<kj::AsyncIoStream> stream;
    TwoPartyVatNetwork network;
    RpcSystem<rpc::twoparty::VatId> rpcSystem;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
    ServerContext(kj::Own<kj::AsyncIoStream>&& stream, SturdyRefRestorer<AnyPointer>& restorer,
                  ReaderOptions readerOpts)
        : stream(kj::mv(stream)),
          network(*this->stream, rpc::twoparty::Side::SERVER, readerOpts),
          rpcSystem(makeRpcServer(network, restorer)) {}
#pragma GCC diagnostic pop
  };

  Impl(Capability::Client mainInterface, kj::StringPtr bindAddress, uint defaultPort,
       ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) {
    auto paf = kj::newPromiseAndFulfiller<uint>();
    portPromise = paf.promise.fork();

    tasks.add(context->getIoProvider().getNetwork().parseAddress(bindAddress, defaultPort)
        .then(kj::mvCapture(paf.fulfiller,
          [this, readerOpts](kj::Own<kj::PromiseFulfiller<uint>>&& portFulfiller,
                             kj::Own<kj::NetworkAddress>&& addr) {
      auto listener = addr->listen();
      portFulfiller->fulfill(listener->getPort());
      acceptLoop(kj::mv(listener), readerOpts);
    })));
  }

  Impl(Capability::Client mainInterface, struct sockaddr* bindAddress, uint addrSize,
       ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()), portPromise(nullptr), tasks(*this) {
    auto listener = context->getIoProvider().getNetwork()
        .getSockaddr(bindAddress, addrSize)->listen();
    portPromise = kj::Promise<uint>(listener->getPort()).fork();
    acceptLoop(kj::mv(listener), readerOpts);
  }

  Impl(Capability::Client mainInterface, int socketFd, uint port, ReaderOptions readerOpts)
      : mainInterface(kj::mv(mainInterface)),
        context(EzRpcContext::getThreadLocal()),
        portPromise(kj::Promise<uint>(port).fork()),
        tasks(*this) {
    acceptLoop(context->getLowLevelIoProvider().wrapListenSocketFd(socketFd), readerOpts);
  }

  void acceptLoop(kj::Own<kj::ConnectionReceiver>&& listener, ReaderOptions readerOpts) {
    auto ptr = listener.get();
    tasks.add(ptr->accept().then(kj::mvCapture(kj::mv(listener),
        [this, readerOpts](kj::Own<kj::ConnectionReceiver>&& listener,
                           kj::Own<kj::AsyncIoStream>&& connection) {
      acceptLoop(kj::mv(listener), readerOpts);

      auto server = kj::heap<ServerContext>(kj::mv(connection), *this, readerOpts);

      // Arrange to destroy the server context when all references are gone, or when the
      // EzRpcServer is destroyed (which will destroy the TaskSet).
      tasks.add(server->network.onDisconnect().attach(kj::mv(server)));
    })));
  }

  Capability::Client restore(AnyPointer::Reader objectId) override {
    if (objectId.isNull()) {
      return mainInterface;
    } else {
      auto name = objectId.getAs<Text>();
      auto iter = exportMap.find(name);
      if (iter == exportMap.end()) {
        KJ_FAIL_REQUIRE("Server exports no such capability.", name) { break; }
        return nullptr;
      } else {
        return iter->second.cap;
      }
    }
  }

  void taskFailed(kj::Exception&& exception) override {
    kj::throwFatalException(kj::mv(exception));
  }
};

EzRpcServer::EzRpcServer(Capability::Client mainInterface, kj::StringPtr bindAddress,
                         uint defaultPort, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), bindAddress, defaultPort, readerOpts)) {}

EzRpcServer::EzRpcServer(Capability::Client mainInterface, struct sockaddr* bindAddress,
                         uint addrSize, ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), bindAddress, addrSize, readerOpts)) {}

EzRpcServer::EzRpcServer(Capability::Client mainInterface, int socketFd, uint port,
                         ReaderOptions readerOpts)
    : impl(kj::heap<Impl>(kj::mv(mainInterface), socketFd, port, readerOpts)) {}

EzRpcServer::EzRpcServer(kj::StringPtr bindAddress, uint defaultPort,
                         ReaderOptions readerOpts)
    : EzRpcServer(nullptr, bindAddress, defaultPort, readerOpts) {}

EzRpcServer::EzRpcServer(struct sockaddr* bindAddress, uint addrSize,
                         ReaderOptions readerOpts)
    : EzRpcServer(nullptr, bindAddress, addrSize, readerOpts) {}

EzRpcServer::EzRpcServer(int socketFd, uint port, ReaderOptions readerOpts)
    : EzRpcServer(nullptr, socketFd, port, readerOpts) {}

EzRpcServer::~EzRpcServer() noexcept(false) {}

void EzRpcServer::exportCap(kj::StringPtr name, Capability::Client cap) {
  Impl::ExportedCap entry(kj::heapString(name), cap);
  impl->exportMap[entry.name] = kj::mv(entry);
}

kj::Promise<uint> EzRpcServer::getPort() {
  return impl->portPromise.addBranch();
}

kj::WaitScope& EzRpcServer::getWaitScope() {
  return impl->context->getWaitScope();
}

kj::AsyncIoProvider& EzRpcServer::getIoProvider() {
  return impl->context->getIoProvider();
}

kj::LowLevelAsyncIoProvider& EzRpcServer::getLowLevelIoProvider() {
  return impl->context->getLowLevelIoProvider();
}

}  // namespace capnp
<|endoftext|>


<commit_before>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/
#include <mitkContourModel.h>

mitk::ContourModel::ContourModel()
{
  this->m_Contour = mitk::ContourModelElement::New();
  m_SelectedVertex = NULL;
}

mitk::ContourModel::ContourModel(const mitk::ContourModel &other) :
m_Contour(other.m_Contour)
{
  m_SelectedVertex = NULL;
}

mitk::ContourModel::~ContourModel()
{
  m_SelectedVertex = NULL;
  this->m_Contour = NULL;
}

bool mitk::ContourModel::SelectVertexAt(int index)
{
  if(index < 0 || index > this->m_Contour->GetSize())
    return false;

  this->m_SelectedVertex = this->m_Contour->GetVertexAt(index);

  return true;
}

bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps)
{
  this->m_SelectedVertex = this->m_Contour->GetVertexAt(point, eps);
  return this->m_SelectedVertex != NULL;
}

bool mitk::ContourModel::RemoveVertexAt(int index)
{
  if(index < 0 || index > this->m_Contour->GetSize())
    return false;

  this->m_Contour->RemoveVertexAt(index);

  return true;
}

bool mitk::ContourModel::RemoveVertexAt(mitk::Point3D &point, float eps)
{
  return this->m_Contour->RemoveVertexAt(point, eps);
}

void mitk::ContourModel::MoveSelectedVertex(mitk::Vector3D &translate)
{
  if(this->m_SelectedVertex)
  {
    this->MoveVertex(this->m_SelectedVertex,translate);
  }
}

void mitk::ContourModel::MoveContour(mitk::Vector3D &translate)
{
  VertexListType* vList = this->m_Contour->GetVertexList();
  VertexIterator it = vList->begin();
  VertexIterator end = vList->end();

  while(it != end)
  {
    this->MoveVertex((*it),translate);
    it++;
  }

}

void mitk::ContourModel::MoveVertex(VertexType* vertex, mitk::Vector3D &vector)
{
  vertex->Coordinates[0] += vector[0];
  vertex->Coordinates[1] += vector[1];
  vertex->Coordinates[2] += vector[2];
}

void mitk::ContourModel::SetRequestedRegionToLargestPossibleRegion ()
{

}

bool mitk::ContourModel::RequestedRegionIsOutsideOfTheBufferedRegion ()
{
  return NULL;
}

bool mitk::ContourModel::VerifyRequestedRegion ()
{
  return NULL;
}

const mitk::Geometry3D * mitk::ContourModel::GetUpdatedGeometry (int t)
{
  return NULL;
}

mitk::Geometry3D* mitk::ContourModel::GetGeometry (int t)const
{
  return NULL;
}

void mitk::ContourModel::SetRequestedRegion (itk::DataObject *data)
{

}<commit_msg>init timestep<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

===================================================================*/
#include <mitkContourModel.h>

mitk::ContourModel::ContourModel()
{
  this->m_Contour = mitk::ContourModelElement::New();
  Superclass::InitializeTimeSlicedGeometry(1);
  m_SelectedVertex = NULL;
}

mitk::ContourModel::ContourModel(const mitk::ContourModel &other) :
m_Contour(other.m_Contour)
{
  m_SelectedVertex = NULL;
}

mitk::ContourModel::~ContourModel()
{
  m_SelectedVertex = NULL;
  this->m_Contour = NULL;
}

bool mitk::ContourModel::SelectVertexAt(int index)
{
  if(index < 0 || index > this->m_Contour->GetSize())
    return false;

  this->m_SelectedVertex = this->m_Contour->GetVertexAt(index);

  return true;
}

bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps)
{
  this->m_SelectedVertex = this->m_Contour->GetVertexAt(point, eps);
  return this->m_SelectedVertex != NULL;
}

bool mitk::ContourModel::RemoveVertexAt(int index)
{
  if(index < 0 || index > this->m_Contour->GetSize())
    return false;

  this->m_Contour->RemoveVertexAt(index);

  return true;
}

bool mitk::ContourModel::RemoveVertexAt(mitk::Point3D &point, float eps)
{
  return this->m_Contour->RemoveVertexAt(point, eps);
}

void mitk::ContourModel::MoveSelectedVertex(mitk::Vector3D &translate)
{
  if(this->m_SelectedVertex)
  {
    this->MoveVertex(this->m_SelectedVertex,translate);
  }
}

void mitk::ContourModel::MoveContour(mitk::Vector3D &translate)
{
  VertexListType* vList = this->m_Contour->GetVertexList();
  VertexIterator it = vList->begin();
  VertexIterator end = vList->end();

  while(it != end)
  {
    this->MoveVertex((*it),translate);
    it++;
  }

}

void mitk::ContourModel::MoveVertex(VertexType* vertex, mitk::Vector3D &vector)
{
  vertex->Coordinates[0] += vector[0];
  vertex->Coordinates[1] += vector[1];
  vertex->Coordinates[2] += vector[2];
}

void mitk::ContourModel::SetRequestedRegionToLargestPossibleRegion ()
{

}

bool mitk::ContourModel::RequestedRegionIsOutsideOfTheBufferedRegion ()
{
  return false;
}

bool mitk::ContourModel::VerifyRequestedRegion ()
{
  return true;
}

const mitk::Geometry3D * mitk::ContourModel::GetUpdatedGeometry (int t)
{
  return NULL;
}

mitk::Geometry3D* mitk::ContourModel::GetGeometry (int t)const
{
  return NULL;
}

void mitk::ContourModel::SetRequestedRegion (itk::DataObject *data)
{

}<|endoftext|>


<commit_before>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

//===--- FusionOfTensorsOps.cpp - Pass to fuse operations on tensors-------===//
//
// Pass to fuse operations on tensors after conversion to Linalg. Uses the
// patterns from MLIR for fusion linalg operations on tensors, and a few
// patterns to fuse these with IREE specific operations.
//
//===----------------------------------------------------------------------===//

#include "iree/compiler/Dialect/Flow/Transforms/PassDetail.h"
#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"

static llvm::cl::opt<bool> clEnableFusionWithReductionOps(
    "iree-enable-fusion-with-reduction-ops",
    llvm::cl::desc("Allow fusing generic ops with reductions"),
    llvm::cl::init(false));

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace Flow {

namespace {

using linalg::LinalgOp;

/// Pass to fuse linalg on tensor operations as well as fusion of hal.interface*
/// operations with linalg.tensor_reshape operation.
struct FusionOfTensorOpsPass
    : public FusionOfTensorOpsBase<FusionOfTensorOpsPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<AffineDialect, linalg::LinalgDialect>();
  }

  void runOnOperation() override {
    OwningRewritePatternList fusionPatterns(&getContext());
    OwningRewritePatternList interfacePatterns(&getContext());
    Operation *op = getOperation();
    MLIRContext *context = op->getContext();

    // Only fuse operations where all uses of the producer are generic
    // operations. If an operation is used in a named op, it will be computed
    // anyway, so the consumers can just use that value.
    linalg::ControlElementwiseOpsFusionFn controlFn =
        [](const OpResult &producer, const OpOperand &consumer) {
          // TODO(GH-5611): Enable fusion with reduction consumer for all
          // targets. Currently vectorization doesn't handle generic ops with
          // reduction iterators we will disable for now to allow vectorizing
          // producer pointwise ops to avoid performance regressions on CPU.
          if (!clEnableFusionWithReductionOps) {
            auto consumerOp = consumer.getOwner();
            if (isa<linalg::GenericOp>(consumerOp) &&
                dyn_cast<LinalgOp>(consumerOp).getNumReductionLoops()) {
              return false;
            }
          }

          // Limit the number of operands. We have hard limit (32) of bindings
          // passing down to HAL. Set the number to be as same as the limit --
          // IREE_HAL_MODULE_MAX_DESCRIPTOR_BINDING_COUNT.
          constexpr int64_t kIreeMaxOperandCount = 32;
          auto numOperands = producer.getOwner()->getNumOperands() +
                             consumer.getOwner()->getNumOperands() - 1;
          if (numOperands >= kIreeMaxOperandCount) return false;

          llvm::SmallDenseSet<Operation *, 4> numUsers;
          for (Operation *user : producer.getUsers()) {
            if (isa<linalg::GenericOp>(user)) continue;
            numUsers.insert(user);
          }
          return numUsers.empty();
        };
    // Simple heuristic to decide if reshaope should be folded in the linalg.
    // If the source of the reshape is a linalg op fold to potentially allow the
    // two linalg ops to be fused. Otherwise leave it to avoid adding dimensions
    // to the consumer linalg op.
    linalg::ControlElementwiseOpsFusionFn foldReshapeBetweenLinalgFn =
        [](const OpResult &producer, const OpOperand &consumer) {
          auto collapseOp =
              producer.getDefiningOp<linalg::TensorCollapseShapeOp>();
          if (collapseOp)
            return collapseOp.src().getDefiningOp<LinalgOp>() != nullptr;
          auto expandOp = producer.getDefiningOp<linalg::TensorExpandShapeOp>();
          if (expandOp)
            return expandOp.src().getDefiningOp<LinalgOp>() != nullptr;
          return false;
        };
    linalg::populateElementwiseOpsFusionPatterns(
        fusionPatterns,
        linalg::LinalgElementwiseFusionOptions()
            .setControlFoldingReshapes(foldReshapeBetweenLinalgFn)
            .setControlElementwiseOpsFusionFn(controlFn));

    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(fusionPatterns));

    OwningRewritePatternList reshapeCanonicalizations(&getContext());
    linalg::populateFoldUnitDimsReshapeOpsByLinearizationPatterns(
        reshapeCanonicalizations);
    linalg::TensorCollapseShapeOp::getCanonicalizationPatterns(
        reshapeCanonicalizations, context);
    linalg::TensorExpandShapeOp::getCanonicalizationPatterns(
        reshapeCanonicalizations, context);
    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(reshapeCanonicalizations));

    // Push the remaining reshapes down the graphs.
    OwningRewritePatternList pushReshapePatterns(&getContext());
    linalg::populatePushReshapeOpsPatterns(pushReshapePatterns);
    linalg::TensorCollapseShapeOp::getCanonicalizationPatterns(
        pushReshapePatterns, context);
    linalg::TensorExpandShapeOp::getCanonicalizationPatterns(
        pushReshapePatterns, context);
    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(pushReshapePatterns));
  }
};

}  // namespace

std::unique_ptr<Pass> createFusionOfTensorOpsPass() {
  return std::make_unique<FusionOfTensorOpsPass>();
}

}  // namespace Flow
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<commit_msg>Considering duplicate operands in Linalg fusion. (#6644)<commit_after>// Copyright 2020 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

//===--- FusionOfTensorsOps.cpp - Pass to fuse operations on tensors-------===//
//
// Pass to fuse operations on tensors after conversion to Linalg. Uses the
// patterns from MLIR for fusion linalg operations on tensors, and a few
// patterns to fuse these with IREE specific operations.
//
//===----------------------------------------------------------------------===//

#include "iree/compiler/Dialect/Flow/Transforms/PassDetail.h"
#include "iree/compiler/Dialect/Flow/Transforms/Passes.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Linalg/IR/LinalgOps.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"

static llvm::cl::opt<bool> clEnableFusionWithReductionOps(
    "iree-enable-fusion-with-reduction-ops",
    llvm::cl::desc("Allow fusing generic ops with reductions"),
    llvm::cl::init(false));

namespace mlir {
namespace iree_compiler {
namespace IREE {
namespace Flow {

namespace {

using linalg::LinalgOp;

/// Pass to fuse linalg on tensor operations as well as fusion of hal.interface*
/// operations with linalg.tensor_reshape operation.
struct FusionOfTensorOpsPass
    : public FusionOfTensorOpsBase<FusionOfTensorOpsPass> {
  void getDependentDialects(DialectRegistry &registry) const override {
    registry.insert<AffineDialect, linalg::LinalgDialect>();
  }

  void runOnOperation() override {
    OwningRewritePatternList fusionPatterns(&getContext());
    OwningRewritePatternList interfacePatterns(&getContext());
    Operation *op = getOperation();
    MLIRContext *context = op->getContext();

    // Only fuse operations where all uses of the producer are generic
    // operations. If an operation is used in a named op, it will be computed
    // anyway, so the consumers can just use that value.
    linalg::ControlElementwiseOpsFusionFn controlFn =
        [](const OpResult &producer, OpOperand &consumer) {
          // TODO(GH-5611): Enable fusion with reduction consumer for all
          // targets. Currently vectorization doesn't handle generic ops with
          // reduction iterators we will disable for now to allow vectorizing
          // producer pointwise ops to avoid performance regressions on CPU.
          if (!clEnableFusionWithReductionOps) {
            auto consumerOp = consumer.getOwner();
            if (isa<linalg::GenericOp>(consumerOp) &&
                dyn_cast<LinalgOp>(consumerOp).getNumReductionLoops()) {
              return false;
            }
          }

          // Limit the number of operands. We have hard limit (32) of bindings
          // passing down to HAL. Set the number to be as same as the limit --
          // IREE_HAL_MODULE_MAX_DESCRIPTOR_BINDING_COUNT.
          constexpr int64_t kIreeMaxOperandCount = 32;
          DenseSet<Value> operands;
          operands.insert(producer.getOwner()->operand_begin(),
                          producer.getOwner()->operand_end());
          operands.insert(consumer.getOwner()->operand_begin(),
                          std::next(consumer.getOwner()->operand_begin(),
                                    consumer.getOperandNumber()));
          operands.insert(std::next(consumer.getOwner()->operand_begin(),
                                    consumer.getOperandNumber() + 1),
                          consumer.getOwner()->operand_end());
          if (operands.size() >= kIreeMaxOperandCount) return false;

          llvm::SmallDenseSet<Operation *, 4> numUsers;
          for (Operation *user : producer.getUsers()) {
            if (isa<linalg::GenericOp>(user)) continue;
            numUsers.insert(user);
          }
          return numUsers.empty();
        };
    // Simple heuristic to decide if reshaope should be folded in the linalg.
    // If the source of the reshape is a linalg op fold to potentially allow the
    // two linalg ops to be fused. Otherwise leave it to avoid adding dimensions
    // to the consumer linalg op.
    linalg::ControlElementwiseOpsFusionFn foldReshapeBetweenLinalgFn =
        [](const OpResult &producer, const OpOperand &consumer) {
          auto collapseOp =
              producer.getDefiningOp<linalg::TensorCollapseShapeOp>();
          if (collapseOp)
            return collapseOp.src().getDefiningOp<LinalgOp>() != nullptr;
          auto expandOp = producer.getDefiningOp<linalg::TensorExpandShapeOp>();
          if (expandOp)
            return expandOp.src().getDefiningOp<LinalgOp>() != nullptr;
          return false;
        };
    linalg::populateElementwiseOpsFusionPatterns(
        fusionPatterns,
        linalg::LinalgElementwiseFusionOptions()
            .setControlFoldingReshapes(foldReshapeBetweenLinalgFn)
            .setControlElementwiseOpsFusionFn(controlFn));

    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(fusionPatterns));

    OwningRewritePatternList reshapeCanonicalizations(&getContext());
    linalg::populateFoldUnitDimsReshapeOpsByLinearizationPatterns(
        reshapeCanonicalizations);
    linalg::TensorCollapseShapeOp::getCanonicalizationPatterns(
        reshapeCanonicalizations, context);
    linalg::TensorExpandShapeOp::getCanonicalizationPatterns(
        reshapeCanonicalizations, context);
    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(reshapeCanonicalizations));

    // Push the remaining reshapes down the graphs.
    OwningRewritePatternList pushReshapePatterns(&getContext());
    linalg::populatePushReshapeOpsPatterns(pushReshapePatterns);
    linalg::TensorCollapseShapeOp::getCanonicalizationPatterns(
        pushReshapePatterns, context);
    linalg::TensorExpandShapeOp::getCanonicalizationPatterns(
        pushReshapePatterns, context);
    (void)applyPatternsAndFoldGreedily(op->getRegions(),
                                       std::move(pushReshapePatterns));
  }
};

}  // namespace

std::unique_ptr<Pass> createFusionOfTensorOpsPass() {
  return std::make_unique<FusionOfTensorOpsPass>();
}

}  // namespace Flow
}  // namespace IREE
}  // namespace iree_compiler
}  // namespace mlir
<|endoftext|>


<commit_before>/**
* SimpleTruthValue.cc
*
* @author Guilherme Lamacie
* @author Welter Silva
*/
#include "SimpleTruthValue.h"
#include "exceptions.h"
#include <math.h>

#define KKK 800.0f

SimpleTruthValue::SimpleTruthValue(float m, float c){
    mean = m;
    count = c;
}

SimpleTruthValue::SimpleTruthValue(SimpleTruthValue const& source) {
    mean = source.mean;
    count = source.count;
}

void SimpleTruthValue::setMean(float m){
    mean = m;
}

void SimpleTruthValue::setCount(float c){
    count = c;
}

void SimpleTruthValue::setConfidence(float c){
    count = confidenceToCount(c);
}

float SimpleTruthValue::getMean() const{
    return mean;
}

float SimpleTruthValue::getCount() const{
    return count;
}

float SimpleTruthValue::getConfidence() const{
    return countToConfidence(count);
}

float SimpleTruthValue::toFloat() const{
    return getMean();
}

std::string SimpleTruthValue::toString() const{
    char buf[1024];
    // TODO: confidence is not needed for Saving&Loading. So, for saving memory space
    // in dump files, it should be removed. However, toString is being used for debug
    // purposes...
    sprintf(buf, "[%f,%f=%f]", getMean(), getCount(),getConfidence());
    return buf;
}

SimpleTruthValue* SimpleTruthValue::clone() const {
    return new SimpleTruthValue(*this);
}

SimpleTruthValue& SimpleTruthValue::operator=(const TruthValue& rhs) throw (RuntimeException) {
    const SimpleTruthValue* tv = dynamic_cast<const SimpleTruthValue*>(&rhs);
    if (tv) {
        if (tv != this) { // check if this is the same object first.
            mean = tv->mean;
            count = tv->count;
        }
    } else {
#if 0
		// The following line was causing a compilation error on MSVC...
        throw RuntimeException(TRACE_INFO, "Cannot assign a TV of type '%s' to one of type '%s'\n",
                                    typeid(rhs).name(), typeid(*this).name());
#else
        throw RuntimeException(TRACE_INFO,
                "SimpleTruthValue - Invalid assignment of a SimpleTV object.");
#endif

    }
    return *this;
}

TruthValueType SimpleTruthValue::getType() const{
    return SIMPLE_TRUTH_VALUE;
}

float SimpleTruthValue::confidenceToCount(float c) {
	c = min(c, 0.9999999f);
	return -KKK*c/(c-1);
}

float SimpleTruthValue::countToConfidence(float c) {
    return (c/(c+KKK));
}

SimpleTruthValue* SimpleTruthValue::fromString(const char* tvStr) {
    float mean, count, conf;
    // TODO: confidence is not needed for Saving&Loading. So, for saving memory space
    // in dump files, it should be removed. However, toString is being used for debug
    // purposes...
    sscanf(tvStr, "[%f,%f=%f]", &mean, &count,&conf);
    //printf("SimpleTruthValue::fromString(%s) => mean = %f, count = %f, conf = %f\n", tvStr, mean, count, conf);
    return new SimpleTruthValue(mean, count);
}
<commit_msg>eliminate spurious minus sign.<commit_after>/**
* SimpleTruthValue.cc
*
* @author Guilherme Lamacie
* @author Welter Silva
*/
#include "SimpleTruthValue.h"
#include "exceptions.h"
#include <math.h>

#define KKK 800.0f

SimpleTruthValue::SimpleTruthValue(float m, float c){
    mean = m;
    count = c;
}

SimpleTruthValue::SimpleTruthValue(SimpleTruthValue const& source) {
    mean = source.mean;
    count = source.count;
}

void SimpleTruthValue::setMean(float m){
    mean = m;
}

void SimpleTruthValue::setCount(float c){
    count = c;
}

void SimpleTruthValue::setConfidence(float c){
    count = confidenceToCount(c);
}

float SimpleTruthValue::getMean() const{
    return mean;
}

float SimpleTruthValue::getCount() const{
    return count;
}

float SimpleTruthValue::getConfidence() const{
    return countToConfidence(count);
}

float SimpleTruthValue::toFloat() const{
    return getMean();
}

std::string SimpleTruthValue::toString() const{
    char buf[1024];
    // TODO: confidence is not needed for Saving&Loading. So, for saving memory space
    // in dump files, it should be removed. However, toString is being used for debug
    // purposes...
    sprintf(buf, "[%f,%f=%f]", getMean(), getCount(),getConfidence());
    return buf;
}

SimpleTruthValue* SimpleTruthValue::clone() const {
    return new SimpleTruthValue(*this);
}

SimpleTruthValue& SimpleTruthValue::operator=(const TruthValue& rhs) throw (RuntimeException) {
    const SimpleTruthValue* tv = dynamic_cast<const SimpleTruthValue*>(&rhs);
    if (tv) {
        if (tv != this) { // check if this is the same object first.
            mean = tv->mean;
            count = tv->count;
        }
    } else {
#if 0
		// The following line was causing a compilation error on MSVC...
        throw RuntimeException(TRACE_INFO, "Cannot assign a TV of type '%s' to one of type '%s'\n",
                                    typeid(rhs).name(), typeid(*this).name());
#else
        throw RuntimeException(TRACE_INFO,
                "SimpleTruthValue - Invalid assignment of a SimpleTV object.");
#endif

    }
    return *this;
}

TruthValueType SimpleTruthValue::getType() const{
    return SIMPLE_TRUTH_VALUE;
}

float SimpleTruthValue::confidenceToCount(float c) {
	c = min(c, 0.9999999f);
	return KKK*c/(1.0-c);
}

float SimpleTruthValue::countToConfidence(float c) {
    return (c/(c+KKK));
}

SimpleTruthValue* SimpleTruthValue::fromString(const char* tvStr) {
    float mean, count, conf;
    // TODO: confidence is not needed for Saving&Loading. So, for saving memory space
    // in dump files, it should be removed. However, toString is being used for debug
    // purposes...
    sscanf(tvStr, "[%f,%f=%f]", &mean, &count,&conf);
    //printf("SimpleTruthValue::fromString(%s) => mean = %f, count = %f, conf = %f\n", tvStr, mean, count, conf);
    return new SimpleTruthValue(mean, count);
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s

template <typename T>
struct a {
};
extern template class a<int>;
// CHECK-NOT: ; [ DW_TAG_structure_type ] [a<int>]

template <typename T>
struct b {
};
extern template class b<int>;
b<int> bi;
// CHECK: ; [ DW_TAG_structure_type ] [b<int>] {{.*}} [def]

template <typename T>
struct c {
  void f() {}
};
extern template class c<int>;
c<int> ci;
// CHECK: ; [ DW_TAG_structure_type ] [c<int>] {{.*}} [decl]

template <typename T>
struct d {
  void f();
};
extern template class d<int>;
d<int> di;
// CHECK: ; [ DW_TAG_structure_type ] [d<int>] {{.*}} [def]

template <typename T>
struct e {
  void f();
};
template <typename T>
void e<T>::f() {
}
extern template class e<int>;
e<int> ei;
// CHECK: ; [ DW_TAG_structure_type ] [e<int>] {{.*}} [decl]

template <typename T>
struct f {
  void g();
};
extern template class f<int>;
template <typename T>
void f<T>::g() {
}
f<int> fi;
// Is this right? We don't seem to emit a def for 'f<int>::g' (even if it is
// called in this translation unit) so I guess if we're relying on its
// definition to be wherever the explicit instantiation definition is, we can do
// the same for the debug info.
// CHECK: ; [ DW_TAG_structure_type ] [f<int>] {{.*}} [decl]

template <typename T>
struct g {
  void f();
};
template <>
void g<int>::f();
extern template class g<int>;
g<int> gi;
// CHECK: ; [ DW_TAG_structure_type ] [g<int>] {{.*}} [def]

template <typename T>
struct h {
};
template class h<int>;
// CHECK: ; [ DW_TAG_structure_type ] [h<int>] {{.*}} [def]
<commit_msg>Add triple to test.  On Mac OS it was failing to generate debug info which matched the check lines<commit_after>// RUN: %clang_cc1 -S -emit-llvm -g %s -o - -triple=x86_64-unknown-unknown | FileCheck %s

template <typename T>
struct a {
};
extern template class a<int>;
// CHECK-NOT: ; [ DW_TAG_structure_type ] [a<int>]

template <typename T>
struct b {
};
extern template class b<int>;
b<int> bi;
// CHECK: ; [ DW_TAG_structure_type ] [b<int>] {{.*}} [def]

template <typename T>
struct c {
  void f() {}
};
extern template class c<int>;
c<int> ci;
// CHECK: ; [ DW_TAG_structure_type ] [c<int>] {{.*}} [decl]

template <typename T>
struct d {
  void f();
};
extern template class d<int>;
d<int> di;
// CHECK: ; [ DW_TAG_structure_type ] [d<int>] {{.*}} [def]

template <typename T>
struct e {
  void f();
};
template <typename T>
void e<T>::f() {
}
extern template class e<int>;
e<int> ei;
// CHECK: ; [ DW_TAG_structure_type ] [e<int>] {{.*}} [decl]

template <typename T>
struct f {
  void g();
};
extern template class f<int>;
template <typename T>
void f<T>::g() {
}
f<int> fi;
// Is this right? We don't seem to emit a def for 'f<int>::g' (even if it is
// called in this translation unit) so I guess if we're relying on its
// definition to be wherever the explicit instantiation definition is, we can do
// the same for the debug info.
// CHECK: ; [ DW_TAG_structure_type ] [f<int>] {{.*}} [decl]

template <typename T>
struct g {
  void f();
};
template <>
void g<int>::f();
extern template class g<int>;
g<int> gi;
// CHECK: ; [ DW_TAG_structure_type ] [g<int>] {{.*}} [def]

template <typename T>
struct h {
};
template class h<int>;
// CHECK: ; [ DW_TAG_structure_type ] [h<int>] {{.*}} [def]
<|endoftext|>