<commit_before>/**
 * @file   Singleton.hpp
 * @brief  Singleton class prototype.
 * @author zer0
 * @date   2016-04-04
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <atomic>
#include <mutex>

#ifndef SINGLETON_PROTOTYPE
#define SINGLETON_PROTOTYPE(base_class)             \
    protected:                                      \
        base_class();                               \
    public:                                         \
        ~base_class();                              \
    private:                                        \
        static std::atomic<base_class*> __instance; \
        static std::mutex __instance_lock;          \
    public:                                         \
        static base_class * getInstance();
#endif

#ifndef SINGLETON_IMPLEMENT
#define SINGLETON_IMPLEMENT(base_class)                             \
        std::atomic<base_class*> base_class::__instance(nullptr);   \
        std::mutex base_class::__instance_lock;                     \
                                                                    \
        base_class * base_class::getInstance()                      \
        {                                                           \
            base_class * temp = __instance.load();                  \
            if (temp == nullptr) {                                  \
                std::lock_guard<std::mutex> guard(__instance_lock); \
                temp = __instance.load();                           \
                if (temp == nullptr) {                              \
                    temp = new base_class();                        \
                    __instance.store(temp);                         \
                }                                                   \
            }                                                       \
            return temp;                                            \
        }
#endif

#endif // __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__

<commit_msg>Create SingletonLifeManager class.<commit_after>/**
 * @file   Singleton.hpp
 * @brief  Singleton class prototype.
 * @author zer0
 * @date   2016-04-04
 */

#ifndef __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__
#define __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#include <libtbag/config.h>
#include <libtbag/Noncopyable.hpp>
#include <libtbag/pattern/Observer.hpp>

#include <cstdlib>
#include <atomic>
#include <mutex>

/**
 * Don't use @c std::atexit function.
 *
 * @remarks
 *  Default variable is true.
 */
constexpr bool isManualRelease() noexcept
{
    return false;
}

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace pattern {

/**
 * SingletonLifeManager class prototype.
 *
 * @author zer0
 * @date   2016-04-11
 *
 * @remarks
 *  Management of Singleton classes.
 */
class SingletonLifeManager : public Noncopyable
{
public:
    UnorderedObservable _observable;

protected:
    SingletonLifeManager() {
        __EMPTY_BLOCK__
    }

public:
    ~SingletonLifeManager() {
        this->_observable.notify();
    }

public:
    void add(std::function<void(void)> const & observer) {
        this->_observable.add(observer);
    }

// Singleton section.
private:
    static std::atomic<SingletonLifeManager*> __instance;
    static std::mutex __instance_lock;

public:
    static void releaseInstance() {
        SingletonLifeManager * temp = __instance.load();
        if (temp != nullptr) {
            std::lock_guard<std::mutex> guard(__instance_lock);
            temp = __instance.load();
            if (temp != nullptr) {
                delete temp; // Release, all singleton objects.
                __instance.store(nullptr);
            }
        }
    }

public:
    static SingletonLifeManager * getInstance() {
        SingletonLifeManager * temp = __instance.load();
        if (temp == nullptr) {
            std::lock_guard<std::mutex> guard(__instance_lock);
            temp = __instance.load();
            if (temp == nullptr) {
                temp = new SingletonLifeManager();
                __instance.store(temp);

                if (!isManualRelease()) {
                    // Register release method.
                    std::atexit(&SingletonLifeManager::releaseInstance);
                }
            }
        }
        return temp;
    }
};

std::atomic<SingletonLifeManager*> SingletonLifeManager::__instance(nullptr);
std::mutex SingletonLifeManager::__instance_lock;

} // namespace pattern

#ifndef SINGLETON_PROTOTYPE
#define SINGLETON_PROTOTYPE(base_class)                         \
    protected:                                                  \
        base_class();                                           \
    public:                                                     \
        ~base_class();                                          \
    private:                                                    \
        static std::atomic<base_class*> __instance;             \
        static std::mutex __instance_lock;                      \
    private:                                                    \
        static void releaseInstance();                          \
    public:                                                     \
        static base_class * getInstance();                      \
    private: // default access modifier of class.
#endif

#ifndef SINGLETON_IMPLEMENT
#define SINGLETON_IMPLEMENT(base_class)                             \
    std::atomic<base_class*> base_class::__instance(nullptr);       \
    std::mutex base_class::__instance_lock;                         \
                                                                    \
    void base_class::releaseInstance() {                            \
        base_class * temp = __instance.load();                      \
        if (temp != nullptr) {                                      \
            std::lock_guard<std::mutex> guard(__instance_lock);     \
            temp = __instance.load();                               \
            if (temp != nullptr) {                                  \
                delete temp;                                        \
                __instance.store(nullptr);                          \
            }                                                       \
        }                                                           \
    }                                                               \
                                                                    \
    base_class * base_class::getInstance()                          \
    {                                                               \
        base_class * temp = __instance.load();                      \
        if (temp == nullptr) {                                      \
            std::lock_guard<std::mutex> guard(__instance_lock);     \
            temp = __instance.load();                               \
            if (temp == nullptr) {                                  \
                temp = new base_class();                            \
                __instance.store(temp);                             \
                using namespace libtbag;                            \
                using namespace libtbag::pattern;                   \
                SingletonLifeManager::getInstance()->add([](){      \
                        base_class::releaseInstance();              \
                    });                                             \
            }                                                       \
        }                                                           \
        return temp;                                                \
    }
#endif

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

#endif // __INCLUDE_LIBTBAG__LIBTBAG_PATTERN_SINGLETON_HPP__

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: repainttarget.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-03-30 07:38:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _VCLCANVAS_REPAINTTARGET_HXX
#define _VCLCANVAS_REPAINTTARGET_HXX

#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif

#include "cachedbitmap.hxx"

class Point;
class Size;
class GraphicAttr;

namespace vclcanvas
{
    /* Definition of RepaintTarget interface */

    /** Target interface for XCachedPrimitive implementations

        This interface must be implemented on all canvas
        implementations that hand out XCachedPrimitives
     */
    class RepaintTarget
    {
    public:
        virtual ~RepaintTarget() {}

        // call this when a bitmap is repainted
        virtual bool repaint( const GraphicObjectSharedPtr& rGrf,
                              const ::Point&                rPt,
                              const ::Size&                 rSz,
                              const GraphicAttr&            rAttr ) const = 0;
    };
}

#endif /* _VCLCANVAS_REPAINTTARGET_HXX */
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.20); FILE MERGED 2005/09/05 17:27:16 rt 1.2.20.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: repainttarget.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 23:22:47 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _VCLCANVAS_REPAINTTARGET_HXX
#define _VCLCANVAS_REPAINTTARGET_HXX

#ifndef _RTL_REF_HXX_
#include <rtl/ref.hxx>
#endif

#include "cachedbitmap.hxx"

class Point;
class Size;
class GraphicAttr;

namespace vclcanvas
{
    /* Definition of RepaintTarget interface */

    /** Target interface for XCachedPrimitive implementations

        This interface must be implemented on all canvas
        implementations that hand out XCachedPrimitives
     */
    class RepaintTarget
    {
    public:
        virtual ~RepaintTarget() {}

        // call this when a bitmap is repainted
        virtual bool repaint( const GraphicObjectSharedPtr& rGrf,
                              const ::Point&                rPt,
                              const ::Size&                 rSz,
                              const GraphicAttr&            rAttr ) const = 0;
    };
}

#endif /* _VCLCANVAS_REPAINTTARGET_HXX */
<|endoftext|>


<commit_before>#include <cstdlib>

#include "connection.hpp"
#include "../common/assert.hpp"
#include "../common/message.hpp"
#include "../common/network/tcp_socket.hpp"

#include "rsg.pb.h"

namespace rsg
{
    thread_local Connection* connection = nullptr;
}

static void retrieve_rsg_connection_params_from_env(std::string & server_hostname, uint16_t & port, int & actor_id)
{
    const char * c_server_hostname = std::getenv("RSG_SERVER_HOSTNAME");
    RSG_ENFORCE(c_server_hostname != nullptr, "Invalid RSG connection initialization: RSG_SERVER_HOSTNAME is not set.");
    server_hostname = std::string(c_server_hostname);

    const char * server_port = std::getenv("RSG_SERVER_PORT");
    RSG_ENFORCE(server_port != nullptr, "Invalid RSG connection initialization: RSG_SERVER_PORT is not set.");
    try
    {
        port = std::stoi(std::string(server_port));
    }
    catch (const rsg::Error & e)
    {
        throw rsg::Error("Invalid RSG connection initialization: RSG_SERVER_PORT ('%s') is not a valid port", server_port);
    }

    const char * initial_actor_id = std::getenv("RSG_INITIAL_ACTOR_ID");
    RSG_ENFORCE(initial_actor_id != nullptr, "Invalid RSG connection initialization: RSG_INITIAL_ACTOR_ID is not set.");
    try
    {
        actor_id = std::stoi(std::string(initial_actor_id));
    }
    catch(const std::exception & e)
    {
        throw rsg::Error("Invalid RSG connection initialization: RSG_INITIAL_ACTOR_ID ('%s') is not a valid actor id", initial_actor_id);
    }
}

rsg::Connection::Connection(const std::string & server_hostname, uint16_t port, int actor_id) : _actor_id(actor_id)
{
    // Connect to the server.
    _socket = new TcpSocket();
    _socket->connect(server_hostname, port);
    _socket->disable_nagle_algorithm();

    // Generate command.
    rsg::pb::Command command;
    auto actor = new rsg::pb::Actor();
    actor->set_id(_actor_id);
    command.set_allocated_connect(actor);

    // Write message on socket.
    write_message(command, *_socket);

    // Read acknowledment.
    rsg::pb::CommandAck command_ack;
    read_message(command_ack, *_socket);

    if (!command_ack.success())
        printf("connect failed\n");
}

rsg::Connection::~Connection()
{
    // Wait for the termination of all children threads.
    for (pthread_t child : _children)
    {
        int ret = pthread_join(child, nullptr);
        RSG_ENFORCE(ret == 0, "Error while joining thread");
    }

    try
    {
        rsg::pb::Decision decision;
        decision.set_quit(true);

        rsg::pb::DecisionAck ack;
        write_message(decision, *_socket);
    }
    catch (const rsg::Error & e)
    {
        printf("Could not tell server that I want to quit: %s\n", e.what());
    }

    delete _socket;
    _socket = nullptr;
}

void rsg::Connection::send_decision(const rsg::pb::Decision & decision, rsg::pb::DecisionAck & decision_ack)
{
    write_message(decision, *_socket);
    read_message(decision_ack, *_socket);
}

void rsg::Connection::add_child_thread(pthread_t child)
{
    _children.push_back(child);
}

int rsg::Connection::actor_id() const
{
    return _actor_id;
}

