<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qquickanimatorcontroller_p.h"

#include <private/qquickwindow_p.h>
#include <private/qsgrenderloop_p.h>

#include <private/qanimationgroupjob_p.h>

#include <QtGui/qscreen.h>

QT_BEGIN_NAMESPACE

QQuickAnimatorController::QQuickAnimatorController()
    : window(0)
{
}

QQuickAnimatorController::~QQuickAnimatorController()
{
    qDeleteAll(activeRootAnimations);
}

void QQuickAnimatorController::itemDestroyed(QObject *o)
{
    deletedSinceLastFrame << (QQuickItem *) o;
}

void QQuickAnimatorController::advance()
{
    bool running = false;
    for (QSet<QAbstractAnimationJob *>::const_iterator it = activeRootAnimations.constBegin();
         !running && it != activeRootAnimations.constEnd(); ++it) {
        if ((*it)->isRunning())
            running = true;
    }

    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        if ((*it)->isTransform()) {
            QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it);
            xform->transformHelper()->apply();
        }
    }

    if (running)
        window->update();
}

static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
{
    if (job->isRenderThreadJob()) {
        QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
        if (j->target() && c->deletedSinceLastFrame.contains(j->target()))
            j->targetWasDeleted();
        else
            j->initialize(c);
    } else if (job->isGroup()) {
        QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
        for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
            qquick_initialize_helper(a, c);
    }
}

void QQuickAnimatorController::beforeNodeSync()
{
    // Force a render pass if we are adding new animations
    // so that advance will be called..
    if (starting.size())
        window->update();

    for (int i=0; i<starting.size(); ++i) {
        QAbstractAnimationJob *job = starting.at(i);
        job->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
        qquick_initialize_helper(job, this);
        job->start();
    }
    starting.clear();
    deletedSinceLastFrame.clear();

    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        if ((*it)->isTransform()) {
            QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it);
            xform->transformHelper()->sync();
        }
    }
}

void QQuickAnimatorController::afterNodeSync()
{
    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        if ((*it)->isUniform()) {
            QQuickUniformAnimatorJob *job = static_cast<QQuickUniformAnimatorJob *>(*it);
            job->afterNodeSync();
        }
    }
}

void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job)
{
    mutex.lock();
    starting << job;
    mutex.unlock();
}

void QQuickAnimatorController::animationsStarted()
{
    window->update();
}

void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
                                                     QAbstractAnimationJob::State newState,
                                                     QAbstractAnimationJob::State)
{
    if (newState == QAbstractAnimationJob::Running)
        activeRootAnimations << job;
    else
        activeRootAnimations.remove(job);
}

bool QQuickAnimatorController::event(QEvent *e)
{
     if ((int) e->type() == StopAnimation) {
        QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
        mutex.lock();
        starting.removeOne(job);
        mutex.unlock();
        job->stop();
        return true;

    } else if ((uint) e->type() == DeleteAnimation) {
        QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
        mutex.lock();
        starting.removeOne(job);
        mutex.unlock();
        job->stop();
        delete job;
        return true;
    }

    return QObject::event(e);
}

QT_END_NAMESPACE
<commit_msg>Fix crash in tst_qmltest with the new animators.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qquickanimatorcontroller_p.h"

#include <private/qquickwindow_p.h>
#include <private/qsgrenderloop_p.h>

#include <private/qanimationgroupjob_p.h>

#include <QtGui/qscreen.h>

QT_BEGIN_NAMESPACE

QQuickAnimatorController::QQuickAnimatorController()
    : window(0)
{
}

QQuickAnimatorController::~QQuickAnimatorController()
{
    qDeleteAll(activeRootAnimations);
}

void QQuickAnimatorController::itemDestroyed(QObject *o)
{
    deletedSinceLastFrame << (QQuickItem *) o;
}

void QQuickAnimatorController::advance()
{
    bool running = false;
    for (QSet<QAbstractAnimationJob *>::const_iterator it = activeRootAnimations.constBegin();
         !running && it != activeRootAnimations.constEnd(); ++it) {
        if ((*it)->isRunning())
            running = true;
    }

    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        QQuickAnimatorJob *job = *it;
        if (job->isTransform() && job->target()) {
            QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it);
            xform->transformHelper()->apply();
        }
    }

    if (running)
        window->update();
}

static void qquick_initialize_helper(QAbstractAnimationJob *job, QQuickAnimatorController *c)
{
    if (job->isRenderThreadJob()) {
        QQuickAnimatorJob *j = static_cast<QQuickAnimatorJob *>(job);
        if (!j->target())
            return;
        else if (c->deletedSinceLastFrame.contains(j->target()))
            j->targetWasDeleted();
        else
            j->initialize(c);
    } else if (job->isGroup()) {
        QAnimationGroupJob *g = static_cast<QAnimationGroupJob *>(job);
        for (QAbstractAnimationJob *a = g->firstChild(); a; a = a->nextSibling())
            qquick_initialize_helper(a, c);
    }
}

void QQuickAnimatorController::beforeNodeSync()
{
    // Force a render pass if we are adding new animations
    // so that advance will be called..
    if (starting.size())
        window->update();

    for (int i=0; i<starting.size(); ++i) {
        QAbstractAnimationJob *job = starting.at(i);
        job->addAnimationChangeListener(this, QAbstractAnimationJob::StateChange);
        qquick_initialize_helper(job, this);
        job->start();
    }
    starting.clear();

    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        QQuickAnimatorJob *job = *it;
        if (!job->target())
            continue;
        else if (deletedSinceLastFrame.contains(job->target()))
            job->targetWasDeleted();
        else if (job->isTransform()) {
            QQuickTransformAnimatorJob *xform = static_cast<QQuickTransformAnimatorJob *>(*it);
            xform->transformHelper()->sync();
        }
    }
    deletedSinceLastFrame.clear();
}

void QQuickAnimatorController::afterNodeSync()
{
    for (QSet<QQuickAnimatorJob *>::const_iterator it = activeLeafAnimations.constBegin();
         it != activeLeafAnimations.constEnd(); ++it) {
        QQuickAnimatorJob *job = *it;
        if (job->isUniform() && job->target()) {
            QQuickUniformAnimatorJob *job = static_cast<QQuickUniformAnimatorJob *>(*it);
            job->afterNodeSync();
        }
    }
}

void QQuickAnimatorController::startAnimation(QAbstractAnimationJob *job)
{
    mutex.lock();
    starting << job;
    mutex.unlock();
}

void QQuickAnimatorController::animationsStarted()
{
    window->update();
}

void QQuickAnimatorController::animationStateChanged(QAbstractAnimationJob *job,
                                                     QAbstractAnimationJob::State newState,
                                                     QAbstractAnimationJob::State)
{
    if (newState == QAbstractAnimationJob::Running)
        activeRootAnimations << job;
    else
        activeRootAnimations.remove(job);
}

bool QQuickAnimatorController::event(QEvent *e)
{
     if ((int) e->type() == StopAnimation) {
        QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
        mutex.lock();
        starting.removeOne(job);
        mutex.unlock();
        job->stop();
        return true;

    } else if ((uint) e->type() == DeleteAnimation) {
        QAbstractAnimationJob *job = static_cast<Event *>(e)->job;
        mutex.lock();
        starting.removeOne(job);
        mutex.unlock();
        job->stop();
        delete job;
        return true;
    }

    return QObject::event(e);
}

QT_END_NAMESPACE
<|endoftext|>


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

#include "base/logging.hh"
#include "systemc/core/process.hh"
#include "systemc/core/scheduler.hh"
#include "systemc/ext/core/sc_main.hh"
#include "systemc/ext/core/sc_process_handle.hh"
#include "systemc/ext/utils/sc_report_handler.hh"