void rsg::connect(int actor_id)
{
    RSG_ENFORCE(connection == nullptr, "Invalid rsg::connect() call: Already connected!");

    std::string server_hostname;
    uint16_t port = 0;
    int env_actor_id;

    try {
        retrieve_rsg_connection_params_from_env(server_hostname, port, env_actor_id);
    } catch (const rsg::Error & e) {
        if (strstr(e.what(), "RSG_INITIAL_ACTOR_ID") != nullptr)
        {
            fprintf(stdout, "Killing the server, as this process had no/invalid actor_id.\n");
            fflush(stdout);

            char kill_command[128];
            snprintf(kill_command, 128,
                "rsg kill --reason=\"could not connect: invalid actor_id '%s'\" -h %s -p %d",
                std::getenv("RSG_INITIAL_ACTOR_ID"), server_hostname.c_str(), port);
            int ret = system(kill_command);
            RSG_ENFORCE(ret != -1, "Could not kill server: Could not execute a `rsg` process.");
            RSG_ENFORCE(ret == 0 || ret == 1, "Could not kill server: `rsg kill` returned %d", ret);
        }
        throw;
    }

    if (actor_id == -1)
        actor_id = env_actor_id;

    connection = new Connection(server_hostname, port, actor_id);
}

void rsg::connect()
{
    connect(-1);
}

static void autoconnect(void) __attribute__((constructor));
void autoconnect(void)
{
    if (std::getenv("RSG_AUTOCONNECT") != nullptr)
        rsg::connect();
}

void rsg::disconnect()
{
    delete rsg::connection;
    rsg::connection = nullptr;
}

static void autodisconnect(void) __attribute__((destructor));
void autodisconnect(void)
{
    rsg::disconnect();
}
<commit_msg>[code] fix warning<commit_after>#include <cstdlib>

#include "connection.hpp"
#include "../common/assert.hpp"
#include "../common/message.hpp"
#include "../common/network/tcp_socket.hpp"

#include "rsg.pb.h"

namespace rsg
{
    thread_local Connection* connection = nullptr;
}

static void retrieve_rsg_connection_params_from_env(std::string & server_hostname, uint16_t & port, int & actor_id)
{
    const char * c_server_hostname = std::getenv("RSG_SERVER_HOSTNAME");
    RSG_ENFORCE(c_server_hostname != nullptr, "Invalid RSG connection initialization: RSG_SERVER_HOSTNAME is not set.");
    server_hostname = std::string(c_server_hostname);

    const char * server_port = std::getenv("RSG_SERVER_PORT");
    RSG_ENFORCE(server_port != nullptr, "Invalid RSG connection initialization: RSG_SERVER_PORT is not set.");
    try
    {
        port = std::stoi(std::string(server_port));
    }
    catch (const rsg::Error & e)
    {
        throw rsg::Error("Invalid RSG connection initialization: RSG_SERVER_PORT ('%s') is not a valid port", server_port);
    }

    const char * initial_actor_id = std::getenv("RSG_INITIAL_ACTOR_ID");
    RSG_ENFORCE(initial_actor_id != nullptr, "Invalid RSG connection initialization: RSG_INITIAL_ACTOR_ID is not set.");
    try
    {
        actor_id = std::stoi(std::string(initial_actor_id));
    }
    catch(const std::exception & e)
    {
        throw rsg::Error("Invalid RSG connection initialization: RSG_INITIAL_ACTOR_ID ('%s') is not a valid actor id", initial_actor_id);
    }
}

rsg::Connection::Connection(const std::string & server_hostname, uint16_t port, int actor_id) : _actor_id(actor_id)
{
    // Connect to the server.
    _socket = new TcpSocket();
    _socket->connect(server_hostname, port);
    _socket->disable_nagle_algorithm();

    // Generate command.
    rsg::pb::Command command;
    auto actor = new rsg::pb::Actor();
    actor->set_id(_actor_id);
    command.set_allocated_connect(actor);

    // Write message on socket.
    write_message(command, *_socket);

    // Read acknowledment.
    rsg::pb::CommandAck command_ack;
    read_message(command_ack, *_socket);

    if (!command_ack.success())
        printf("connect failed\n");
}

rsg::Connection::~Connection()
{
    // Wait for the termination of all children threads.
    for (pthread_t child : _children)
    {
        int ret = pthread_join(child, nullptr);
        if (ret != 0)
        {
            printf("Error while joining thread\n");
        }
    }

    try
    {
        rsg::pb::Decision decision;
        decision.set_quit(true);

        rsg::pb::DecisionAck ack;
        write_message(decision, *_socket);
    }
    catch (const rsg::Error & e)
    {
        printf("Could not tell server that I want to quit: %s\n", e.what());
    }

    delete _socket;
    _socket = nullptr;
}

void rsg::Connection::send_decision(const rsg::pb::Decision & decision, rsg::pb::DecisionAck & decision_ack)
{
    write_message(decision, *_socket);
    read_message(decision_ack, *_socket);
}

void rsg::Connection::add_child_thread(pthread_t child)
{
    _children.push_back(child);
}

int rsg::Connection::actor_id() const
{
    return _actor_id;
}

void rsg::connect(int actor_id)
{
    RSG_ENFORCE(connection == nullptr, "Invalid rsg::connect() call: Already connected!");

    std::string server_hostname;
    uint16_t port = 0;
    int env_actor_id;

    try {
        retrieve_rsg_connection_params_from_env(server_hostname, port, env_actor_id);
    } catch (const rsg::Error & e) {
        if (strstr(e.what(), "RSG_INITIAL_ACTOR_ID") != nullptr)
        {
            fprintf(stdout, "Killing the server, as this process had no/invalid actor_id.\n");
            fflush(stdout);

            char kill_command[128];
            snprintf(kill_command, 128,
                "rsg kill --reason=\"could not connect: invalid actor_id '%s'\" -h %s -p %d",
                std::getenv("RSG_INITIAL_ACTOR_ID"), server_hostname.c_str(), port);
            int ret = system(kill_command);
            RSG_ENFORCE(ret != -1, "Could not kill server: Could not execute a `rsg` process.");
            RSG_ENFORCE(ret == 0 || ret == 1, "Could not kill server: `rsg kill` returned %d", ret);
        }
        throw;
    }

    if (actor_id == -1)
        actor_id = env_actor_id;

    connection = new Connection(server_hostname, port, actor_id);
}

void rsg::connect()
{
    connect(-1);
}

static void autoconnect(void) __attribute__((constructor));
void autoconnect(void)
{
    if (std::getenv("RSG_AUTOCONNECT") != nullptr)
        rsg::connect();
}

void rsg::disconnect()
{
    delete rsg::connection;
    rsg::connection = nullptr;
}

static void autodisconnect(void) __attribute__((destructor));
void autodisconnect(void)
{
    rsg::disconnect();
}
<|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.
 */

#ifndef __SYSTEMC_CORE_SCHEDULER_HH__
#define __SYSTEMC_CORE_SCHEDULER_HH__

#include <functional>
#include <map>
#include <mutex>
#include <set>
#include <vector>

#include "base/logging.hh"
#include "sim/core.hh"
#include "sim/eventq_impl.hh"
#include "systemc/core/channel.hh"
#include "systemc/core/list.hh"
#include "systemc/core/process.hh"
#include "systemc/core/sched_event.hh"

class Fiber;

namespace sc_gem5
{

class TraceFile;

typedef NodeList<Process> ProcessList;
typedef NodeList<Channel> ChannelList;

/*
 * The scheduler supports three different mechanisms, the initialization phase,
 * delta cycles, and timed notifications.
 *
 * INITIALIZATION PHASE
 *
 * The initialization phase has three parts:
 * 1. Run requested channel updates.
 * 2. Make processes which need to initialize runnable (methods and threads
 *    which didn't have dont_initialize called on them).
 * 3. Process delta notifications.
 *
 * First, the Kernel SimObject calls the update() method during its startup()
 * callback which handles the requested channel updates. The Kernel also
 * schedules an event to be run at time 0 with a slightly elevated priority
 * so that it happens before any "normal" event.
 *
 * When that t0 event happens, it calls the schedulers prepareForInit method
 * which performs step 2 above. That indirectly causes the scheduler's
 * readyEvent to be scheduled with slightly lowered priority, ensuring it
 * happens after any "normal" event.
 *
 * Because delta notifications are scheduled at the standard priority, all
 * of those events will happen next, performing step 3 above. Once they finish,
 * if the readyEvent was scheduled above, there shouldn't be any higher
 * priority events in front of it. When it runs, it will start the first
 * evaluate phase of the first delta cycle.
 *
 * DELTA CYCLE
 *
 * A delta cycle has three phases within it.
 * 1. The evaluate phase where runnable processes are allowed to run.
 * 2. The update phase where requested channel updates hapen.
 * 3. The delta notification phase where delta notifications happen.
 *
 * The readyEvent runs all three steps of the delta cycle. It first goes
 * through the list of runnable processes and executes them until the set is
 * empty, and then immediately runs the update phase. Since these are all part
 * of the same event, there's no chance for other events to intervene and
 * break the required order above.
 *
 * During the update phase above, the spec forbids any action which would make
 * a process runnable. That means that once the update phase finishes, the set
 * of runnable processes will be empty. There may, however, have been some
 * delta notifications/timeouts which will have been scheduled during either
 * the evaluate or update phase above. Those will have been accumulated in the
 * scheduler, and are now all executed.
 *
 * If any processes became runnable during the delta notification phase, the
 * readyEvent will have been scheduled and will be waiting and ready to run
 * again, effectively starting the next delta cycle.
 *
 * TIMED NOTIFICATION PHASE
 *
 * If no processes became runnable, the event queue will continue to process
 * events until it comes across an event which represents all the timed
 * notifications which are supposed to happen at a particular time. The object
 * which tracks them will execute all those notifications, and then destroy
 * itself. If the readyEvent is now ready to run, the next delta cycle will
 * start.
 *
 * PAUSE/STOP
 *
 * To inject a pause from sc_pause which should happen after the current delta
 * cycle's delta notification phase, an event is scheduled with a lower than
 * normal priority, but higher than the readyEvent. That ensures that any
 * delta notifications which are scheduled with normal priority will happen
 * first, since those are part of the current delta cycle. Then the pause
 * event will happen before the next readyEvent which would start the next
 * delta cycle. All of these events are scheduled for the current time, and so
 * would happen before any timed notifications went off.
 *
 * To inject a stop from sc_stop, the delta cycles should stop before even the
 * delta notifications have happened, but after the evaluate and update phases.
 * For that, a stop event with slightly higher than normal priority will be
 * scheduled so that it happens before any of the delta notification events
 * which are at normal priority.
 *
 * MAX RUN TIME
 *
 * When sc_start is called, it's possible to pass in a maximum time the
 * simulation should run to, at which point sc_pause is implicitly called. The
 * simulation is supposed to run up to the latest timed notification phase
 * which is less than or equal to the maximum time. In other words it should
 * run timed notifications at the maximum time, but not the subsequent evaluate
 * phase. That's implemented by scheduling an event at the max time with a
 * priority which is lower than all the others except the ready event. Timed
 * notifications will happen before it fires, but it will override any ready
 * event and prevent the evaluate phase from starting.
 */

class Scheduler
{
  public:
    typedef std::list<ScEvent *> ScEvents;

    class TimeSlot : public ::Event
    {
      public:
        TimeSlot() : ::Event(Default_Pri, AutoDelete) {}

        ScEvents events;
        void process();
    };

    typedef std::map<Tick, TimeSlot *> TimeSlots;

    Scheduler();
    ~Scheduler();

    void clear();

    const std::string name() const { return "systemc_scheduler"; }

    uint64_t numCycles() { return _numCycles; }
    Process *current() { return _current; }

    void initPhase();

    // Register a process with the scheduler.
    void reg(Process *p);

    // Run the next process, if there is one.
    void yield();

    // Put a process on the ready list.
    void ready(Process *p);

    // Mark a process as ready if init is finished, or put it on the list of
    // processes to be initialized.
    void resume(Process *p);

    // Remove a process from the ready/init list if it was on one of them, and
    // return if it was.
    bool suspend(Process *p);

    // Schedule an update for a given channel.
    void requestUpdate(Channel *c);
    // Same as above, but may be called from a different thread.
    void asyncRequestUpdate(Channel *c);

    // Run the given process immediately, preempting whatever may be running.
    void
    runNow(Process *p)
    {
        // This function may put a process on the wrong list, ie a thread
        // the method list. That's fine since that's just a performance
        // optimization, and the important thing here is how the processes are
        // ordered.

        // If a process is running, schedule it/us to run again.
        if (_current)
            readyListMethods.pushFirst(_current);
        // Schedule p to run first.
        readyListMethods.pushFirst(p);
        yield();
    }

    // Run this process at the next opportunity.
    void
    runNext(Process *p)
    {
        // Like above, it's ok if this isn't a method. Putting it on this list
        // just gives it priority.
        readyListMethods.pushFirst(p);
        if (!inEvaluate())
            scheduleReadyEvent();
    }

    // Set an event queue for scheduling events.
    void setEventQueue(EventQueue *_eq) { eq = _eq; }

    // Get the current time according to gem5.
    Tick getCurTick() { return eq ? eq->getCurTick() : 0; }

    Tick
    delayed(const ::sc_core::sc_time &delay)
    {
        return getCurTick() + delay.value();
    }

    // For scheduling delayed/timed notifications/timeouts.
    void
    schedule(ScEvent *event, const ::sc_core::sc_time &delay)
    {
        Tick tick = delayed(delay);
        if (tick < getCurTick())
            tick = getCurTick();

        // Delta notification/timeout.
        if (delay.value() == 0) {
            event->schedule(deltas, tick);
            if (!inEvaluate() && !inUpdate())
                scheduleReadyEvent();
            return;
        }

        // Timed notification/timeout.
        TimeSlot *&ts = timeSlots[tick];
        if (!ts) {
            ts = new TimeSlot;
            schedule(ts, tick);
        }
        event->schedule(ts->events, tick);
    }

    // For descheduling delayed/timed notifications/timeouts.
    void
    deschedule(ScEvent *event)
    {
        ScEvents *on = event->scheduledOn();

        if (on == &deltas) {
            event->deschedule();
            return;
        }

        // Timed notification/timeout.
        auto tsit = timeSlots.find(event->when());
        panic_if(tsit == timeSlots.end(),
                "Descheduling event at time with no events.");
        TimeSlot *ts = tsit->second;
        ScEvents &events = ts->events;
        assert(on == &events);
        event->deschedule();

        // If no more events are happening at this time slot, get rid of it.
        if (events.empty()) {
            deschedule(ts);
            timeSlots.erase(tsit);
        }
    }

    void
    completeTimeSlot(TimeSlot *ts)
    {
        assert(ts == timeSlots.begin()->second);
        timeSlots.erase(timeSlots.begin());
        if (!runToTime && starved())
            scheduleStarvationEvent();
        scheduleTimeAdvancesEvent();
    }

    // Pending activity ignores gem5 activity, much like how a systemc
    // simulation wouldn't know about asynchronous external events (socket IO
    // for instance) that might happen before time advances in a pure
    // systemc simulation. Also the spec lists what specific types of pending
    // activity needs to be counted, which obviously doesn't include gem5
    // events.

    // Return whether there's pending systemc activity at this time.
    bool
    pendingCurr()
    {
        return !readyListMethods.empty() || !readyListThreads.empty() ||
            !updateList.empty() || !deltas.empty();
    }

    // Return whether there are pending timed notifications or timeouts.
    bool
    pendingFuture()
    {
        return !timeSlots.empty();
    }

    // Return how many ticks there are until the first pending event, if any.
    Tick
    timeToPending()
    {
        if (pendingCurr())
            return 0;
        if (pendingFuture())
            return timeSlots.begin()->first - getCurTick();
        return MaxTick - getCurTick();
    }

    // Run scheduled channel updates.
    void runUpdate();

    // Run delta events.
    void runDelta();

    void start(Tick max_tick, bool run_to_time);
    void oneCycle();

    void schedulePause();
    void scheduleStop(bool finish_delta);

    enum Status
    {
        StatusOther = 0,
        StatusEvaluate,
        StatusUpdate,
        StatusDelta,
        StatusTiming,
        StatusPaused,
        StatusStopped
    };

    bool elaborationDone() { return _elaborationDone; }
    void elaborationDone(bool b) { _elaborationDone = b; }

    bool paused() { return status() == StatusPaused; }
    bool stopped() { return status() == StatusStopped; }
    bool inEvaluate() { return status() == StatusEvaluate; }
    bool inUpdate() { return status() == StatusUpdate; }
    bool inDelta() { return status() == StatusDelta; }
    bool inTiming() { return status() == StatusTiming; }

    uint64_t changeStamp() { return _changeStamp; }
    void stepChangeStamp() { _changeStamp++; }

    // Throw upwards, either to sc_main or to the report handler if sc_main
    // isn't running.
    void throwUp();

    Status status() { return _status; }
    void status(Status s) { _status = s; }

    void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); }
    void unregisterTraceFile(TraceFile *tf) { traceFiles.erase(tf); }

  private:
    typedef const EventBase::Priority Priority;
    static Priority DefaultPriority = EventBase::Default_Pri;

    static Priority StopPriority = DefaultPriority - 1;
    static Priority PausePriority = DefaultPriority + 1;
    static Priority MaxTickPriority = DefaultPriority + 2;
    static Priority ReadyPriority = DefaultPriority + 3;
    static Priority StarvationPriority = ReadyPriority;
    static Priority TimeAdvancesPriority = EventBase::Maximum_Pri;

    EventQueue *eq;

    // For gem5 style events.
    void
    schedule(::Event *event, Tick tick)
    {
        if (initDone)
            eq->schedule(event, tick);
        else
            eventsToSchedule[event] = tick;
    }

    void schedule(::Event *event) { schedule(event, getCurTick()); }

    void
    deschedule(::Event *event)
    {
        if (initDone)
            eq->deschedule(event);
        else
            eventsToSchedule.erase(event);
    }

    ScEvents deltas;
    TimeSlots timeSlots;

    Process *
    getNextReady()
    {
        Process *p = readyListMethods.getNext();
        return p ? p : readyListThreads.getNext();
    }

    void runReady();
    EventWrapper<Scheduler, &Scheduler::runReady> readyEvent;
    void scheduleReadyEvent();

    void pause();
    void stop();
    EventWrapper<Scheduler, &Scheduler::pause> pauseEvent;
    EventWrapper<Scheduler, &Scheduler::stop> stopEvent;

    const ::sc_core::sc_report *_throwUp;

    bool
    starved()
    {
        return (readyListMethods.empty() && readyListThreads.empty() &&
                updateList.empty() && deltas.empty() &&
                (timeSlots.empty() || timeSlots.begin()->first > maxTick) &&
                initList.empty());
    }
    EventWrapper<Scheduler, &Scheduler::pause> starvationEvent;
    void scheduleStarvationEvent();

    bool _elaborationDone;
    bool _started;
    bool _stopNow;

    Status _status;

    Tick maxTick;
    Tick lastReadyTick;
    void
    maxTickFunc()
    {
        if (lastReadyTick != getCurTick())
            _changeStamp++;
        pause();
    }
    EventWrapper<Scheduler, &Scheduler::maxTickFunc> maxTickEvent;

    void timeAdvances() { trace(false); }
    EventWrapper<Scheduler, &Scheduler::timeAdvances> timeAdvancesEvent;
    void
    scheduleTimeAdvancesEvent()
    {
        if (!traceFiles.empty() && !timeAdvancesEvent.scheduled())
            schedule(&timeAdvancesEvent);
    }

    uint64_t _numCycles;
    uint64_t _changeStamp;

    Process *_current;

    bool initDone;
    bool runToTime;
    bool runOnce;

    ProcessList initList;

    ProcessList readyListMethods;
    ProcessList readyListThreads;

    ChannelList updateList;

    ChannelList asyncUpdateList;
    std::mutex asyncListMutex;

    std::map<::Event *, Tick> eventsToSchedule;

    std::set<TraceFile *> traceFiles;

    void trace(bool delta);
};

extern Scheduler scheduler;

// A proxy function to avoid having to expose the scheduler in header files.
Process *getCurrentProcess();

inline void
Scheduler::TimeSlot::process()
{
    scheduler.stepChangeStamp();
    scheduler.status(StatusTiming);

    try {
        while (!events.empty())
            events.front()->run();
    } catch (...) {
        if (events.empty())
            scheduler.completeTimeSlot(this);
        else
            scheduler.schedule(this);
        scheduler.throwUp();
    }

    scheduler.status(StatusOther);
    scheduler.completeTimeSlot(this);
}

const ::sc_core::sc_report reportifyException();

} // namespace sc_gem5

#endif // __SYSTEMC_CORE_SCHEDULER_H__
<commit_msg>systemc: Replace include of eventq_impl.hh with eventq.hh.<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.
 */

#ifndef __SYSTEMC_CORE_SCHEDULER_HH__
#define __SYSTEMC_CORE_SCHEDULER_HH__

#include <functional>
#include <map>
#include <mutex>
#include <set>
#include <vector>

#include "base/logging.hh"
#include "sim/core.hh"
#include "sim/eventq.hh"
#include "systemc/core/channel.hh"
#include "systemc/core/list.hh"
#include "systemc/core/process.hh"
#include "systemc/core/sched_event.hh"

class Fiber;