namespace sc_core
{

const char *
sc_unwind_exception::what() const throw()
{
    return _isReset ? "RESET" : "KILL";
}

bool
sc_unwind_exception::is_reset() const
{
    return _isReset;
}

sc_unwind_exception::sc_unwind_exception() : _isReset(false) {}
sc_unwind_exception::sc_unwind_exception(const sc_unwind_exception &e) :
    _isReset(e._isReset)
{}
sc_unwind_exception::~sc_unwind_exception() throw() {}

void
sc_set_location(const char *file, int lineno)
{
    sc_process_b *current = ::sc_gem5::scheduler.current();
    if (!current)
        return;
    current->file = file;
    current->lineno = lineno;
}

sc_process_b *
sc_get_curr_process_handle()
{
    warn("%s not implemented.\n", __PRETTY_FUNCTION__);
    return nullptr;
}

sc_process_handle::sc_process_handle() : _gem5_process(nullptr) {}

sc_process_handle::sc_process_handle(const sc_process_handle &handle) :
    _gem5_process(handle._gem5_process)
{
    if (_gem5_process)
        _gem5_process->incref();
}

sc_process_handle::sc_process_handle(sc_object *obj) :
    _gem5_process(dynamic_cast<::sc_gem5::Process *>(obj))
{
    if (_gem5_process)
        _gem5_process->incref();
}

sc_process_handle::~sc_process_handle()
{
    if (_gem5_process)
        _gem5_process->decref();
}

bool
sc_process_handle::valid() const
{
    return _gem5_process != nullptr;
}

sc_process_handle &
sc_process_handle::operator = (const sc_process_handle &handle)
{
    if (_gem5_process)
        _gem5_process->decref();
    _gem5_process = handle._gem5_process;
    if (_gem5_process)
        _gem5_process->incref();
    return *this;
}

bool
sc_process_handle::operator == (const sc_process_handle &handle) const
{
    return _gem5_process && handle._gem5_process &&
        (_gem5_process == handle._gem5_process);
}

bool
sc_process_handle::operator != (const sc_process_handle &handle) const
{
    return !(handle == *this);
}

bool
sc_process_handle::operator < (const sc_process_handle &other) const
{
    return _gem5_process < other._gem5_process;
}

void
sc_process_handle::swap(sc_process_handle &handle)
{
    ::sc_gem5::Process *temp = handle._gem5_process;
    handle._gem5_process = _gem5_process;
    _gem5_process = temp;
}

const char *
sc_process_handle::name() const
{
    return _gem5_process ? _gem5_process->name() : "";
}

sc_curr_proc_kind
sc_process_handle::proc_kind() const
{
    return _gem5_process ? _gem5_process->procKind() : SC_NO_PROC_;
}

const std::vector<sc_object *> &
sc_process_handle::get_child_objects() const
{
    static const std::vector<sc_object *> empty;
    return _gem5_process ? _gem5_process->get_child_objects() : empty;
}

const std::vector<sc_event *> &
sc_process_handle::get_child_events() const
{
    static const std::vector<sc_event *> empty;
    return _gem5_process ? _gem5_process->get_child_events() : empty;
}

sc_object *
sc_process_handle::get_parent_object() const
{
    return _gem5_process ? _gem5_process->get_parent_object() : nullptr;
}

sc_object *
sc_process_handle::get_process_object() const
{
    return _gem5_process;
}

bool
sc_process_handle::dynamic() const
{
    return _gem5_process ? _gem5_process->dynamic() : false;
}

bool
sc_process_handle::terminated() const
{
    return _gem5_process ? _gem5_process->terminated() : false;
}

const sc_event &
sc_process_handle::terminated_event() const
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "terminated_event()");
        static sc_event non_event;
        return non_event;
    }
    return _gem5_process->terminatedEvent();
}

void
sc_process_handle::suspend(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "suspend()");
        return;
    }
    _gem5_process->suspend(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::resume(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "resume()");
        return;
    }
    _gem5_process->resume(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::disable(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "disable()");
        return;
    }
    _gem5_process->disable(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::enable(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "enable()");
        return;
    }
    _gem5_process->enable(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::kill(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "kill()");
        return;
    }
    _gem5_process->kill(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::reset(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "reset()");
        return;
    }
    _gem5_process->reset(include_descendants == SC_INCLUDE_DESCENDANTS);
}

bool
sc_process_handle::is_unwinding()
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "is_unwinding()");
        return false;
    }
    return _gem5_process->isUnwinding();
}

const sc_event &
sc_process_handle::reset_event() const
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "reset()");
        static sc_event non_event;
        return non_event;
    }
    return _gem5_process->resetEvent();
}

void
sc_process_handle::sync_reset_on(
        sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "sync_reset_on()");
        return;
    }
    _gem5_process->syncResetOn(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::sync_reset_off(
        sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "sync_reset_off()");
        return;
    }
    _gem5_process->syncResetOff(include_descendants == SC_INCLUDE_DESCENDANTS);
}

sc_process_handle
sc_get_current_process_handle()
{
    if (sc_is_running())
        return sc_process_handle(::sc_gem5::scheduler.current());
    else
        return sc_process_handle(::sc_gem5::Process::newest());
}

bool
sc_is_unwinding()
{
    return sc_get_current_process_handle().is_unwinding();
}

bool sc_allow_process_control_corners;

} // namespace sc_core
<commit_msg>systemc: Implement sc_get_curr_process_handle().<commit_after>/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "base/logging.hh"
#include "systemc/core/process.hh"
#include "systemc/core/scheduler.hh"
#include "systemc/ext/core/sc_main.hh"
#include "systemc/ext/core/sc_process_handle.hh"
#include "systemc/ext/utils/sc_report_handler.hh"

namespace sc_core
{

const char *
sc_unwind_exception::what() const throw()
{
    return _isReset ? "RESET" : "KILL";
}

bool
sc_unwind_exception::is_reset() const
{
    return _isReset;
}

sc_unwind_exception::sc_unwind_exception() : _isReset(false) {}
sc_unwind_exception::sc_unwind_exception(const sc_unwind_exception &e) :
    _isReset(e._isReset)
{}
sc_unwind_exception::~sc_unwind_exception() throw() {}

void
sc_set_location(const char *file, int lineno)
{
    sc_process_b *current = ::sc_gem5::scheduler.current();
    if (!current)
        return;
    current->file = file;
    current->lineno = lineno;
}

sc_process_b *
sc_get_curr_process_handle()
{
    return ::sc_gem5::scheduler.current();
}

sc_process_handle::sc_process_handle() : _gem5_process(nullptr) {}

sc_process_handle::sc_process_handle(const sc_process_handle &handle) :
    _gem5_process(handle._gem5_process)
{
    if (_gem5_process)
        _gem5_process->incref();
}

sc_process_handle::sc_process_handle(sc_object *obj) :
    _gem5_process(dynamic_cast<::sc_gem5::Process *>(obj))
{
    if (_gem5_process)
        _gem5_process->incref();
}

sc_process_handle::~sc_process_handle()
{
    if (_gem5_process)
        _gem5_process->decref();
}

bool
sc_process_handle::valid() const
{
    return _gem5_process != nullptr;
}

sc_process_handle &
sc_process_handle::operator = (const sc_process_handle &handle)
{
    if (_gem5_process)
        _gem5_process->decref();
    _gem5_process = handle._gem5_process;
    if (_gem5_process)
        _gem5_process->incref();
    return *this;
}

bool
sc_process_handle::operator == (const sc_process_handle &handle) const
{
    return _gem5_process && handle._gem5_process &&
        (_gem5_process == handle._gem5_process);
}

bool
sc_process_handle::operator != (const sc_process_handle &handle) const
{
    return !(handle == *this);
}

bool
sc_process_handle::operator < (const sc_process_handle &other) const
{
    return _gem5_process < other._gem5_process;
}

void
sc_process_handle::swap(sc_process_handle &handle)
{
    ::sc_gem5::Process *temp = handle._gem5_process;
    handle._gem5_process = _gem5_process;
    _gem5_process = temp;
}

const char *
sc_process_handle::name() const
{
    return _gem5_process ? _gem5_process->name() : "";
}

sc_curr_proc_kind
sc_process_handle::proc_kind() const
{
    return _gem5_process ? _gem5_process->procKind() : SC_NO_PROC_;
}

const std::vector<sc_object *> &
sc_process_handle::get_child_objects() const
{
    static const std::vector<sc_object *> empty;
    return _gem5_process ? _gem5_process->get_child_objects() : empty;
}

const std::vector<sc_event *> &
sc_process_handle::get_child_events() const
{
    static const std::vector<sc_event *> empty;
    return _gem5_process ? _gem5_process->get_child_events() : empty;
}

sc_object *
sc_process_handle::get_parent_object() const
{
    return _gem5_process ? _gem5_process->get_parent_object() : nullptr;
}

sc_object *
sc_process_handle::get_process_object() const
{
    return _gem5_process;
}

bool
sc_process_handle::dynamic() const
{
    return _gem5_process ? _gem5_process->dynamic() : false;
}

bool
sc_process_handle::terminated() const
{
    return _gem5_process ? _gem5_process->terminated() : false;
}

const sc_event &
sc_process_handle::terminated_event() const
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "terminated_event()");
        static sc_event non_event;
        return non_event;
    }
    return _gem5_process->terminatedEvent();
}