namespace sc_gem5
{

class TraceFile;

typedef NodeList<Process> ProcessList;
typedef NodeList<Channel> ChannelList;

/*
 * The scheduler supports three different mechanisms, the initialization phase,
 * delta cycles, and timed notifications.
 *
 * INITIALIZATION PHASE
 *
 * The initialization phase has three parts:
 * 1. Run requested channel updates.
 * 2. Make processes which need to initialize runnable (methods and threads
 *    which didn't have dont_initialize called on them).
 * 3. Process delta notifications.
 *
 * First, the Kernel SimObject calls the update() method during its startup()
 * callback which handles the requested channel updates. The Kernel also
 * schedules an event to be run at time 0 with a slightly elevated priority
 * so that it happens before any "normal" event.
 *
 * When that t0 event happens, it calls the schedulers prepareForInit method
 * which performs step 2 above. That indirectly causes the scheduler's
 * readyEvent to be scheduled with slightly lowered priority, ensuring it
 * happens after any "normal" event.
 *
 * Because delta notifications are scheduled at the standard priority, all
 * of those events will happen next, performing step 3 above. Once they finish,
 * if the readyEvent was scheduled above, there shouldn't be any higher
 * priority events in front of it. When it runs, it will start the first
 * evaluate phase of the first delta cycle.
 *
 * DELTA CYCLE
 *
 * A delta cycle has three phases within it.
 * 1. The evaluate phase where runnable processes are allowed to run.
 * 2. The update phase where requested channel updates hapen.
 * 3. The delta notification phase where delta notifications happen.
 *
 * The readyEvent runs all three steps of the delta cycle. It first goes
 * through the list of runnable processes and executes them until the set is
 * empty, and then immediately runs the update phase. Since these are all part
 * of the same event, there's no chance for other events to intervene and
 * break the required order above.
 *
 * During the update phase above, the spec forbids any action which would make
 * a process runnable. That means that once the update phase finishes, the set
 * of runnable processes will be empty. There may, however, have been some
 * delta notifications/timeouts which will have been scheduled during either
 * the evaluate or update phase above. Those will have been accumulated in the
 * scheduler, and are now all executed.
 *
 * If any processes became runnable during the delta notification phase, the
 * readyEvent will have been scheduled and will be waiting and ready to run
 * again, effectively starting the next delta cycle.
 *
 * TIMED NOTIFICATION PHASE
 *
 * If no processes became runnable, the event queue will continue to process
 * events until it comes across an event which represents all the timed
 * notifications which are supposed to happen at a particular time. The object
 * which tracks them will execute all those notifications, and then destroy
 * itself. If the readyEvent is now ready to run, the next delta cycle will
 * start.
 *
 * PAUSE/STOP
 *
 * To inject a pause from sc_pause which should happen after the current delta
 * cycle's delta notification phase, an event is scheduled with a lower than
 * normal priority, but higher than the readyEvent. That ensures that any
 * delta notifications which are scheduled with normal priority will happen
 * first, since those are part of the current delta cycle. Then the pause
 * event will happen before the next readyEvent which would start the next
 * delta cycle. All of these events are scheduled for the current time, and so
 * would happen before any timed notifications went off.
 *
 * To inject a stop from sc_stop, the delta cycles should stop before even the
 * delta notifications have happened, but after the evaluate and update phases.
 * For that, a stop event with slightly higher than normal priority will be
 * scheduled so that it happens before any of the delta notification events
 * which are at normal priority.
 *
 * MAX RUN TIME
 *
 * When sc_start is called, it's possible to pass in a maximum time the
 * simulation should run to, at which point sc_pause is implicitly called. The
 * simulation is supposed to run up to the latest timed notification phase
 * which is less than or equal to the maximum time. In other words it should
 * run timed notifications at the maximum time, but not the subsequent evaluate
 * phase. That's implemented by scheduling an event at the max time with a
 * priority which is lower than all the others except the ready event. Timed
 * notifications will happen before it fires, but it will override any ready
 * event and prevent the evaluate phase from starting.
 */

class Scheduler
{
  public:
    typedef std::list<ScEvent *> ScEvents;

    class TimeSlot : public ::Event
    {
      public:
        TimeSlot() : ::Event(Default_Pri, AutoDelete) {}

        ScEvents events;
        void process();
    };

    typedef std::map<Tick, TimeSlot *> TimeSlots;

    Scheduler();
    ~Scheduler();

    void clear();

    const std::string name() const { return "systemc_scheduler"; }

    uint64_t numCycles() { return _numCycles; }
    Process *current() { return _current; }

    void initPhase();

    // Register a process with the scheduler.
    void reg(Process *p);

    // Run the next process, if there is one.
    void yield();

    // Put a process on the ready list.
    void ready(Process *p);

    // Mark a process as ready if init is finished, or put it on the list of
    // processes to be initialized.
    void resume(Process *p);

    // Remove a process from the ready/init list if it was on one of them, and
    // return if it was.
    bool suspend(Process *p);

    // Schedule an update for a given channel.
    void requestUpdate(Channel *c);
    // Same as above, but may be called from a different thread.
    void asyncRequestUpdate(Channel *c);

    // Run the given process immediately, preempting whatever may be running.
    void
    runNow(Process *p)
    {
        // This function may put a process on the wrong list, ie a thread
        // the method list. That's fine since that's just a performance
        // optimization, and the important thing here is how the processes are
        // ordered.

        // If a process is running, schedule it/us to run again.
        if (_current)
            readyListMethods.pushFirst(_current);
        // Schedule p to run first.
        readyListMethods.pushFirst(p);
        yield();
    }

    // Run this process at the next opportunity.
    void
    runNext(Process *p)
    {
        // Like above, it's ok if this isn't a method. Putting it on this list
        // just gives it priority.
        readyListMethods.pushFirst(p);
        if (!inEvaluate())
            scheduleReadyEvent();
    }

    // Set an event queue for scheduling events.
    void setEventQueue(EventQueue *_eq) { eq = _eq; }

    // Get the current time according to gem5.
    Tick getCurTick() { return eq ? eq->getCurTick() : 0; }

    Tick
    delayed(const ::sc_core::sc_time &delay)
    {
        return getCurTick() + delay.value();
    }

    // For scheduling delayed/timed notifications/timeouts.
    void
    schedule(ScEvent *event, const ::sc_core::sc_time &delay)
    {
        Tick tick = delayed(delay);
        if (tick < getCurTick())
            tick = getCurTick();

        // Delta notification/timeout.
        if (delay.value() == 0) {
            event->schedule(deltas, tick);
            if (!inEvaluate() && !inUpdate())
                scheduleReadyEvent();
            return;
        }

        // Timed notification/timeout.
        TimeSlot *&ts = timeSlots[tick];
        if (!ts) {
            ts = new TimeSlot;
            schedule(ts, tick);
        }
        event->schedule(ts->events, tick);
    }

    // For descheduling delayed/timed notifications/timeouts.
    void
    deschedule(ScEvent *event)
    {
        ScEvents *on = event->scheduledOn();

        if (on == &deltas) {
            event->deschedule();
            return;
        }

        // Timed notification/timeout.
        auto tsit = timeSlots.find(event->when());
        panic_if(tsit == timeSlots.end(),
                "Descheduling event at time with no events.");
        TimeSlot *ts = tsit->second;
        ScEvents &events = ts->events;
        assert(on == &events);
        event->deschedule();

        // If no more events are happening at this time slot, get rid of it.
        if (events.empty()) {
            deschedule(ts);
            timeSlots.erase(tsit);
        }
    }

    void
    completeTimeSlot(TimeSlot *ts)
    {
        assert(ts == timeSlots.begin()->second);
        timeSlots.erase(timeSlots.begin());
        if (!runToTime && starved())
            scheduleStarvationEvent();
        scheduleTimeAdvancesEvent();
    }

    // Pending activity ignores gem5 activity, much like how a systemc
    // simulation wouldn't know about asynchronous external events (socket IO
    // for instance) that might happen before time advances in a pure
    // systemc simulation. Also the spec lists what specific types of pending
    // activity needs to be counted, which obviously doesn't include gem5
    // events.

    // Return whether there's pending systemc activity at this time.
    bool
    pendingCurr()
    {
        return !readyListMethods.empty() || !readyListThreads.empty() ||
            !updateList.empty() || !deltas.empty();
    }

    // Return whether there are pending timed notifications or timeouts.
    bool
    pendingFuture()
    {
        return !timeSlots.empty();
    }

    // Return how many ticks there are until the first pending event, if any.
    Tick
    timeToPending()
    {
        if (pendingCurr())
            return 0;
        if (pendingFuture())
            return timeSlots.begin()->first - getCurTick();
        return MaxTick - getCurTick();
    }

    // Run scheduled channel updates.
    void runUpdate();

    // Run delta events.
    void runDelta();

    void start(Tick max_tick, bool run_to_time);
    void oneCycle();

    void schedulePause();
    void scheduleStop(bool finish_delta);

    enum Status
    {
        StatusOther = 0,
        StatusEvaluate,
        StatusUpdate,
        StatusDelta,
        StatusTiming,
        StatusPaused,
        StatusStopped
    };

    bool elaborationDone() { return _elaborationDone; }
    void elaborationDone(bool b) { _elaborationDone = b; }

    bool paused() { return status() == StatusPaused; }
    bool stopped() { return status() == StatusStopped; }
    bool inEvaluate() { return status() == StatusEvaluate; }
    bool inUpdate() { return status() == StatusUpdate; }
    bool inDelta() { return status() == StatusDelta; }
    bool inTiming() { return status() == StatusTiming; }

    uint64_t changeStamp() { return _changeStamp; }
    void stepChangeStamp() { _changeStamp++; }

    // Throw upwards, either to sc_main or to the report handler if sc_main
    // isn't running.
    void throwUp();

    Status status() { return _status; }
    void status(Status s) { _status = s; }

    void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); }
    void unregisterTraceFile(TraceFile *tf) { traceFiles.erase(tf); }

  private:
    typedef const EventBase::Priority Priority;
    static Priority DefaultPriority = EventBase::Default_Pri;

    static Priority StopPriority = DefaultPriority - 1;
    static Priority PausePriority = DefaultPriority + 1;
    static Priority MaxTickPriority = DefaultPriority + 2;
    static Priority ReadyPriority = DefaultPriority + 3;
    static Priority StarvationPriority = ReadyPriority;
    static Priority TimeAdvancesPriority = EventBase::Maximum_Pri;

    EventQueue *eq;

    // For gem5 style events.
    void
    schedule(::Event *event, Tick tick)
    {
        if (initDone)
            eq->schedule(event, tick);
        else
            eventsToSchedule[event] = tick;
    }

    void schedule(::Event *event) { schedule(event, getCurTick()); }

    void
    deschedule(::Event *event)
    {
        if (initDone)
            eq->deschedule(event);
        else
            eventsToSchedule.erase(event);
    }

    ScEvents deltas;
    TimeSlots timeSlots;

    Process *
    getNextReady()
    {
        Process *p = readyListMethods.getNext();
        return p ? p : readyListThreads.getNext();
    }

    void runReady();
    EventWrapper<Scheduler, &Scheduler::runReady> readyEvent;
    void scheduleReadyEvent();

    void pause();
    void stop();
    EventWrapper<Scheduler, &Scheduler::pause> pauseEvent;
    EventWrapper<Scheduler, &Scheduler::stop> stopEvent;

    const ::sc_core::sc_report *_throwUp;

    bool
    starved()
    {
        return (readyListMethods.empty() && readyListThreads.empty() &&
                updateList.empty() && deltas.empty() &&
                (timeSlots.empty() || timeSlots.begin()->first > maxTick) &&
                initList.empty());
    }
    EventWrapper<Scheduler, &Scheduler::pause> starvationEvent;
    void scheduleStarvationEvent();

    bool _elaborationDone;
    bool _started;
    bool _stopNow;

    Status _status;

    Tick maxTick;
    Tick lastReadyTick;
    void
    maxTickFunc()
    {
        if (lastReadyTick != getCurTick())
            _changeStamp++;
        pause();
    }
    EventWrapper<Scheduler, &Scheduler::maxTickFunc> maxTickEvent;

    void timeAdvances() { trace(false); }
    EventWrapper<Scheduler, &Scheduler::timeAdvances> timeAdvancesEvent;
    void
    scheduleTimeAdvancesEvent()
    {
        if (!traceFiles.empty() && !timeAdvancesEvent.scheduled())
            schedule(&timeAdvancesEvent);
    }

    uint64_t _numCycles;
    uint64_t _changeStamp;

    Process *_current;

    bool initDone;
    bool runToTime;
    bool runOnce;

    ProcessList initList;

    ProcessList readyListMethods;
    ProcessList readyListThreads;

    ChannelList updateList;

    ChannelList asyncUpdateList;
    std::mutex asyncListMutex;

    std::map<::Event *, Tick> eventsToSchedule;

    std::set<TraceFile *> traceFiles;

    void trace(bool delta);
};

extern Scheduler scheduler;

// A proxy function to avoid having to expose the scheduler in header files.
Process *getCurrentProcess();

inline void
Scheduler::TimeSlot::process()
{
    scheduler.stepChangeStamp();
    scheduler.status(StatusTiming);

    try {
        while (!events.empty())
            events.front()->run();
    } catch (...) {
        if (events.empty())
            scheduler.completeTimeSlot(this);
        else
            scheduler.schedule(this);
        scheduler.throwUp();
    }

    scheduler.status(StatusOther);
    scheduler.completeTimeSlot(this);
}

const ::sc_core::sc_report reportifyException();

} // namespace sc_gem5

#endif // __SYSTEMC_CORE_SCHEDULER_H__
<|endoftext|>


<commit_before>#include "openmc/tallies/filter_energy.h"

#include "openmc/capi.h"
#include "openmc/constants.h"  // For F90_NONE
#include "openmc/mgxs_interface.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// EnergyFilter implementation
//==============================================================================

void
EnergyFilter::from_xml(pugi::xml_node node)
{
  bins_ = get_node_array<double>(node, "bins");
  n_bins_ = bins_.size() - 1;

  // In MG mode, check if the filter bins match the transport bins.
  // We can save tallying time if we know that the tally bins match the energy
  // group structure.  In that case, the matching bin index is simply the group
  // (after flipping for the different ordering of the library and tallying
  // systems).
  if (!settings::run_CE) {
    if (n_bins_ == num_energy_groups) {
      matches_transport_groups_ = true;
      for (auto i = 0; i < n_bins_ + 1; i++) {
        if (rev_energy_bins[i] != bins_[i]) {
          matches_transport_groups_ = false;
          break;
        }
      }
    }
  }
}

void
EnergyFilter::get_all_bins(const Particle* p, int estimator, FilterMatch& match)
const
{
  if (p->g != F90_NONE && matches_transport_groups_) {
    if (estimator == ESTIMATOR_TRACKLENGTH) {
      //TODO: off-by-one
      match.bins_.push_back(num_energy_groups - p->g + 1);
    } else {
      //TODO: off-by-one
      match.bins_.push_back(num_energy_groups - p->last_g + 1);
    }
    match.weights_.push_back(1.0);

  } else {
    // Get the pre-collision energy of the particle.
    auto E = p->last_E;

    // Bin the energy.
    if (E >= bins_.front() && E <= bins_.back()) {
      //TODO: off-by-one
      auto bin = lower_bound_index(bins_.begin(), bins_.end(), E) + 1;
      match.bins_.push_back(bin);
      match.weights_.push_back(1.0);
    }
  }
}

void
EnergyFilter::to_statepoint(hid_t filter_group) const
{
  Filter::to_statepoint(filter_group);
  write_dataset(filter_group, "bins", bins_);
}

std::string
EnergyFilter::text_label(int bin) const
{
  std::stringstream out;
  //TODO: off-by-one
  out << "Incoming Energy [" << bins_[bin-1] << ", " << bins_[bin] << ")";
  return out.str();
}

//==============================================================================
// EnergyoutFilter implementation
//==============================================================================

void
EnergyoutFilter::get_all_bins(const Particle* p, int estimator,
                              FilterMatch& match) const
{
  if (p->g != F90_NONE && matches_transport_groups_) {
    match.bins_.push_back(num_energy_groups - p->g + 1);
    match.weights_.push_back(1.0);

  } else {
    if (p->E >= bins_.front() && p->E <= bins_.back()) {
      //TODO: off-by-one
      auto bin = lower_bound_index(bins_.begin(), bins_.end(), p->E) + 1;
      match.bins_.push_back(bin);
      match.weights_.push_back(1.0);
    }
  }
}

std::string
EnergyoutFilter::text_label(int bin) const
{
  std::stringstream out;
  //TODO: off-by-one
  out << "Outgoing Energy [" << bins_[bin-1] << ", " << bins_[bin] << ")";
  return out.str();
}

//==============================================================================
// Fortran interoperability
//==============================================================================

extern "C" bool energy_filter_matches_transport_groups(EnergyFilter* filt)
{return filt->matches_transport_groups_;}

extern "C" int
energy_filter_search(EnergyFilter* filt, double val)
{
  if (val < filt->bins_.front() || val > filt->bins_.back()) {
    return -1;
  } else {
    //TODO: off-by-one
    return lower_bound_index(filt->bins_.begin(), filt->bins_.end(), val) + 1;
  }
}

//==============================================================================
// C-API functions
//==============================================================================

extern"C" int
openmc_energy_filter_get_bins(int32_t index, double** energies, int32_t* n)
{
  // Make sure this is a valid index to an allocated filter.
  int err = verify_filter(index);
  if (err) return err;

  // Get a pointer to the filter and downcast.
  auto* filt_base = filter_from_f(index);
  auto* filt = dynamic_cast<EnergyFilter*>(filt_base);

  // Check the filter type.
  if (!filt) {
    set_errmsg("Tried to get energy bins on a non-energy filter.");
    return OPENMC_E_INVALID_TYPE;
  }

  // Output the bins.
  *energies = filt->bins_.data();
  *n = filt->bins_.size();
  return 0;
}

extern "C" int
openmc_energy_filter_set_bins(int32_t index, int32_t n, const double* energies)
{
  // Make sure this is a valid index to an allocated filter.
  int err = verify_filter(index);
  if (err) return err;

  // Get a pointer to the filter and downcast.
  auto* filt_base = filter_from_f(index);
  auto* filt = dynamic_cast<EnergyFilter*>(filt_base);

  // Check the filter type.
  if (!filt) {
    set_errmsg("Tried to set energy bins on a non-energy filter.");
    return OPENMC_E_INVALID_TYPE;
  }

  // Update the filter.
  filt->bins_.clear();
  filt->bins_.resize(n);
  for (int i = 0; i < n; i++) filt->bins_[i] = energies[i];
  filt->n_bins_ = n - 1;
  filter_update_n_bins(index);
}

}// namespace openmc
<commit_msg>Make sure openmc_energy_filter_set_bins returns an int<commit_after>#include "openmc/tallies/filter_energy.h"

#include "openmc/capi.h"
#include "openmc/constants.h"  // For F90_NONE
#include "openmc/mgxs_interface.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// EnergyFilter implementation
//==============================================================================

void
EnergyFilter::from_xml(pugi::xml_node node)
{
  bins_ = get_node_array<double>(node, "bins");
  n_bins_ = bins_.size() - 1;

  // In MG mode, check if the filter bins match the transport bins.
  // We can save tallying time if we know that the tally bins match the energy
  // group structure.  In that case, the matching bin index is simply the group
  // (after flipping for the different ordering of the library and tallying
  // systems).
  if (!settings::run_CE) {
    if (n_bins_ == num_energy_groups) {
      matches_transport_groups_ = true;
      for (auto i = 0; i < n_bins_ + 1; i++) {
        if (rev_energy_bins[i] != bins_[i]) {
          matches_transport_groups_ = false;
          break;
        }
      }
    }
  }
}

void
EnergyFilter::get_all_bins(const Particle* p, int estimator, FilterMatch& match)
const
{
  if (p->g != F90_NONE && matches_transport_groups_) {
    if (estimator == ESTIMATOR_TRACKLENGTH) {
      //TODO: off-by-one
      match.bins_.push_back(num_energy_groups - p->g + 1);
    } else {
      //TODO: off-by-one
      match.bins_.push_back(num_energy_groups - p->last_g + 1);
    }
    match.weights_.push_back(1.0);

  } else {
    // Get the pre-collision energy of the particle.
    auto E = p->last_E;

    // Bin the energy.
    if (E >= bins_.front() && E <= bins_.back()) {
      //TODO: off-by-one
      auto bin = lower_bound_index(bins_.begin(), bins_.end(), E) + 1;
      match.bins_.push_back(bin);
      match.weights_.push_back(1.0);
    }
  }
}

void
EnergyFilter::to_statepoint(hid_t filter_group) const
{
  Filter::to_statepoint(filter_group);
  write_dataset(filter_group, "bins", bins_);
}

std::string
EnergyFilter::text_label(int bin) const
{
  std::stringstream out;
  //TODO: off-by-one
  out << "Incoming Energy [" << bins_[bin-1] << ", " << bins_[bin] << ")";
  return out.str();
}

//==============================================================================
// EnergyoutFilter implementation
//==============================================================================

void
EnergyoutFilter::get_all_bins(const Particle* p, int estimator,
                              FilterMatch& match) const
{
  if (p->g != F90_NONE && matches_transport_groups_) {
    match.bins_.push_back(num_energy_groups - p->g + 1);
    match.weights_.push_back(1.0);

  } else {
    if (p->E >= bins_.front() && p->E <= bins_.back()) {
      //TODO: off-by-one
      auto bin = lower_bound_index(bins_.begin(), bins_.end(), p->E) + 1;
      match.bins_.push_back(bin);
      match.weights_.push_back(1.0);
    }
  }
}

std::string
EnergyoutFilter::text_label(int bin) const
{
  std::stringstream out;
  //TODO: off-by-one
  out << "Outgoing Energy [" << bins_[bin-1] << ", " << bins_[bin] << ")";
  return out.str();
}

//==============================================================================
// Fortran interoperability
//==============================================================================

extern "C" bool energy_filter_matches_transport_groups(EnergyFilter* filt)
{return filt->matches_transport_groups_;}

extern "C" int
energy_filter_search(EnergyFilter* filt, double val)
{
  if (val < filt->bins_.front() || val > filt->bins_.back()) {
    return -1;
  } else {
    //TODO: off-by-one
    return lower_bound_index(filt->bins_.begin(), filt->bins_.end(), val) + 1;
  }
}

//==============================================================================
// C-API functions
//==============================================================================