void
sc_process_handle::suspend(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "suspend()");
        return;
    }
    _gem5_process->suspend(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::resume(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "resume()");
        return;
    }
    _gem5_process->resume(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::disable(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "disable()");
        return;
    }
    _gem5_process->disable(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::enable(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "enable()");
        return;
    }
    _gem5_process->enable(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::kill(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "kill()");
        return;
    }
    _gem5_process->kill(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::reset(sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "reset()");
        return;
    }
    _gem5_process->reset(include_descendants == SC_INCLUDE_DESCENDANTS);
}

bool
sc_process_handle::is_unwinding()
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "is_unwinding()");
        return false;
    }
    return _gem5_process->isUnwinding();
}

const sc_event &
sc_process_handle::reset_event() const
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "reset()");
        static sc_event non_event;
        return non_event;
    }
    return _gem5_process->resetEvent();
}

void
sc_process_handle::sync_reset_on(
        sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "sync_reset_on()");
        return;
    }
    _gem5_process->syncResetOn(include_descendants == SC_INCLUDE_DESCENDANTS);
}

void
sc_process_handle::sync_reset_off(
        sc_descendent_inclusion_info include_descendants)
{
    if (!_gem5_process) {
        SC_REPORT_WARNING("(W570) attempt to use an empty "
                "process handle ignored", "sync_reset_off()");
        return;
    }
    _gem5_process->syncResetOff(include_descendants == SC_INCLUDE_DESCENDANTS);
}

sc_process_handle
sc_get_current_process_handle()
{
    if (sc_is_running())
        return sc_process_handle(::sc_gem5::scheduler.current());
    else
        return sc_process_handle(::sc_gem5::Process::newest());
}

bool
sc_is_unwinding()
{
    return sc_get_current_process_handle().is_unwinding();
}

bool sc_allow_process_control_corners;

} // namespace sc_core
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.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 "qsystemnetworkinfo.h"
#include "qsysteminfocommon_p.h"
#include <QMetaType>

QTM_BEGIN_NAMESPACE
        Q_GLOBAL_STATIC(QSystemNetworkInfoPrivate, netInfoPrivate)

#ifdef QT_SIMULATOR
QSystemNetworkInfoPrivate *getSystemNetworkInfoPrivate() { return netInfoPrivate(); }
#endif

/*!
   \class QSystemNetworkInfo
   \ingroup systeminfo
  \inmodule QtSystemInfo

  \brief The QSystemNetworkInfo class provides access to various networking status and signals.

*/

        /*!
            \enum QSystemNetworkInfo::NetworkStatus
            This enum describes the status of the network connection:

            \value UndefinedStatus        There is no network device, or error.
            \value NoNetworkAvailable     There is no network available.
            \value EmergencyOnly          Emergency calls only.
            \value Searching              Searching for or connecting with the network.
            \value Busy                   Network is busy.
            \value Connected              Connected to network.
            \value HomeNetwork            On Home Network.
            \value Denied                 Network access denied.
            \value Roaming                On Roaming network.

          */

/*!
    \enum QSystemNetworkInfo::NetworkMode
    This enum describes the type of network:

    \value UnknownMode             Unknown network, or network error.
    \value GsmMode                 Global System for Mobile (GSM) network.
    \value CdmaMode                Code division multiple access (CDMA) network.
    \value WcdmaMode               Wideband Code Division Multiple Access (W-CDMA) network.
    \value WlanMode                Wireless Local Area Network (WLAN) network.
    \value EthernetMode            Wired Local Area network.
    \value BluetoothMode           Bluetooth network.
    \value WimaxMode               Wimax network.
    \value LteMode                 Lte network.
*/

/*!
    \enum QSystemNetworkInfo::CellDataTechnology
    This enum describes the type of cellular technology:

    \value UnknownDataTechnology   Unknown cellular technology, or error.
    \value GprsDataTechnology      General Packet Radio Service (GPRS) data service.
    \value EdgeDataTechnology      Enhanced Data Rates for GSM Evolution (EDGE) data service.
    \value UmtsDataTechnology      Universal Mobile Telecommunications System (UMTS) data service.
    \value HspaDataTechnology      High Speed Packet Access (HSPA) data service.
*/

        /*!
          \fn void QSystemNetworkInfo::networkStatusChanged(QSystemNetworkInfo::NetworkMode mode, QSystemNetworkInfo::NetworkStatus status)

          This signal is emitted whenever the network status of \a mode changes, specified by \a status.
          */

        /*!
          \fn void QSystemNetworkInfo::networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode mode,int strength)

          This signal is emitted whenever the network \a mode signal strength changes, specified by \a strength.
          */

        /*!
          \fn void QSystemNetworkInfo::currentMobileCountryCodeChanged(const QString &mcc)

          This signal is emitted whenever the Mobile Country Code changes, specified by \a mcc.
        */

        /*!
          \fn void QSystemNetworkInfo::currentMobileNetworkCodeChanged(const QString &mnc)

          This signal is emitted whenever the network Mobile Network Code changes, specified by \a mnc.
        */

        /*!
          \fn void QSystemNetworkInfo::networkNameChanged(QSystemNetworkInfo::NetworkMode mode,const QString & netName)

          This signal is emitted whenever the network \a mode name changes, specified by \a netName.

        */

        /*!
          \fn void QSystemNetworkInfo::cellIdChanged(int cellId)

          This signal is emitted whenever the network cell changes, specified by \a cellId.
        */

/*!
  \fn void QSystemNetworkInfo::networkModeChanged(QSystemNetworkInfo::NetworkMode mode)

  This signal is emitted whenever the network mode changes, specified by \a mode.
*/

/*!
    \fn void QSystemNetworkInfo::cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology cellTech)

    This signal is emitted whenever the cellular technology changes, specified by \a cellTech.
*/

/*!
    Constructs a QSystemNetworkInfo with the given \a parent.
*/
QSystemNetworkInfo::QSystemNetworkInfo(QObject *parent)
   : QObject(parent), d(netInfoPrivate())
{
    qRegisterMetaType<QSystemNetworkInfo::NetworkMode>("QSystemNetworkInfo::NetworkMode");
    qRegisterMetaType<QSystemNetworkInfo::NetworkStatus>("QSystemNetworkInfo::NetworkStatus");
}

/*!
 Destroys the QSystemNetworkInfo object.
*/
QSystemNetworkInfo::~QSystemNetworkInfo()
{
}

/*!
   Returns the status of the network \a mode.
*/
QSystemNetworkInfo::NetworkStatus QSystemNetworkInfo::networkStatus(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->networkStatus(mode);
}