extern"C" int
openmc_energy_filter_get_bins(int32_t index, double** energies, int32_t* n)
{
  // Make sure this is a valid index to an allocated filter.
  int err = verify_filter(index);
  if (err) return err;

  // Get a pointer to the filter and downcast.
  auto* filt_base = filter_from_f(index);
  auto* filt = dynamic_cast<EnergyFilter*>(filt_base);

  // Check the filter type.
  if (!filt) {
    set_errmsg("Tried to get energy bins on a non-energy filter.");
    return OPENMC_E_INVALID_TYPE;
  }

  // Output the bins.
  *energies = filt->bins_.data();
  *n = filt->bins_.size();
  return 0;
}

extern "C" int
openmc_energy_filter_set_bins(int32_t index, int32_t n, const double* energies)
{
  // Make sure this is a valid index to an allocated filter.
  int err = verify_filter(index);
  if (err) return err;

  // Get a pointer to the filter and downcast.
  auto* filt_base = filter_from_f(index);
  auto* filt = dynamic_cast<EnergyFilter*>(filt_base);

  // Check the filter type.
  if (!filt) {
    set_errmsg("Tried to set energy bins on a non-energy filter.");
    return OPENMC_E_INVALID_TYPE;
  }

  // Update the filter.
  filt->bins_.clear();
  filt->bins_.resize(n);
  for (int i = 0; i < n; i++) filt->bins_[i] = energies[i];
  filt->n_bins_ = n - 1;
  filter_update_n_bins(index);
  return 0;
}

}// namespace openmc
<|endoftext|>


<commit_before>#include "ExecStats.h"

#include <iostream>
#include <iomanip>
#include <cassert>

namespace dev
{
namespace eth
{
namespace jit
{

void ExecStats::stateChanged(ExecState _state)
{
	if (!CHECK(m_state != ExecState::Finished))
		return;

	auto now = clock::now();
	if (_state != ExecState::Started)
	{
		assert(time[(int)m_state] == ExecStats::duration::zero());
		time[(int)m_state] = now - m_tp;
	}
	m_state = _state;
	m_tp = now;
}

namespace
{
struct StatsAgg
{
	using unit = std::chrono::microseconds;
	ExecStats::duration tot = ExecStats::duration::zero();
	ExecStats::duration min = ExecStats::duration::max();
	ExecStats::duration max = ExecStats::duration::zero();
	size_t count = 0;

	void update(ExecStats::duration _d)
	{
		++count;
		tot += _d;
		min = _d < min ? _d : min;
		max = _d > max ? _d : max;
	}

	void output(char const* _name, std::ostream& _os)
	{
		auto avg = tot / count;
		_os << std::setfill(' ')
			<< std::setw(12) << std::left  << _name
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(tot).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(avg).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(min).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(max).count()
			<< std::endl;
	}
};

char const* getExecStateName(ExecState _state)
{
	switch (_state)
	{
	case ExecState::Started: return "Start";
	case ExecState::CacheLoad: return "CacheLoad";
	case ExecState::CacheWrite: return "CacheWrite";
	case ExecState::Compilation: return "Compilation";
	case ExecState::CodeGen: return "CodeGen";
	case ExecState::Execution: return "Execution";
	case ExecState::Return: return "Return";
	case ExecState::Finished: return "Finish";
	}
	return nullptr;
}
}

StatsCollector::~StatsCollector()
{
	if (stats.empty())
		return;

	std::cout << "        [us]     total       avg       min       max\n";
	for (int i = 0; i < (int)ExecState::Finished; ++i)
	{
		StatsAgg agg;
		for (auto&& s : stats)
			agg.update(s->time[i]);

		agg.output(getExecStateName(ExecState(i)), std::cout);
	}
}

}
}
}
<commit_msg>Build fix<commit_after>#include "ExecStats.h"

#include <iostream>
#include <iomanip>
#include <cassert>

#include "Utils.h"

namespace dev
{
namespace eth
{
namespace jit
{

void ExecStats::stateChanged(ExecState _state)
{
	if (!CHECK(m_state != ExecState::Finished))
		return;

	auto now = clock::now();
	if (_state != ExecState::Started)
	{
		assert(time[(int)m_state] == ExecStats::duration::zero());
		time[(int)m_state] = now - m_tp;
	}
	m_state = _state;
	m_tp = now;
}

namespace
{
struct StatsAgg
{
	using unit = std::chrono::microseconds;
	ExecStats::duration tot = ExecStats::duration::zero();
	ExecStats::duration min = ExecStats::duration::max();
	ExecStats::duration max = ExecStats::duration::zero();
	size_t count = 0;

	void update(ExecStats::duration _d)
	{
		++count;
		tot += _d;
		min = _d < min ? _d : min;
		max = _d > max ? _d : max;
	}

	void output(char const* _name, std::ostream& _os)
	{
		auto avg = tot / count;
		_os << std::setfill(' ')
			<< std::setw(12) << std::left  << _name
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(tot).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(avg).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(min).count()
			<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(max).count()
			<< std::endl;
	}
};

char const* getExecStateName(ExecState _state)
{
	switch (_state)
	{
	case ExecState::Started: return "Start";
	case ExecState::CacheLoad: return "CacheLoad";
	case ExecState::CacheWrite: return "CacheWrite";
	case ExecState::Compilation: return "Compilation";
	case ExecState::CodeGen: return "CodeGen";
	case ExecState::Execution: return "Execution";
	case ExecState::Return: return "Return";
	case ExecState::Finished: return "Finish";
	}
	return nullptr;
}
}

StatsCollector::~StatsCollector()
{
	if (stats.empty())
		return;

	std::cout << "        [us]     total       avg       min       max\n";
	for (int i = 0; i < (int)ExecState::Finished; ++i)
	{
		StatsAgg agg;
		for (auto&& s : stats)
			agg.update(s->time[i]);

		agg.output(getExecStateName(ExecState(i)), std::cout);
	}
}

}
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/appcache/appcache_group.h"

#include <algorithm>

#include "base/logging.h"
#include "base/message_loop.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_service.h"
#include "webkit/appcache/appcache_storage.h"
#include "webkit/appcache/appcache_update_job.h"

namespace appcache {

class AppCacheGroup;

// Use this helper class because we cannot make AppCacheGroup a derived class
// of AppCacheHost::Observer as it would create a circular dependency between
// AppCacheHost and AppCacheGroup.
class AppCacheGroup::HostObserver : public AppCacheHost::Observer {
 public:
  explicit HostObserver(AppCacheGroup* group) : group_(group) {}

  // Methods for AppCacheHost::Observer.
  void OnCacheSelectionComplete(AppCacheHost* host) {}  // N/A
  void OnDestructionImminent(AppCacheHost* host) {
    group_->HostDestructionImminent(host);
  }
 private:
  AppCacheGroup* group_;
};

AppCacheGroup::AppCacheGroup(AppCacheService* service,
                             const GURL& manifest_url,
                             int64 group_id)
    : group_id_(group_id),
      manifest_url_(manifest_url),
      update_status_(IDLE),
      is_obsolete_(false),
      newest_complete_cache_(NULL),
      update_job_(NULL),
      service_(service),
      restart_update_task_(NULL) {
  service_->storage()->working_set()->AddGroup(this);
  host_observer_.reset(new HostObserver(this));
}

AppCacheGroup::~AppCacheGroup() {
  DCHECK(old_caches_.empty());
  DCHECK(!newest_complete_cache_);
  DCHECK(!restart_update_task_);
  DCHECK(queued_updates_.empty());

  if (update_job_)
    delete update_job_;
  DCHECK_EQ(IDLE, update_status_);

  service_->storage()->working_set()->RemoveGroup(this);
  service_->storage()->DeleteResponses(
      manifest_url_, newly_deletable_response_ids_);
}

void AppCacheGroup::AddUpdateObserver(UpdateObserver* observer) {
  // If observer being added is a host that has been queued for later update,
  // add observer to a different observer list.
  AppCacheHost* host = static_cast<AppCacheHost*>(observer);
  if (queued_updates_.find(host) != queued_updates_.end())
    queued_observers_.AddObserver(observer);
  else
    observers_.AddObserver(observer);
}

void AppCacheGroup::RemoveUpdateObserver(UpdateObserver* observer) {
  observers_.RemoveObserver(observer);
  queued_observers_.RemoveObserver(observer);
}

void AppCacheGroup::AddCache(AppCache* complete_cache) {
  DCHECK(complete_cache->is_complete());
  complete_cache->set_owning_group(this);

  if (!newest_complete_cache_) {
    newest_complete_cache_ = complete_cache;
    return;
  }

  if (complete_cache->IsNewerThan(newest_complete_cache_)) {
    old_caches_.push_back(newest_complete_cache_);
    newest_complete_cache_ = complete_cache;

    // Update hosts of older caches to add a reference to the newest cache.
    for (Caches::iterator it = old_caches_.begin();
         it != old_caches_.end(); ++it) {
      AppCache::AppCacheHosts& hosts = (*it)->associated_hosts();
      for (AppCache::AppCacheHosts::iterator host_it = hosts.begin();
           host_it != hosts.end(); ++host_it) {
        (*host_it)->SetSwappableCache(this);
      }
    }
  } else {
    old_caches_.push_back(complete_cache);
  }
}

void AppCacheGroup::RemoveCache(AppCache* cache) {
  DCHECK(cache->associated_hosts().empty());
  if (cache == newest_complete_cache_) {
    AppCache* tmp_cache = newest_complete_cache_;
    newest_complete_cache_ = NULL;
    tmp_cache->set_owning_group(NULL);  // may cause this group to be deleted
  } else {
    scoped_refptr<AppCacheGroup> protect(this);

    Caches::iterator it =
        std::find(old_caches_.begin(), old_caches_.end(), cache);
    if (it != old_caches_.end()) {
      AppCache* tmp_cache = *it;
      old_caches_.erase(it);
      tmp_cache->set_owning_group(NULL);  // may cause group to be released
    }

    if (!is_obsolete() && old_caches_.empty() &&
        !newly_deletable_response_ids_.empty()) {
      service_->storage()->DeleteResponses(
          manifest_url_, newly_deletable_response_ids_);
      newly_deletable_response_ids_.clear();
    }
  }
}

void AppCacheGroup::AddNewlyDeletableResponseIds(
    std::vector<int64>* response_ids) {
  if (!is_obsolete() && old_caches_.empty()) {
    service_->storage()->DeleteResponses(
        manifest_url_, *response_ids);
    response_ids->clear();
    return;
  }

  if (newly_deletable_response_ids_.empty()) {
    newly_deletable_response_ids_.swap(*response_ids);
    return;
  }
  newly_deletable_response_ids_.insert(
      newly_deletable_response_ids_.end(),
      response_ids->begin(), response_ids->end());
  response_ids->clear();
}

void AppCacheGroup::StartUpdateWithNewMasterEntry(
    AppCacheHost* host, const GURL& new_master_resource) {
  if (!update_job_)
    update_job_ = new AppCacheUpdateJob(service_, this);

  update_job_->StartUpdate(host, new_master_resource);

  // Run queued update immediately as an update has been started manually.
  if (restart_update_task_) {
    restart_update_task_->Cancel();
    restart_update_task_ = NULL;
    RunQueuedUpdates();
  }
}

void AppCacheGroup::QueueUpdate(AppCacheHost* host,
                                const GURL& new_master_resource) {
  DCHECK(update_job_ && host && !new_master_resource.is_empty());
  queued_updates_.insert(QueuedUpdates::value_type(host, new_master_resource));

  // Need to know when host is destroyed.
  host->AddObserver(host_observer_.get());

  // If host is already observing for updates, move host to queued observers
  // list so that host is not notified when the current update completes.
  if (FindObserver(host, observers_)) {
    observers_.RemoveObserver(host);
    queued_observers_.AddObserver(host);
  }
}

void AppCacheGroup::RunQueuedUpdates() {
  if (restart_update_task_)
    restart_update_task_ = NULL;

  if (queued_updates_.empty())
    return;

  QueuedUpdates updates_to_run;
  queued_updates_.swap(updates_to_run);
  DCHECK(queued_updates_.empty());

  for (QueuedUpdates::iterator it = updates_to_run.begin();
       it != updates_to_run.end(); ++it) {
    AppCacheHost* host = it->first;
    host->RemoveObserver(host_observer_.get());
    if (FindObserver(host, queued_observers_)) {
      queued_observers_.RemoveObserver(host);
      observers_.AddObserver(host);
    }

    if (!is_obsolete())
      StartUpdateWithNewMasterEntry(host, it->second);
  }
}

bool AppCacheGroup::FindObserver(UpdateObserver* find_me,
    const ObserverList<UpdateObserver>& observer_list) {
  ObserverList<UpdateObserver>::Iterator it(observer_list);
  UpdateObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    if (obs == find_me)
      return true;
  }
  return false;
}

void AppCacheGroup::ScheduleUpdateRestart(int delay_ms) {
  DCHECK(!restart_update_task_);
  restart_update_task_ =
      NewRunnableMethod(this, &AppCacheGroup::RunQueuedUpdates);
  MessageLoop::current()->PostDelayedTask(FROM_HERE, restart_update_task_,
                                          delay_ms);
}

void AppCacheGroup::HostDestructionImminent(AppCacheHost* host) {
  queued_updates_.erase(host);
  if (queued_updates_.empty() && restart_update_task_) {
    restart_update_task_->Cancel();
    restart_update_task_ = NULL;
  }
}

void AppCacheGroup::SetUpdateStatus(UpdateStatus status) {
  if (status == update_status_)
    return;

  update_status_ = status;

  if (status != IDLE) {
    DCHECK(update_job_);
  } else {
    update_job_ = NULL;

    // Note, this method may be called from within our destructor so we have
    // to be careful about calling addref and release in here. If there are
    // any observers, this will not be the case since each observer will have
    // a reference to us.
    if (observers_.size() || queued_observers_.size()) {
      // Observers may release us in these callbacks, so we protect against
      // deletion by adding an extra ref in this scope.
      scoped_refptr<AppCacheGroup> protect(this);
      FOR_EACH_OBSERVER(UpdateObserver, observers_, OnUpdateComplete(this));
      if (!queued_updates_.empty())
        ScheduleUpdateRestart(kUpdateRestartDelayMs);
    }
  }
}

}  // namespace appcache
<commit_msg>Revert 37466 - Fix a refcounting memory bug.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/appcache/appcache_group.h"

#include <algorithm>

#include "base/logging.h"
#include "base/message_loop.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_service.h"
#include "webkit/appcache/appcache_storage.h"
#include "webkit/appcache/appcache_update_job.h"

namespace appcache {

class AppCacheGroup;

// Use this helper class because we cannot make AppCacheGroup a derived class
// of AppCacheHost::Observer as it would create a circular dependency between
// AppCacheHost and AppCacheGroup.
class AppCacheGroup::HostObserver : public AppCacheHost::Observer {
 public:
  explicit HostObserver(AppCacheGroup* group) : group_(group) {}