/*!
   Returns the strength of the network signal, per network \a mode , 0 - 100 linear scaling,
   or -1 in the case of unknown network mode or error.

   In the case of QSystemNetworkInfo::EthMode, it will either be 100 for carrier active, or 0 for when
   there is no carrier or cable connected.
*/
int QSystemNetworkInfo::networkSignalStrength(QSystemNetworkInfo::NetworkMode mode)
{
    QSystemNetworkInfo::NetworkStatus info = netInfoPrivate()->networkStatus(mode);
    if(info  == QSystemNetworkInfo::UndefinedStatus
            || info == QSystemNetworkInfo::NoNetworkAvailable) {
        return 0;
    }
    return netInfoPrivate()->networkSignalStrength(mode);
}

/*!
 \property QSystemNetworkInfo::cellId
 \brief The devices Cell ID
   Returns the Cell ID of the connected tower or based station, or 0 if not connected.
*/
int QSystemNetworkInfo::cellId()
{
   return netInfoPrivate()->cellId();
}

/*!
 \property QSystemNetworkInfo::locationAreaCode
 \brief The LAC.

   Returns the Location Area Code. In the case of a Desktop computer, 0 is returned.
*/
int QSystemNetworkInfo::locationAreaCode()
{
   return netInfoPrivate()->locationAreaCode();
}

/*!
  \property QSystemNetworkInfo::currentMobileCountryCode
  \brief The current MCC.

   Returns the current Mobile Country Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::currentMobileCountryCode()
{
   return netInfoPrivate()->currentMobileCountryCode();
}

/*!
 \property QSystemNetworkInfo::currentMobileNetworkCode
 \brief The current MNC.

   Returns the current Mobile Network Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::currentMobileNetworkCode()
{
   return netInfoPrivate()->currentMobileNetworkCode();
}

/*!
 \property QSystemNetworkInfo::homeMobileCountryCode
 \brief The home MNC.

   Returns the home Mobile Country Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::homeMobileCountryCode()
{
   return netInfoPrivate()->homeMobileCountryCode();
}

/*!
 \property QSystemNetworkInfo::homeMobileNetworkCode
 \brief The home MCC.

   Returns the home Mobile Network Code. In the case of a Desktop computer, an empty string is returned.
   Note: Some platforms don't support retrieving this info. In this case the Network Code is
   returned only when the device is registered on home network.
*/
QString QSystemNetworkInfo::homeMobileNetworkCode()
{
   return netInfoPrivate()->homeMobileNetworkCode();
}

/*!
 Returns the name of the operator for the network \a mode.  For wlan this returns the network's current SSID.
In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::networkName(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->networkName(mode);
}

/*!
 Returns the MAC address for the interface servicing the network \a mode.
 */
QString QSystemNetworkInfo::macAddress(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->macAddress(mode);
}

/*!
 Returns the first found QNetworkInterface for type \a mode, or an invalid QNetworkInterface, if none is found.

 */
QNetworkInterface QSystemNetworkInfo::interfaceForMode(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->interfaceForMode(mode);
}

/*!
 \property QSystemNetworkInfo::currentMode

    Returns the current active mode. If more than one mode is active, returns the
     default or preferred mode. If no modes are active, returns UnknownMode.

*/
QSystemNetworkInfo::NetworkMode QSystemNetworkInfo::currentMode()
{
   return netInfoPrivate()->currentMode();
}

/*!
   \internal

   This function is called when the client connects to the networkSignalStrengthChanged()
   signal.
*/
void QSystemNetworkInfo::connectNotify(const char *signal)
{
   //check for networkSignalStrengthChanged() signal connect notification
   //This is not required on all platforms
#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
                                 networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode, int))))) {
        netInfoPrivate()->setWlanSignalStrengthCheckEnabled(true);
    }
#endif
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileCountryCodeChanged(QString))))) {
        connect(d,SIGNAL(currentMobileCountryCodeChanged(QString)),
                this,SIGNAL(currentMobileCountryCodeChanged(QString)));
    }

    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileNetworkCodeChanged(QString))))) {
        connect(d,SIGNAL(currentMobileNetworkCodeChanged(QString)),
                this,SIGNAL(currentMobileNetworkCodeChanged(QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkModeChanged(QSystemNetworkInfo::NetworkMode))))) {
        connect(d,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)),
                this,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkNameChanged(QSystemNetworkInfo::NetworkMode,QString))))) {
        connect(d,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)),
                this,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int))))) {
        connect(d,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)),
                this,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus))))) {
        connect(d,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)),
                this,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        connect(d,SIGNAL(cellIdChanged(int)),this,SIGNAL(cellIdChanged(int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        connect(d,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)),
                this,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)));
    }
}

/*!
   \internal

   This function is called when the client disconnects from the networkSignalStrengthChanged()
   signal.

   \sa connectNotify()
*/
void QSystemNetworkInfo::disconnectNotify(const char *signal)
{
   //check for networkSignalStrengthChanged() signal disconnect notification
   //This is not required on all platforms
#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
                                 networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode, int))))) {
        netInfoPrivate()->setWlanSignalStrengthCheckEnabled(false);
    }
#endif
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileCountryCodeChanged(QString))))) {
        disconnect(d,SIGNAL(currentMobileCountryCodeChanged(QString)),
                this,SIGNAL(currentMobileCountryCodeChanged(QString)));
    }

    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileNetworkCodeChanged(QString))))) {
        disconnect(d,SIGNAL(currentMobileNetworkCodeChanged(QString)),
                this,SIGNAL(currentMobileNetworkCodeChanged(QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkModeChanged(QSystemNetworkInfo::NetworkMode))))) {
        disconnect(d,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)),
                this,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkNameChanged(QSystemNetworkInfo::NetworkMode,QString))))) {
        disconnect(d,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)),
                this,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int))))) {
        disconnect(d,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)),
                this,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus))))) {
        disconnect(d,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)),
                this,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        disconnect(d,SIGNAL(cellIdChanged(int)),this,SIGNAL(cellIdChanged(int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        disconnect(d,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)),
                this,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)));
    }
}

/*!
    \property QSystemNetworkInfo::cellDataTechnology

    Returns the current active cell data technology.

    If no data technology is active, or data technology is not supported, QSystemNetworkInfo::UnknownDataTechnology
    is returned.
*/
QSystemNetworkInfo::CellDataTechnology QSystemNetworkInfo::cellDataTechnology()
{
    return netInfoPrivate()->cellDataTechnology();
}

#include "moc_qsystemnetworkinfo.cpp"

QTM_END_NAMESPACE
<commit_msg>Fix the doc for interfaceForMode().<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.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 "qsystemnetworkinfo.h"
#include "qsysteminfocommon_p.h"
#include <QMetaType>

QTM_BEGIN_NAMESPACE
        Q_GLOBAL_STATIC(QSystemNetworkInfoPrivate, netInfoPrivate)

#ifdef QT_SIMULATOR
QSystemNetworkInfoPrivate *getSystemNetworkInfoPrivate() { return netInfoPrivate(); }
#endif

/*!
   \class QSystemNetworkInfo
   \ingroup systeminfo
  \inmodule QtSystemInfo

  \brief The QSystemNetworkInfo class provides access to various networking status and signals.

*/

        /*!
            \enum QSystemNetworkInfo::NetworkStatus
            This enum describes the status of the network connection:

            \value UndefinedStatus        There is no network device, or error.
            \value NoNetworkAvailable     There is no network available.
            \value EmergencyOnly          Emergency calls only.
            \value Searching              Searching for or connecting with the network.
            \value Busy                   Network is busy.
            \value Connected              Connected to network.
            \value HomeNetwork            On Home Network.
            \value Denied                 Network access denied.
            \value Roaming                On Roaming network.

          */