  // Methods for AppCacheHost::Observer.
  void OnCacheSelectionComplete(AppCacheHost* host) {}  // N/A
  void OnDestructionImminent(AppCacheHost* host) {
    group_->HostDestructionImminent(host);
  }
 private:
  AppCacheGroup* group_;
};

AppCacheGroup::AppCacheGroup(AppCacheService* service,
                             const GURL& manifest_url,
                             int64 group_id)
    : group_id_(group_id),
      manifest_url_(manifest_url),
      update_status_(IDLE),
      is_obsolete_(false),
      newest_complete_cache_(NULL),
      update_job_(NULL),
      service_(service),
      restart_update_task_(NULL) {
  service_->storage()->working_set()->AddGroup(this);
  host_observer_.reset(new HostObserver(this));
}

AppCacheGroup::~AppCacheGroup() {
  DCHECK(old_caches_.empty());
  DCHECK(!newest_complete_cache_);
  DCHECK(!restart_update_task_);
  DCHECK(queued_updates_.empty());

  if (update_job_)
    delete update_job_;
  DCHECK_EQ(IDLE, update_status_);

  service_->storage()->working_set()->RemoveGroup(this);
  service_->storage()->DeleteResponses(
      manifest_url_, newly_deletable_response_ids_);
}

void AppCacheGroup::AddUpdateObserver(UpdateObserver* observer) {
  // If observer being added is a host that has been queued for later update,
  // add observer to a different observer list.
  AppCacheHost* host = static_cast<AppCacheHost*>(observer);
  if (queued_updates_.find(host) != queued_updates_.end())
    queued_observers_.AddObserver(observer);
  else
    observers_.AddObserver(observer);
}

void AppCacheGroup::RemoveUpdateObserver(UpdateObserver* observer) {
  observers_.RemoveObserver(observer);
  queued_observers_.RemoveObserver(observer);
}

void AppCacheGroup::AddCache(AppCache* complete_cache) {
  DCHECK(complete_cache->is_complete());
  complete_cache->set_owning_group(this);

  if (!newest_complete_cache_) {
    newest_complete_cache_ = complete_cache;
    return;
  }

  if (complete_cache->IsNewerThan(newest_complete_cache_)) {
    old_caches_.push_back(newest_complete_cache_);
    newest_complete_cache_ = complete_cache;

    // Update hosts of older caches to add a reference to the newest cache.
    for (Caches::iterator it = old_caches_.begin();
         it != old_caches_.end(); ++it) {
      AppCache::AppCacheHosts& hosts = (*it)->associated_hosts();
      for (AppCache::AppCacheHosts::iterator host_it = hosts.begin();
           host_it != hosts.end(); ++host_it) {
        (*host_it)->SetSwappableCache(this);
      }
    }
  } else {
    old_caches_.push_back(complete_cache);
  }
}

void AppCacheGroup::RemoveCache(AppCache* cache) {
  DCHECK(cache->associated_hosts().empty());
  if (cache == newest_complete_cache_) {
    AppCache* tmp_cache = newest_complete_cache_;
    newest_complete_cache_ = NULL;
    tmp_cache->set_owning_group(NULL);  // may cause this group to be deleted
  } else {
    scoped_refptr<AppCacheGroup> protect(this);

    Caches::iterator it =
        std::find(old_caches_.begin(), old_caches_.end(), cache);
    if (it != old_caches_.end()) {
      AppCache* tmp_cache = *it;
      old_caches_.erase(it);
      tmp_cache->set_owning_group(NULL);  // may cause group to be released
    }

    if (!is_obsolete() && old_caches_.empty() &&
        !newly_deletable_response_ids_.empty()) {
      service_->storage()->DeleteResponses(
          manifest_url_, newly_deletable_response_ids_);
      newly_deletable_response_ids_.clear();
    }
  }
}

void AppCacheGroup::AddNewlyDeletableResponseIds(
    std::vector<int64>* response_ids) {
  if (!is_obsolete() && old_caches_.empty()) {
    service_->storage()->DeleteResponses(
        manifest_url_, *response_ids);
    response_ids->clear();
    return;
  }

  if (newly_deletable_response_ids_.empty()) {
    newly_deletable_response_ids_.swap(*response_ids);
    return;
  }
  newly_deletable_response_ids_.insert(
      newly_deletable_response_ids_.end(),
      response_ids->begin(), response_ids->end());
  response_ids->clear();
}

void AppCacheGroup::StartUpdateWithNewMasterEntry(
    AppCacheHost* host, const GURL& new_master_resource) {
  if (!update_job_)
    update_job_ = new AppCacheUpdateJob(service_, this);

  update_job_->StartUpdate(host, new_master_resource);

  // Run queued update immediately as an update has been started manually.
  if (restart_update_task_) {
    restart_update_task_->Cancel();
    restart_update_task_ = NULL;
    RunQueuedUpdates();
  }
}

void AppCacheGroup::QueueUpdate(AppCacheHost* host,
                                const GURL& new_master_resource) {
  DCHECK(update_job_ && host && !new_master_resource.is_empty());
  queued_updates_.insert(QueuedUpdates::value_type(host, new_master_resource));

  // Need to know when host is destroyed.
  host->AddObserver(host_observer_.get());

  // If host is already observing for updates, move host to queued observers
  // list so that host is not notified when the current update completes.
  if (FindObserver(host, observers_)) {
    observers_.RemoveObserver(host);
    queued_observers_.AddObserver(host);
  }
}

void AppCacheGroup::RunQueuedUpdates() {
  if (restart_update_task_)
    restart_update_task_ = NULL;

  if (queued_updates_.empty())
    return;

  QueuedUpdates updates_to_run;
  queued_updates_.swap(updates_to_run);
  DCHECK(queued_updates_.empty());

  for (QueuedUpdates::iterator it = updates_to_run.begin();
       it != updates_to_run.end(); ++it) {
    AppCacheHost* host = it->first;
    host->RemoveObserver(host_observer_.get());
    if (FindObserver(host, queued_observers_)) {
      queued_observers_.RemoveObserver(host);
      observers_.AddObserver(host);
    }

    if (!is_obsolete())
      StartUpdateWithNewMasterEntry(host, it->second);
  }
}

bool AppCacheGroup::FindObserver(UpdateObserver* find_me,
    const ObserverList<UpdateObserver>& observer_list) {
  ObserverList<UpdateObserver>::Iterator it(observer_list);
  UpdateObserver* obs;
  while ((obs = it.GetNext()) != NULL) {
    if (obs == find_me)
      return true;
  }
  return false;
}

void AppCacheGroup::ScheduleUpdateRestart(int delay_ms) {
  DCHECK(!restart_update_task_);
  restart_update_task_ =
      NewRunnableMethod(this, &AppCacheGroup::RunQueuedUpdates);
  MessageLoop::current()->PostDelayedTask(FROM_HERE, restart_update_task_,
                                          delay_ms);
}

void AppCacheGroup::HostDestructionImminent(AppCacheHost* host) {
  queued_updates_.erase(host);
  if (queued_updates_.empty() && restart_update_task_) {
    restart_update_task_->Cancel();
    restart_update_task_ = NULL;
  }
}

void AppCacheGroup::SetUpdateStatus(UpdateStatus status) {
  if (status == update_status_)
    return;

  update_status_ = status;

  if (status != IDLE) {
    DCHECK(update_job_);
  } else {
    update_job_ = NULL;

    // Check member variable before notifying observers about update finishing.
    // Observers may remove reference to group, causing group to be deleted
    // after the notifications. If there are queued updates, then the group
    // will continue to exist.
    bool restart_update = !queued_updates_.empty();

    FOR_EACH_OBSERVER(UpdateObserver, observers_, OnUpdateComplete(this));

    if (restart_update)
      ScheduleUpdateRestart(kUpdateRestartDelayMs);
  }
}

}  // namespace appcache
<|endoftext|>


<commit_before>/*++
Copyright (c) 2012 Microsoft Corporation

Module Name:

    fpa2bv_tactic.cpp

Abstract:

    Tactic that converts floating points to bit-vectors

Author:

    Christoph (cwinter) 2012-02-09

Notes:

--*/
#include"tactical.h"
#include"fpa2bv_rewriter.h"
#include"simplify_tactic.h"
#include"fpa2bv_tactic.h"
#include"fpa2bv_model_converter.h"

class fpa2bv_tactic : public tactic {
    struct imp {
        ast_manager &     m;
        fpa2bv_converter  m_conv;
        fpa2bv_rewriter   m_rw;
        unsigned          m_num_steps;