/*!
    \enum QSystemNetworkInfo::NetworkMode
    This enum describes the type of network:

    \value UnknownMode             Unknown network, or network error.
    \value GsmMode                 Global System for Mobile (GSM) network.
    \value CdmaMode                Code division multiple access (CDMA) network.
    \value WcdmaMode               Wideband Code Division Multiple Access (W-CDMA) network.
    \value WlanMode                Wireless Local Area Network (WLAN) network.
    \value EthernetMode            Wired Local Area network.
    \value BluetoothMode           Bluetooth network.
    \value WimaxMode               Wimax network.
    \value LteMode                 Lte network.
*/

/*!
    \enum QSystemNetworkInfo::CellDataTechnology
    This enum describes the type of cellular technology:

    \value UnknownDataTechnology   Unknown cellular technology, or error.
    \value GprsDataTechnology      General Packet Radio Service (GPRS) data service.
    \value EdgeDataTechnology      Enhanced Data Rates for GSM Evolution (EDGE) data service.
    \value UmtsDataTechnology      Universal Mobile Telecommunications System (UMTS) data service.
    \value HspaDataTechnology      High Speed Packet Access (HSPA) data service.
*/

        /*!
          \fn void QSystemNetworkInfo::networkStatusChanged(QSystemNetworkInfo::NetworkMode mode, QSystemNetworkInfo::NetworkStatus status)

          This signal is emitted whenever the network status of \a mode changes, specified by \a status.
          */

        /*!
          \fn void QSystemNetworkInfo::networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode mode,int strength)

          This signal is emitted whenever the network \a mode signal strength changes, specified by \a strength.
          */

        /*!
          \fn void QSystemNetworkInfo::currentMobileCountryCodeChanged(const QString &mcc)

          This signal is emitted whenever the Mobile Country Code changes, specified by \a mcc.
        */

        /*!
          \fn void QSystemNetworkInfo::currentMobileNetworkCodeChanged(const QString &mnc)

          This signal is emitted whenever the network Mobile Network Code changes, specified by \a mnc.
        */

        /*!
          \fn void QSystemNetworkInfo::networkNameChanged(QSystemNetworkInfo::NetworkMode mode,const QString & netName)

          This signal is emitted whenever the network \a mode name changes, specified by \a netName.

        */

        /*!
          \fn void QSystemNetworkInfo::cellIdChanged(int cellId)

          This signal is emitted whenever the network cell changes, specified by \a cellId.
        */

/*!
  \fn void QSystemNetworkInfo::networkModeChanged(QSystemNetworkInfo::NetworkMode mode)

  This signal is emitted whenever the network mode changes, specified by \a mode.
*/

/*!
    \fn void QSystemNetworkInfo::cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology cellTech)

    This signal is emitted whenever the cellular technology changes, specified by \a cellTech.
*/

/*!
    Constructs a QSystemNetworkInfo with the given \a parent.
*/
QSystemNetworkInfo::QSystemNetworkInfo(QObject *parent)
   : QObject(parent), d(netInfoPrivate())
{
    qRegisterMetaType<QSystemNetworkInfo::NetworkMode>("QSystemNetworkInfo::NetworkMode");
    qRegisterMetaType<QSystemNetworkInfo::NetworkStatus>("QSystemNetworkInfo::NetworkStatus");
}

/*!
 Destroys the QSystemNetworkInfo object.
*/
QSystemNetworkInfo::~QSystemNetworkInfo()
{
}

/*!
   Returns the status of the network \a mode.
*/
QSystemNetworkInfo::NetworkStatus QSystemNetworkInfo::networkStatus(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->networkStatus(mode);
}

/*!
   Returns the strength of the network signal, per network \a mode , 0 - 100 linear scaling,
   or -1 in the case of unknown network mode or error.

   In the case of QSystemNetworkInfo::EthMode, it will either be 100 for carrier active, or 0 for when
   there is no carrier or cable connected.
*/
int QSystemNetworkInfo::networkSignalStrength(QSystemNetworkInfo::NetworkMode mode)
{
    QSystemNetworkInfo::NetworkStatus info = netInfoPrivate()->networkStatus(mode);
    if(info  == QSystemNetworkInfo::UndefinedStatus
            || info == QSystemNetworkInfo::NoNetworkAvailable) {
        return 0;
    }
    return netInfoPrivate()->networkSignalStrength(mode);
}

/*!
 \property QSystemNetworkInfo::cellId
 \brief The devices Cell ID
   Returns the Cell ID of the connected tower or based station, or 0 if not connected.
*/
int QSystemNetworkInfo::cellId()
{
   return netInfoPrivate()->cellId();
}

/*!
 \property QSystemNetworkInfo::locationAreaCode
 \brief The LAC.

   Returns the Location Area Code. In the case of a Desktop computer, 0 is returned.
*/
int QSystemNetworkInfo::locationAreaCode()
{
   return netInfoPrivate()->locationAreaCode();
}

/*!
  \property QSystemNetworkInfo::currentMobileCountryCode
  \brief The current MCC.

   Returns the current Mobile Country Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::currentMobileCountryCode()
{
   return netInfoPrivate()->currentMobileCountryCode();
}

/*!
 \property QSystemNetworkInfo::currentMobileNetworkCode
 \brief The current MNC.

   Returns the current Mobile Network Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::currentMobileNetworkCode()
{
   return netInfoPrivate()->currentMobileNetworkCode();
}

/*!
 \property QSystemNetworkInfo::homeMobileCountryCode
 \brief The home MNC.

   Returns the home Mobile Country Code. In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::homeMobileCountryCode()
{
   return netInfoPrivate()->homeMobileCountryCode();
}

/*!
 \property QSystemNetworkInfo::homeMobileNetworkCode
 \brief The home MCC.

   Returns the home Mobile Network Code. In the case of a Desktop computer, an empty string is returned.
   Note: Some platforms don't support retrieving this info. In this case the Network Code is
   returned only when the device is registered on home network.
*/
QString QSystemNetworkInfo::homeMobileNetworkCode()
{
   return netInfoPrivate()->homeMobileNetworkCode();
}

/*!
 Returns the name of the operator for the network \a mode.  For wlan this returns the network's current SSID.
In the case of a Desktop computer, an empty string is returned.
*/
QString QSystemNetworkInfo::networkName(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->networkName(mode);
}

/*!
 Returns the MAC address for the interface servicing the network \a mode.
 */
QString QSystemNetworkInfo::macAddress(QSystemNetworkInfo::NetworkMode mode)
{
   return netInfoPrivate()->macAddress(mode);
}

/*!
    Returns the first found QNetworkInterface for type \a mode. If none is found, or it can't be represented
    by QNetworkInterface (e.g. Bluetooth), an invalid QNetworkInterface object is returned.
*/
QNetworkInterface QSystemNetworkInfo::interfaceForMode(QSystemNetworkInfo::NetworkMode mode)
{
    return netInfoPrivate()->interfaceForMode(mode);
}

/*!
 \property QSystemNetworkInfo::currentMode

    Returns the current active mode. If more than one mode is active, returns the
     default or preferred mode. If no modes are active, returns UnknownMode.

*/
QSystemNetworkInfo::NetworkMode QSystemNetworkInfo::currentMode()
{
   return netInfoPrivate()->currentMode();
}

/*!
   \internal

   This function is called when the client connects to the networkSignalStrengthChanged()
   signal.
*/
void QSystemNetworkInfo::connectNotify(const char *signal)
{
   //check for networkSignalStrengthChanged() signal connect notification
   //This is not required on all platforms
#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
                                 networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode, int))))) {
        netInfoPrivate()->setWlanSignalStrengthCheckEnabled(true);
    }
#endif
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileCountryCodeChanged(QString))))) {
        connect(d,SIGNAL(currentMobileCountryCodeChanged(QString)),
                this,SIGNAL(currentMobileCountryCodeChanged(QString)));
    }

    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileNetworkCodeChanged(QString))))) {
        connect(d,SIGNAL(currentMobileNetworkCodeChanged(QString)),
                this,SIGNAL(currentMobileNetworkCodeChanged(QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkModeChanged(QSystemNetworkInfo::NetworkMode))))) {
        connect(d,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)),
                this,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkNameChanged(QSystemNetworkInfo::NetworkMode,QString))))) {
        connect(d,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)),
                this,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int))))) {
        connect(d,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)),
                this,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus))))) {
        connect(d,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)),
                this,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        connect(d,SIGNAL(cellIdChanged(int)),this,SIGNAL(cellIdChanged(int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        connect(d,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)),
                this,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)));
    }
}

/*!
   \internal

   This function is called when the client disconnects from the networkSignalStrengthChanged()
   signal.

   \sa connectNotify()
*/
void QSystemNetworkInfo::disconnectNotify(const char *signal)
{
   //check for networkSignalStrengthChanged() signal disconnect notification
   //This is not required on all platforms
#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
                                 networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode, int))))) {
        netInfoPrivate()->setWlanSignalStrengthCheckEnabled(false);
    }
#endif
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileCountryCodeChanged(QString))))) {
        disconnect(d,SIGNAL(currentMobileCountryCodeChanged(QString)),
                this,SIGNAL(currentMobileCountryCodeChanged(QString)));
    }

    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            currentMobileNetworkCodeChanged(QString))))) {
        disconnect(d,SIGNAL(currentMobileNetworkCodeChanged(QString)),
                this,SIGNAL(currentMobileNetworkCodeChanged(QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkModeChanged(QSystemNetworkInfo::NetworkMode))))) {
        disconnect(d,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)),
                this,SIGNAL(networkModeChanged(QSystemNetworkInfo::NetworkMode)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkNameChanged(QSystemNetworkInfo::NetworkMode,QString))))) {
        disconnect(d,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)),
                this,SIGNAL(networkNameChanged(QSystemNetworkInfo::NetworkMode,QString)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int))))) {
        disconnect(d,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)),
                this,SIGNAL(networkSignalStrengthChanged(QSystemNetworkInfo::NetworkMode,int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus))))) {
        disconnect(d,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)),
                this,SIGNAL(networkStatusChanged(QSystemNetworkInfo::NetworkMode,QSystemNetworkInfo::NetworkStatus)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        disconnect(d,SIGNAL(cellIdChanged(int)),this,SIGNAL(cellIdChanged(int)));
    }
    if (QLatin1String(signal) == QLatin1String(QMetaObject::normalizedSignature(SIGNAL(
            cellIdChanged(int))))) {
        disconnect(d,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)),
                this,SIGNAL(cellDataTechnologyChanged(QSystemNetworkInfo::CellDataTechnology)));
    }
}

/*!
    \property QSystemNetworkInfo::cellDataTechnology

    Returns the current active cell data technology.

    If no data technology is active, or data technology is not supported, QSystemNetworkInfo::UnknownDataTechnology
    is returned.
*/
QSystemNetworkInfo::CellDataTechnology QSystemNetworkInfo::cellDataTechnology()
{
    return netInfoPrivate()->cellDataTechnology();
}

#include "moc_qsystemnetworkinfo.cpp"

QTM_END_NAMESPACE
<|endoftext|>


<commit_before>// 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

#ifndef __PROCESS_POSIX_SUBPROCESS_HPP__
#define __PROCESS_POSIX_SUBPROCESS_HPP__

#ifdef __linux__
#include <sys/prctl.h>
#endif // __linux__
#include <sys/types.h>

#include <string>

#include <glog/logging.h>

#include <process/subprocess.hpp>

#include <stout/check.hpp>
#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/hashset.hpp>
#include <stout/nothing.hpp>
#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

#include <stout/os/close.hpp>
#include <stout/os/environment.hpp>
#include <stout/os/fcntl.hpp>
#include <stout/os/signals.hpp>
#include <stout/os/strerror.hpp>