        bool              m_proofs_enabled;
        bool              m_produce_models;
        bool              m_produce_unsat_cores;

        imp(ast_manager & _m, params_ref const & p):
            m(_m),
            m_conv(m),
            m_rw(m, m_conv, p),
            m_proofs_enabled(false),
            m_produce_models(false),
            m_produce_unsat_cores(false) {
            }

        void updt_params(params_ref const & p) {
            m_rw.cfg().updt_params(p);
        }

        virtual void operator()(goal_ref const & g,
                                goal_ref_buffer & result,
                                model_converter_ref & mc,
                                proof_converter_ref & pc,
                                expr_dependency_ref & core) {
            SASSERT(g->is_well_sorted());
            m_proofs_enabled      = g->proofs_enabled();
            m_produce_models      = g->models_enabled();
            m_produce_unsat_cores = g->unsat_core_enabled();

            mc = 0; pc = 0; core = 0; result.reset();
            tactic_report report("fpa2bv", *g);
            m_rw.reset();

            TRACE("fpa2bv", tout << "BEFORE: " << std::endl; g->display(tout););

            if (g->inconsistent()) {
                result.push_back(g.get());
                return;
            }

            m_num_steps = 0;
            expr_ref   new_curr(m);
            proof_ref  new_pr(m);
            unsigned size = g->size();
            for (unsigned idx = 0; idx < size; idx++) {
                if (g->inconsistent())
                    break;
                expr * curr = g->form(idx);
                m_rw(curr, new_curr, new_pr);
                m_num_steps += m_rw.get_num_steps();
                if (m_proofs_enabled) {
                    proof * pr = g->pr(idx);
                    new_pr     = m.mk_modus_ponens(pr, new_pr);
                }
                g->update(idx, new_curr, new_pr, g->dep(idx));

                if (is_app(new_curr)) {
                    const app * a = to_app(new_curr.get());
                    if (a->get_family_id() == m_conv.fu().get_family_id() &&
                        a->get_decl_kind() == OP_FPA_IS_NAN) {
                        // Inject auxiliary lemmas that fix e to the one and only NaN value,
                        // that is (= e (fp #b0 #b1...1 #b0...01)), so that the value propagation
                        // has a value to propagate.
                        expr * sgn, *sig, *exp;
                        expr_ref top_exp(m);
                        m_conv.split_fp(new_curr, sgn, exp, sig);
                        m.mk_eq(sgn, m_conv.bu().mk_numeral(0, 1));
                        m.mk_eq(exp, m_conv.bu().mk_numeral(-1, m_conv.bu().get_bv_size(exp)));
                        m.mk_eq(sig, m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(sig)));
                    }
                }
            }

            if (g->models_enabled())
                mc = mk_fpa2bv_model_converter(m, m_conv);

            g->inc_depth();
            result.push_back(g.get());

            for (unsigned i = 0; i < m_conv.m_extra_assertions.size(); i++)
                result.back()->assert_expr(m_conv.m_extra_assertions[i].get());

            SASSERT(g->is_well_sorted());
            TRACE("fpa2bv", tout << "AFTER: " << std::endl; g->display(tout);
                            if (mc) mc->display(tout); tout << std::endl; );
        }
    };

    imp *      m_imp;
    params_ref m_params;

public:
    fpa2bv_tactic(ast_manager & m, params_ref const & p):
        m_params(p) {
        m_imp = alloc(imp, m, p);
    }

    virtual tactic * translate(ast_manager & m) {
        return alloc(fpa2bv_tactic, m, m_params);
    }

    virtual ~fpa2bv_tactic() {
        dealloc(m_imp);
    }

    virtual void updt_params(params_ref const & p) {
        m_params = p;
        m_imp->updt_params(p);
    }

    virtual void collect_param_descrs(param_descrs & r) {
    }

    virtual void operator()(goal_ref const & in,
                            goal_ref_buffer & result,
                            model_converter_ref & mc,
                            proof_converter_ref & pc,
                            expr_dependency_ref & core) {
        try {
            (*m_imp)(in, result, mc, pc, core);
        }
        catch (rewriter_exception & ex) {
            throw tactic_exception(ex.msg());
        }
    }

    virtual void cleanup() {
        imp * d = alloc(imp, m_imp->m, m_params);
        std::swap(d, m_imp);
        dealloc(d);
    }

};

tactic * mk_fpa2bv_tactic(ast_manager & m, params_ref const & p) {
    return clean(alloc(fpa2bv_tactic, m, p));
}
<commit_msg>Fixed memory leak in fpa2bv tactic.<commit_after>/*++
Copyright (c) 2012 Microsoft Corporation

Module Name:

    fpa2bv_tactic.cpp

Abstract:

    Tactic that converts floating points to bit-vectors

Author:

    Christoph (cwinter) 2012-02-09

Notes:

--*/
#include"tactical.h"
#include"fpa2bv_rewriter.h"
#include"simplify_tactic.h"
#include"fpa2bv_tactic.h"
#include"fpa2bv_model_converter.h"

class fpa2bv_tactic : public tactic {
    struct imp {
        ast_manager &     m;
        fpa2bv_converter  m_conv;
        fpa2bv_rewriter   m_rw;
        unsigned          m_num_steps;

        bool              m_proofs_enabled;
        bool              m_produce_models;
        bool              m_produce_unsat_cores;

        imp(ast_manager & _m, params_ref const & p):
            m(_m),
            m_conv(m),
            m_rw(m, m_conv, p),
            m_proofs_enabled(false),
            m_produce_models(false),
            m_produce_unsat_cores(false) {
            }

        void updt_params(params_ref const & p) {
            m_rw.cfg().updt_params(p);
        }

        virtual void operator()(goal_ref const & g,
                                goal_ref_buffer & result,
                                model_converter_ref & mc,
                                proof_converter_ref & pc,
                                expr_dependency_ref & core) {
            SASSERT(g->is_well_sorted());
            m_proofs_enabled      = g->proofs_enabled();
            m_produce_models      = g->models_enabled();
            m_produce_unsat_cores = g->unsat_core_enabled();

            mc = 0; pc = 0; core = 0; result.reset();
            tactic_report report("fpa2bv", *g);
            m_rw.reset();

            TRACE("fpa2bv", tout << "BEFORE: " << std::endl; g->display(tout););

            if (g->inconsistent()) {
                result.push_back(g.get());
                return;
            }

            m_num_steps = 0;
            expr_ref   new_curr(m);
            proof_ref  new_pr(m);
            unsigned size = g->size();
            for (unsigned idx = 0; idx < size; idx++) {
                if (g->inconsistent())
                    break;
                expr * curr = g->form(idx);
                m_rw(curr, new_curr, new_pr);
                m_num_steps += m_rw.get_num_steps();
                if (m_proofs_enabled) {
                    proof * pr = g->pr(idx);
                    new_pr     = m.mk_modus_ponens(pr, new_pr);
                }
                g->update(idx, new_curr, new_pr, g->dep(idx));

                if (is_app(new_curr)) {
                    const app * a = to_app(new_curr.get());
                    if (a->get_family_id() == m_conv.fu().get_family_id() &&
                        a->get_decl_kind() == OP_FPA_IS_NAN) {
                        // Inject auxiliary lemmas that fix e to the one and only NaN value,
                        // that is (= e (fp #b0 #b1...1 #b0...01)), so that the value propagation
                        // has a value to propagate.
                        expr * sgn, *sig, *exp;
                        expr_ref top_exp(m);
                        m_conv.split_fp(new_curr, sgn, exp, sig);
                        result.back()->assert_expr(m.mk_eq(sgn, m_conv.bu().mk_numeral(0, 1)));
                        result.back()->assert_expr(m.mk_eq(exp, m_conv.bu().mk_numeral(-1, m_conv.bu().get_bv_size(exp))));
                        result.back()->assert_expr(m.mk_eq(sig, m_conv.bu().mk_numeral(1, m_conv.bu().get_bv_size(sig))));
                    }
                }
            }

            if (g->models_enabled())
                mc = mk_fpa2bv_model_converter(m, m_conv);

            g->inc_depth();
            result.push_back(g.get());

            for (unsigned i = 0; i < m_conv.m_extra_assertions.size(); i++)
                result.back()->assert_expr(m_conv.m_extra_assertions[i].get());

            SASSERT(g->is_well_sorted());
            TRACE("fpa2bv", tout << "AFTER: " << std::endl; g->display(tout);
                            if (mc) mc->display(tout); tout << std::endl; );
        }
    };

    imp *      m_imp;
    params_ref m_params;

public:
    fpa2bv_tactic(ast_manager & m, params_ref const & p):
        m_params(p) {
        m_imp = alloc(imp, m, p);
    }

    virtual tactic * translate(ast_manager & m) {
        return alloc(fpa2bv_tactic, m, m_params);
    }

    virtual ~fpa2bv_tactic() {
        dealloc(m_imp);
    }

    virtual void updt_params(params_ref const & p) {
        m_params = p;
        m_imp->updt_params(p);
    }

    virtual void collect_param_descrs(param_descrs & r) {
    }

    virtual void operator()(goal_ref const & in,
                            goal_ref_buffer & result,
                            model_converter_ref & mc,
                            proof_converter_ref & pc,
                            expr_dependency_ref & core) {
        try {
            (*m_imp)(in, result, mc, pc, core);
        }
        catch (rewriter_exception & ex) {
            throw tactic_exception(ex.msg());
        }
    }

    virtual void cleanup() {
        imp * d = alloc(imp, m_imp->m, m_params);
        std::swap(d, m_imp);
        dealloc(d);
    }

};

tactic * mk_fpa2bv_tactic(ast_manager & m, params_ref const & p) {
    return clean(alloc(fpa2bv_tactic, m, p));
}
<|endoftext|>