namespace process {
namespace internal {

static void close(std::initializer_list<int_fd> fds);

static void close(
    const Subprocess::IO::InputFileDescriptors& stdinfds,
    const Subprocess::IO::OutputFileDescriptors& stdoutfds,
    const Subprocess::IO::OutputFileDescriptors& stderrfds);

inline pid_t defaultClone(const lambda::function<int()>& func)
{
  pid_t pid = ::fork();
  if (pid == -1) {
    return -1;
  } else if (pid == 0) {
    // Child.
    ::exit(func());
    UNREACHABLE();
  } else {
    // Parent.
    return pid;
  }
}

// This function will invoke `os::cloexec` on all specified file
// descriptors that are valid (i.e., not `None` and >= 0).
inline Try<Nothing> cloexec(
    const InputFileDescriptors& stdinfds,
    const OutputFileDescriptors& stdoutfds,
    const OutputFileDescriptors& stderrfds)
{
  hashset<int> fds = {
    stdinfds.read,
    stdinfds.write.getOrElse(-1),
    stdoutfds.read.getOrElse(-1),
    stdoutfds.write,
    stderrfds.read.getOrElse(-1),
    stderrfds.write
  };

  foreach (int fd, fds) {
    if (fd >= 0) {
      Try<Nothing> cloexec = os::cloexec(fd);
      if (cloexec.isError()) {
        return Error(cloexec.error());
      }
    }
  }

  return Nothing();
}

// The main entry of the child process.
//
// NOTE: This function has to be async signal safe.
inline int childMain(
    const std::string& path,
    char** argv,
    char** envp,
    const InputFileDescriptors& stdinfds,
    const OutputFileDescriptors& stdoutfds,
    const OutputFileDescriptors& stderrfds,
    bool blocking,
    int pipes[2],
    const std::vector<Subprocess::ChildHook>& child_hooks)
{
  // Close parent's end of the pipes.
  if (stdinfds.write.isSome()) {
    ::close(stdinfds.write.get());
  }
  if (stdoutfds.read.isSome()) {
    ::close(stdoutfds.read.get());
  }
  if (stderrfds.read.isSome()) {
    ::close(stderrfds.read.get());
  }

  // Currently we will block the child's execution of the new process
  // until all the parent hooks (if any) have executed.
  if (blocking) {
    ::close(pipes[1]);
  }

  // Redirect I/O for stdin/stdout/stderr.
  while (::dup2(stdinfds.read, STDIN_FILENO) == -1 && errno == EINTR);
  while (::dup2(stdoutfds.write, STDOUT_FILENO) == -1 && errno == EINTR);
  while (::dup2(stderrfds.write, STDERR_FILENO) == -1 && errno == EINTR);

  // Close the copies. We need to make sure that we do not close the
  // file descriptor assigned to stdin/stdout/stderr in case the
  // parent has closed stdin/stdout/stderr when calling this
  // function (in that case, a dup'ed file descriptor may have the
  // same file descriptor number as stdin/stdout/stderr).
  //
  // We also need to ensure that we don't "double close" any file
  // descriptors in the case where one of stdinfds.read,
  // stdoutfds.write, or stdoutfds.write are equal.
  if (stdinfds.read != STDIN_FILENO &&
      stdinfds.read != STDOUT_FILENO &&
      stdinfds.read != STDERR_FILENO) {
    ::close(stdinfds.read);
  }
  if (stdoutfds.write != STDIN_FILENO &&
      stdoutfds.write != STDOUT_FILENO &&
      stdoutfds.write != STDERR_FILENO &&
      stdoutfds.write != stdinfds.read) {
    ::close(stdoutfds.write);
  }
  if (stderrfds.write != STDIN_FILENO &&
      stderrfds.write != STDOUT_FILENO &&
      stderrfds.write != STDERR_FILENO &&
      stderrfds.write != stdinfds.read &&
      stderrfds.write != stdoutfds.write) {
    ::close(stderrfds.write);
  }

  if (blocking) {
    // Do a blocking read on the pipe until the parent signals us to
    // continue.
    char dummy;
    ssize_t length;
    while ((length = ::read(pipes[0], &dummy, sizeof(dummy))) == -1 &&
          errno == EINTR);

    if (length != sizeof(dummy)) {
      ABORT("Failed to synchronize with parent");
    }

    // Now close the pipe as we don't need it anymore.
    ::close(pipes[0]);
  }

  // Run the child hooks.
  foreach (const Subprocess::ChildHook& hook, child_hooks) {
    Try<Nothing> callback = hook();

    // If the callback failed, we should abort execution.
    if (callback.isError()) {
      ABORT("Failed to execute Subprocess::ChildHook: " + callback.error());
    }
  }

  os::execvpe(path.c_str(), argv, envp);

  ABORT("Failed to os::execvpe on path '" + path + "': " + os::strerror(errno));
}

inline Try<pid_t> cloneChild(
    const std::string& path,
    std::vector<std::string> argv,
    const Option<std::map<std::string, std::string>>& environment,
    const Option<lambda::function<
        pid_t(const lambda::function<int()>&)>>& _clone,
    const std::vector<Subprocess::ParentHook>& parent_hooks,
    const std::vector<Subprocess::ChildHook>& child_hooks,
    const InputFileDescriptors stdinfds,
    const OutputFileDescriptors stdoutfds,
    const OutputFileDescriptors stderrfds)
{
  // The real arguments that will be passed to 'os::execvpe'. We need
  // to construct them here before doing the clone as it might not be
  // async signal safe to perform the memory allocation.
  char** _argv = new char*[argv.size() + 1];
  for (size_t i = 0; i < argv.size(); i++) {
    _argv[i] = (char*) argv[i].c_str();
  }
  _argv[argv.size()] = nullptr;

  // Like above, we need to construct the environment that we'll pass
  // to 'os::execvpe' as it might not be async-safe to perform the
  // memory allocations.
  char** envp = os::raw::environment();

  if (environment.isSome()) {
    // NOTE: We add 1 to the size for a `nullptr` terminator.
    envp = new char*[environment.get().size() + 1];

    size_t index = 0;
    foreachpair (
        const std::string& key,
        const std::string& value, environment.get()) {
      std::string entry = key + "=" + value;
      envp[index] = new char[entry.size() + 1];
      strncpy(envp[index], entry.c_str(), entry.size() + 1);
      ++index;
    }

    envp[index] = nullptr;
  }

  // Determine the function to clone the child process. If the user
  // does not specify the clone function, we will use the default.
  lambda::function<pid_t(const lambda::function<int()>&)> clone =
    (_clone.isSome() ? _clone.get() : defaultClone);

  // Currently we will block the child's execution of the new process
  // until all the `parent_hooks` (if any) have executed.
  std::array<int, 2> pipes;
  const bool blocking = !parent_hooks.empty();

  if (blocking) {
    // We assume this should not fail under reasonable conditions so we
    // use CHECK.
    Try<std::array<int, 2>> pipe = os::pipe();
    CHECK_SOME(pipe);

    pipes = pipe.get();
  }

  // Now, clone the child process.
  pid_t pid = clone(lambda::bind(
      &childMain,
      path,
      _argv,
      envp,
      stdinfds,
      stdoutfds,
      stderrfds,
      blocking,
      pipes.data(),
      child_hooks));

  delete[] _argv;

  // Need to delete 'envp' if we had environment variables passed to
  // us and we needed to allocate the space.
  if (environment.isSome()) {
    CHECK_NE(os::raw::environment(), envp);

    // We ignore the last 'envp' entry since it is nullptr.
    for (size_t index = 0; index < environment->size(); index++) {
      delete[] envp[index];
    }

    delete[] envp;
  }

  if (pid == -1) {
    // Save the errno as 'close' below might overwrite it.
    ErrnoError error("Failed to clone");
    internal::close(stdinfds, stdoutfds, stderrfds);

    if (blocking) {
      os::close(pipes[0]);
      os::close(pipes[1]);
    }

    return error;
  }

  // Close the child-ends of the file descriptors that are created by
  // this function.
  internal::close({stdinfds.read, stdoutfds.write, stderrfds.write});

  if (blocking) {
    os::close(pipes[0]);

    // Run the parent hooks.
    foreach (const Subprocess::ParentHook& hook, parent_hooks) {
      Try<Nothing> parentSetup = hook.parent_setup(pid);

      // If the hook callback fails, we shouldn't proceed with the
      // execution and hence the child process should be killed.
      if (parentSetup.isError()) {
        LOG(WARNING)
          << "Failed to execute Subprocess::ParentHook in parent for child '"
          << pid << "': " << parentSetup.error();

        os::close(pipes[1]);

        // Ensure the child is killed.
        ::kill(pid, SIGKILL);

        return Error(
            "Failed to execute Subprocess::ParentHook in parent for child '" +
            stringify(pid) + "': " + parentSetup.error());
      }
    }

    // Now that we've executed the parent hooks, we can signal the child to
    // continue by writing to the pipe.
    char dummy;
    ssize_t length;
    while ((length = ::write(pipes[1], &dummy, sizeof(dummy))) == -1 &&
           errno == EINTR);

    os::close(pipes[1]);

    if (length != sizeof(dummy)) {
      // Ensure the child is killed.
      ::kill(pid, SIGKILL);

      return Error("Failed to synchronize child process");
    }
  }

  return pid;
}

}  // namespace internal {
}  // namespace process {

#endif // __PROCESS_POSIX_SUBPROCESS_HPP__
<commit_msg>Replaced ABORT with SAFE_EXIT in childhook in `subprocess_posix.hpp`.<commit_after>// 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

#ifndef __PROCESS_POSIX_SUBPROCESS_HPP__
#define __PROCESS_POSIX_SUBPROCESS_HPP__

#ifdef __linux__
#include <sys/prctl.h>
#endif // __linux__
#include <sys/types.h>

#include <string>

#include <glog/logging.h>

#include <process/subprocess.hpp>

#include <stout/check.hpp>
#include <stout/error.hpp>
#include <stout/exit.hpp>
#include <stout/foreach.hpp>
#include <stout/hashset.hpp>
#include <stout/nothing.hpp>
#include <stout/lambda.hpp>
#include <stout/none.hpp>
#include <stout/option.hpp>
#include <stout/os.hpp>
#include <stout/try.hpp>
#include <stout/unreachable.hpp>

#include <stout/os/close.hpp>
#include <stout/os/environment.hpp>
#include <stout/os/fcntl.hpp>
#include <stout/os/signals.hpp>
#include <stout/os/strerror.hpp>

namespace process {
namespace internal {

static void close(std::initializer_list<int_fd> fds);

static void close(
    const Subprocess::IO::InputFileDescriptors& stdinfds,
    const Subprocess::IO::OutputFileDescriptors& stdoutfds,
    const Subprocess::IO::OutputFileDescriptors& stderrfds);

inline pid_t defaultClone(const lambda::function<int()>& func)
{
  pid_t pid = ::fork();
  if (pid == -1) {
    return -1;
  } else if (pid == 0) {
    // Child.
    ::exit(func());
    UNREACHABLE();
  } else {
    // Parent.
    return pid;
  }
}

// This function will invoke `os::cloexec` on all specified file
// descriptors that are valid (i.e., not `None` and >= 0).
inline Try<Nothing> cloexec(
    const InputFileDescriptors& stdinfds,
    const OutputFileDescriptors& stdoutfds,
    const OutputFileDescriptors& stderrfds)
{
  hashset<int> fds = {
    stdinfds.read,
    stdinfds.write.getOrElse(-1),
    stdoutfds.read.getOrElse(-1),
    stdoutfds.write,
    stderrfds.read.getOrElse(-1),
    stderrfds.write
  };

  foreach (int fd, fds) {
    if (fd >= 0) {
      Try<Nothing> cloexec = os::cloexec(fd);
      if (cloexec.isError()) {
        return Error(cloexec.error());
      }
    }
  }

  return Nothing();
}

// The main entry of the child process.
//
// NOTE: This function has to be async signal safe.
inline int childMain(
    const std::string& path,
    char** argv,
    char** envp,
    const InputFileDescriptors& stdinfds,
    const OutputFileDescriptors& stdoutfds,
    const OutputFileDescriptors& stderrfds,
    bool blocking,
    int pipes[2],
    const std::vector<Subprocess::ChildHook>& child_hooks)
{
  // Close parent's end of the pipes.
  if (stdinfds.write.isSome()) {
    ::close(stdinfds.write.get());
  }
  if (stdoutfds.read.isSome()) {
    ::close(stdoutfds.read.get());
  }
  if (stderrfds.read.isSome()) {
    ::close(stderrfds.read.get());
  }

  // Currently we will block the child's execution of the new process
  // until all the parent hooks (if any) have executed.
  if (blocking) {
    ::close(pipes[1]);
  }

  // Redirect I/O for stdin/stdout/stderr.
  while (::dup2(stdinfds.read, STDIN_FILENO) == -1 && errno == EINTR);
  while (::dup2(stdoutfds.write, STDOUT_FILENO) == -1 && errno == EINTR);
  while (::dup2(stderrfds.write, STDERR_FILENO) == -1 && errno == EINTR);

  // Close the copies. We need to make sure that we do not close the
  // file descriptor assigned to stdin/stdout/stderr in case the
  // parent has closed stdin/stdout/stderr when calling this
  // function (in that case, a dup'ed file descriptor may have the
  // same file descriptor number as stdin/stdout/stderr).
  //
  // We also need to ensure that we don't "double close" any file
  // descriptors in the case where one of stdinfds.read,
  // stdoutfds.write, or stdoutfds.write are equal.
  if (stdinfds.read != STDIN_FILENO &&
      stdinfds.read != STDOUT_FILENO &&
      stdinfds.read != STDERR_FILENO) {
    ::close(stdinfds.read);
  }
  if (stdoutfds.write != STDIN_FILENO &&
      stdoutfds.write != STDOUT_FILENO &&
      stdoutfds.write != STDERR_FILENO &&
      stdoutfds.write != stdinfds.read) {
    ::close(stdoutfds.write);
  }
  if (stderrfds.write != STDIN_FILENO &&
      stderrfds.write != STDOUT_FILENO &&
      stderrfds.write != STDERR_FILENO &&
      stderrfds.write != stdinfds.read &&
      stderrfds.write != stdoutfds.write) {
    ::close(stderrfds.write);
  }

  if (blocking) {
    // Do a blocking read on the pipe until the parent signals us to
    // continue.
    char dummy;
    ssize_t length;
    while ((length = ::read(pipes[0], &dummy, sizeof(dummy))) == -1 &&
          errno == EINTR);

    if (length != sizeof(dummy)) {
      ABORT("Failed to synchronize with parent");
    }

    // Now close the pipe as we don't need it anymore.
    ::close(pipes[0]);
  }

  // Run the child hooks.
  foreach (const Subprocess::ChildHook& hook, child_hooks) {
    Try<Nothing> callback = hook();

    // If the callback failed, we should abort execution.
    if (callback.isError()) {
      ABORT("Failed to execute Subprocess::ChildHook: " + callback.error());
    }
  }

  os::execvpe(path.c_str(), argv, envp);

  SAFE_EXIT(
      errno, "Failed to os::execvpe on path '%s': %d", path.c_str(), errno);
}

inline Try<pid_t> cloneChild(
    const std::string& path,
    std::vector<std::string> argv,
    const Option<std::map<std::string, std::string>>& environment,
    const Option<lambda::function<
        pid_t(const lambda::function<int()>&)>>& _clone,
    const std::vector<Subprocess::ParentHook>& parent_hooks,
    const std::vector<Subprocess::ChildHook>& child_hooks,
    const InputFileDescriptors stdinfds,
    const OutputFileDescriptors stdoutfds,
    const OutputFileDescriptors stderrfds)
{
  // The real arguments that will be passed to 'os::execvpe'. We need
  // to construct them here before doing the clone as it might not be
  // async signal safe to perform the memory allocation.
  char** _argv = new char*[argv.size() + 1];
  for (size_t i = 0; i < argv.size(); i++) {
    _argv[i] = (char*) argv[i].c_str();
  }
  _argv[argv.size()] = nullptr;

  // Like above, we need to construct the environment that we'll pass
  // to 'os::execvpe' as it might not be async-safe to perform the
  // memory allocations.
  char** envp = os::raw::environment();

  if (environment.isSome()) {
    // NOTE: We add 1 to the size for a `nullptr` terminator.
    envp = new char*[environment.get().size() + 1];

    size_t index = 0;
    foreachpair (
        const std::string& key,
        const std::string& value, environment.get()) {
      std::string entry = key + "=" + value;
      envp[index] = new char[entry.size() + 1];
      strncpy(envp[index], entry.c_str(), entry.size() + 1);
      ++index;
    }

    envp[index] = nullptr;
  }

  // Determine the function to clone the child process. If the user
  // does not specify the clone function, we will use the default.
  lambda::function<pid_t(const lambda::function<int()>&)> clone =
    (_clone.isSome() ? _clone.get() : defaultClone);

  // Currently we will block the child's execution of the new process
  // until all the `parent_hooks` (if any) have executed.
  std::array<int, 2> pipes;
  const bool blocking = !parent_hooks.empty();

  if (blocking) {
    // We assume this should not fail under reasonable conditions so we
    // use CHECK.
    Try<std::array<int, 2>> pipe = os::pipe();
    CHECK_SOME(pipe);

    pipes = pipe.get();
  }

  // Now, clone the child process.
  pid_t pid = clone(lambda::bind(
      &childMain,
      path,
      _argv,
      envp,
      stdinfds,
      stdoutfds,
      stderrfds,
      blocking,
      pipes.data(),
      child_hooks));

  delete[] _argv;

  // Need to delete 'envp' if we had environment variables passed to
  // us and we needed to allocate the space.
  if (environment.isSome()) {
    CHECK_NE(os::raw::environment(), envp);

    // We ignore the last 'envp' entry since it is nullptr.
    for (size_t index = 0; index < environment->size(); index++) {
      delete[] envp[index];
    }

    delete[] envp;
  }

  if (pid == -1) {
    // Save the errno as 'close' below might overwrite it.
    ErrnoError error("Failed to clone");
    internal::close(stdinfds, stdoutfds, stderrfds);

    if (blocking) {
      os::close(pipes[0]);
      os::close(pipes[1]);
    }

    return error;
  }

  // Close the child-ends of the file descriptors that are created by
  // this function.
  internal::close({stdinfds.read, stdoutfds.write, stderrfds.write});

  if (blocking) {
    os::close(pipes[0]);

    // Run the parent hooks.
    foreach (const Subprocess::ParentHook& hook, parent_hooks) {
      Try<Nothing> parentSetup = hook.parent_setup(pid);

      // If the hook callback fails, we shouldn't proceed with the
      // execution and hence the child process should be killed.
      if (parentSetup.isError()) {
        LOG(WARNING)
          << "Failed to execute Subprocess::ParentHook in parent for child '"
          << pid << "': " << parentSetup.error();

        os::close(pipes[1]);

        // Ensure the child is killed.
        ::kill(pid, SIGKILL);

        return Error(
            "Failed to execute Subprocess::ParentHook in parent for child '" +
            stringify(pid) + "': " + parentSetup.error());
      }
    }

    // Now that we've executed the parent hooks, we can signal the child to
    // continue by writing to the pipe.
    char dummy;
    ssize_t length;
    while ((length = ::write(pipes[1], &dummy, sizeof(dummy))) == -1 &&
           errno == EINTR);

    os::close(pipes[1]);

    if (length != sizeof(dummy)) {
      // Ensure the child is killed.
      ::kill(pid, SIGKILL);

      return Error("Failed to synchronize child process");
    }
  }

  return pid;
}

}  // namespace internal {
}  // namespace process {

#endif // __PROCESS_POSIX_SUBPROCESS_HPP__
<|endoftext|>