<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
 */

#include "config.h"
#include "JavaScriptDebugServer.h"

#include "DOMWindow.h"
#include "EventLoop.h"
#include "Frame.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "JSDOMWindowCustom.h"
#include "JavaScriptCallFrame.h"
#include "JavaScriptDebugListener.h"
#include "Page.h"
#include "PageGroup.h"
#include "PausedTimeouts.h"
#include "PluginView.h"
#include "ScrollView.h"
#include "Widget.h"
#include "ScriptController.h"
#include <kjs/DebuggerCallFrame.h>
#include <wtf/MainThread.h>
#include <wtf/UnusedParam.h>

using namespace JSC;

namespace WebCore {

typedef JavaScriptDebugServer::ListenerSet ListenerSet;

JavaScriptDebugServer& JavaScriptDebugServer::shared()
{
    static JavaScriptDebugServer server;
    return server;
}

JavaScriptDebugServer::JavaScriptDebugServer()
    : m_callingListeners(false)
    , m_pauseOnExceptions(false)
    , m_pauseOnNextStatement(false)
    , m_paused(false)
    , m_doneProcessingDebuggerEvents(true)
    , m_pauseOnCallFrame(0)
{
}

JavaScriptDebugServer::~JavaScriptDebugServer()
{
    deleteAllValues(m_pageListenersMap);
    deleteAllValues(m_breakpoints);
    deleteAllValues(m_pausedTimeouts);
}

void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener)
{
    if (!hasListeners())
        Page::setDebuggerForAllPages(this);

    m_listeners.add(listener);
}

void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener)
{
    m_listeners.remove(listener);
    if (!hasListeners()) {
        Page::setDebuggerForAllPages(0);
        m_doneProcessingDebuggerEvents = true;
    }
}

void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener, Page* page)
{
    ASSERT_ARG(page, page);

    if (!hasListeners())
        Page::setDebuggerForAllPages(this);

    pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0);
    if (result.second)
        result.first->second = new ListenerSet;
    ListenerSet* listeners = result.first->second;

    listeners->add(listener);
}

void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener, Page* page)
{
    ASSERT_ARG(page, page);

    PageListenersMap::iterator it = m_pageListenersMap.find(page);
    if (it == m_pageListenersMap.end())
        return;

    ListenerSet* listeners = it->second;

    listeners->remove(listener);

    if (listeners->isEmpty()) {
        m_pageListenersMap.remove(it);
        delete listeners;
    }

    if (!hasListeners()) {
        Page::setDebuggerForAllPages(0);
        m_doneProcessingDebuggerEvents = true;
    }
}

void JavaScriptDebugServer::pageCreated(Page* page)
{
    if (!hasListeners())
        return;

    page->setDebugger(this);
}

bool JavaScriptDebugServer::hasListenersInterestedInPage(Page* page)
{
    ASSERT_ARG(page, page);

    if (!m_listeners.isEmpty())
        return true;

    return m_pageListenersMap.contains(page);
}

void JavaScriptDebugServer::addBreakpoint(int sourceID, unsigned lineNumber)
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines) {
        lines = new HashSet<unsigned>;
        m_breakpoints.set(sourceID, lines);
    }

    lines->add(lineNumber);
}

void JavaScriptDebugServer::removeBreakpoint(int sourceID, unsigned lineNumber)
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines)
        return;

    lines->remove(lineNumber);

    if (!lines->isEmpty())
        return;

    m_breakpoints.remove(sourceID);
    delete lines;
}

bool JavaScriptDebugServer::hasBreakpoint(int sourceID, unsigned lineNumber) const
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines)
        return false;
    return lines->contains(lineNumber);
}

void JavaScriptDebugServer::clearBreakpoints()
{
    deleteAllValues(m_breakpoints);
    m_breakpoints.clear();
}

void JavaScriptDebugServer::setPauseOnExceptions(bool pause)
{
    m_pauseOnExceptions = pause;
}

void JavaScriptDebugServer::pauseProgram()
{
    m_pauseOnNextStatement = true;
}

void JavaScriptDebugServer::continueProgram()
{
    if (!m_paused)
        return;

    m_pauseOnNextStatement = false;
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepIntoStatement()
{
    if (!m_paused)
        return;

    m_pauseOnNextStatement = true;
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepOverStatement()
{
    if (!m_paused)
        return;

    m_pauseOnCallFrame = m_currentCallFrame.get();
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepOutOfFunction()
{
    if (!m_paused)
        return;

    m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->caller() : 0;
    m_doneProcessingDebuggerEvents = true;
}

JavaScriptCallFrame* JavaScriptDebugServer::currentCallFrame()
{
    if (!m_paused)
        return 0;
    return m_currentCallFrame.get();
}

static void dispatchDidParseSource(const ListenerSet& listeners, ExecState* exec, const JSC::SourceProvider& source, int startingLineNumber, const String& sourceURL, int sourceID)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        copy[i]->didParseSource(exec, source, startingLineNumber, sourceURL, sourceID);
}

static void dispatchFailedToParseSource(const ListenerSet& listeners, ExecState* exec, const SourceProvider& source, int startingLineNumber, const String& sourceURL, int errorLine, const String& errorMessage)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        copy[i]->failedToParseSource(exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
}

static Page* toPage(JSGlobalObject* globalObject)
{
    ASSERT_ARG(globalObject, globalObject);

    JSDOMWindow* window = asJSDOMWindow(globalObject);
    Frame* frame = window->impl()->frame();
    return frame ? frame->page() : 0;
}

void JavaScriptDebugServer::sourceParsed(ExecState* exec, int sourceID, const UString& sourceURL, const SourceProvider& source, int startingLineNumber, int errorLine, const UString& errorMessage)
{
    if (m_callingListeners)
        return;

    Page* page = toPage(exec->dynamicGlobalObject());
    if (!page)
        return;

    m_callingListeners = true;

    ASSERT(hasListeners());

    bool isError = errorLine != -1;

    if (!m_listeners.isEmpty()) {
        if (isError)
            dispatchFailedToParseSource(m_listeners, exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
        else
            dispatchDidParseSource(m_listeners, exec, source, startingLineNumber, sourceURL, sourceID);
    }

    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
        ASSERT(!pageListeners->isEmpty());
        if (isError)
            dispatchFailedToParseSource(*pageListeners, exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
        else
            dispatchDidParseSource(*pageListeners, exec, source, startingLineNumber, sourceURL, sourceID);
    }

    m_callingListeners = false;
}

static void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptDebugServer::JavaScriptExecutionCallback callback)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        (copy[i]->*callback)();
}

void JavaScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, Page* page)
{
    if (m_callingListeners)
        return;

    m_callingListeners = true;

    ASSERT(hasListeners());

    WebCore::dispatchFunctionToListeners(m_listeners, callback);
    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
        ASSERT(!pageListeners->isEmpty());
        WebCore::dispatchFunctionToListeners(*pageListeners, callback);
    }

    m_callingListeners = false;
}

void JavaScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused)
{
    setMainThreadCallbacksPaused(paused);

    const HashSet<Page*>& pages = pageGroup.pages();

    HashSet<Page*>::const_iterator end = pages.end();
    for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it)
        setJavaScriptPaused(*it, paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(Page* page, bool paused)
{
    ASSERT_ARG(page, page);

    page->setDefersLoading(paused);

    for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
        setJavaScriptPaused(frame, paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
{
    ASSERT_ARG(frame, frame);

    if (!frame->script()->isEnabled())
        return;

    frame->script()->setPaused(paused);

    if (JSDOMWindow* window = toJSDOMWindow(frame)) {
        if (paused) {
            OwnPtr<PausedTimeouts> timeouts;
            window->pauseTimeouts(timeouts);
            m_pausedTimeouts.set(frame, timeouts.release());
        } else {
            OwnPtr<PausedTimeouts> timeouts(m_pausedTimeouts.take(frame));
            window->resumeTimeouts(timeouts);
        }
    }

    setJavaScriptPaused(frame->view(), paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused)
{
#if !PLATFORM(MAC)
    if (!view)
        return;

    const HashSet<Widget*>* children = view->children();
    ASSERT(children);

    HashSet<Widget*>::iterator end = children->end();
    for (HashSet<Widget*>::iterator it = children->begin(); it != end; ++it) {
        Widget* widget = *it;
        if (!widget->isPluginView())
            continue;
        static_cast<PluginView*>(widget)->setJavaScriptPaused(paused);
    }
#endif
}

void JavaScriptDebugServer::pauseIfNeeded(Page* page)
{
    if (m_paused)
        return;

    if (!page || !hasListenersInterestedInPage(page))
        return;

    bool pauseNow = m_pauseOnNextStatement;
    pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
    pauseNow |= (m_currentCallFrame->line() > 0 && hasBreakpoint(m_currentCallFrame->sourceIdentifier(), m_currentCallFrame->line()));
    if (!pauseNow)
        return;

    m_pauseOnCallFrame = 0;
    m_pauseOnNextStatement = false;
    m_paused = true;

    dispatchFunctionToListeners(&JavaScriptDebugListener::didPause, page);

    setJavaScriptPaused(page->group(), true);

    TimerBase::fireTimersInNestedEventLoop();

    EventLoop loop;
    m_doneProcessingDebuggerEvents = false;
    while (!m_doneProcessingDebuggerEvents && !loop.ended())
        loop.cycle();

    setJavaScriptPaused(page->group(), false);

    m_paused = false;
}

void JavaScriptDebugServer::callEvent(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::atStatement(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::returnEvent(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));

    // Treat stepping over a return statement like stepping out.
    if (m_currentCallFrame == m_pauseOnCallFrame)
        m_pauseOnCallFrame = m_currentCallFrame->caller();
    m_currentCallFrame = m_currentCallFrame->caller();
}

void JavaScriptDebugServer::exception(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    if (m_pauseOnExceptions)
        m_pauseOnNextStatement = true;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));

    // Treat stepping over the end of a program like stepping out.
    if (m_currentCallFrame == m_pauseOnCallFrame)
        m_pauseOnCallFrame = m_currentCallFrame->caller();
    m_currentCallFrame = m_currentCallFrame->caller();
}

void JavaScriptDebugServer::didReachBreakpoint(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_pauseOnNextStatement = true;
    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

} // namespace WebCore
<commit_msg>Fix Qt bustage.<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  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.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
 */

#include "config.h"
#include "JavaScriptDebugServer.h"

#include "DOMWindow.h"
#include "EventLoop.h"
#include "Frame.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "JSDOMWindowCustom.h"
#include "JavaScriptCallFrame.h"
#include "JavaScriptDebugListener.h"
#include "Page.h"
#include "PageGroup.h"
#include "PausedTimeouts.h"
#include "PluginView.h"
#include "ScrollView.h"
#include "Widget.h"
#include "ScriptController.h"
#include <kjs/DebuggerCallFrame.h>
#include <wtf/MainThread.h>
#include <wtf/UnusedParam.h>

using namespace JSC;

namespace WebCore {

typedef JavaScriptDebugServer::ListenerSet ListenerSet;

JavaScriptDebugServer& JavaScriptDebugServer::shared()
{
    static JavaScriptDebugServer server;
    return server;
}

JavaScriptDebugServer::JavaScriptDebugServer()
    : m_callingListeners(false)
    , m_pauseOnExceptions(false)
    , m_pauseOnNextStatement(false)
    , m_paused(false)
    , m_doneProcessingDebuggerEvents(true)
    , m_pauseOnCallFrame(0)
{
}

JavaScriptDebugServer::~JavaScriptDebugServer()
{
    deleteAllValues(m_pageListenersMap);
    deleteAllValues(m_breakpoints);
    deleteAllValues(m_pausedTimeouts);
}

void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener)
{
    if (!hasListeners())
        Page::setDebuggerForAllPages(this);

    m_listeners.add(listener);
}

void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener)
{
    m_listeners.remove(listener);
    if (!hasListeners()) {
        Page::setDebuggerForAllPages(0);
        m_doneProcessingDebuggerEvents = true;
    }
}

void JavaScriptDebugServer::addListener(JavaScriptDebugListener* listener, Page* page)
{
    ASSERT_ARG(page, page);

    if (!hasListeners())
        Page::setDebuggerForAllPages(this);

    pair<PageListenersMap::iterator, bool> result = m_pageListenersMap.add(page, 0);
    if (result.second)
        result.first->second = new ListenerSet;
    ListenerSet* listeners = result.first->second;

    listeners->add(listener);
}

void JavaScriptDebugServer::removeListener(JavaScriptDebugListener* listener, Page* page)
{
    ASSERT_ARG(page, page);

    PageListenersMap::iterator it = m_pageListenersMap.find(page);
    if (it == m_pageListenersMap.end())
        return;

    ListenerSet* listeners = it->second;

    listeners->remove(listener);

    if (listeners->isEmpty()) {
        m_pageListenersMap.remove(it);
        delete listeners;
    }

    if (!hasListeners()) {
        Page::setDebuggerForAllPages(0);
        m_doneProcessingDebuggerEvents = true;
    }
}

void JavaScriptDebugServer::pageCreated(Page* page)
{
    if (!hasListeners())
        return;

    page->setDebugger(this);
}

bool JavaScriptDebugServer::hasListenersInterestedInPage(Page* page)
{
    ASSERT_ARG(page, page);

    if (!m_listeners.isEmpty())
        return true;

    return m_pageListenersMap.contains(page);
}

void JavaScriptDebugServer::addBreakpoint(int sourceID, unsigned lineNumber)
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines) {
        lines = new HashSet<unsigned>;
        m_breakpoints.set(sourceID, lines);
    }

    lines->add(lineNumber);
}

void JavaScriptDebugServer::removeBreakpoint(int sourceID, unsigned lineNumber)
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines)
        return;

    lines->remove(lineNumber);

    if (!lines->isEmpty())
        return;

    m_breakpoints.remove(sourceID);
    delete lines;
}

bool JavaScriptDebugServer::hasBreakpoint(int sourceID, unsigned lineNumber) const
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines)
        return false;
    return lines->contains(lineNumber);
}

void JavaScriptDebugServer::clearBreakpoints()
{
    deleteAllValues(m_breakpoints);
    m_breakpoints.clear();
}

void JavaScriptDebugServer::setPauseOnExceptions(bool pause)
{
    m_pauseOnExceptions = pause;
}

void JavaScriptDebugServer::pauseProgram()
{
    m_pauseOnNextStatement = true;
}

void JavaScriptDebugServer::continueProgram()
{
    if (!m_paused)
        return;

    m_pauseOnNextStatement = false;
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepIntoStatement()
{
    if (!m_paused)
        return;

    m_pauseOnNextStatement = true;
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepOverStatement()
{
    if (!m_paused)
        return;

    m_pauseOnCallFrame = m_currentCallFrame.get();
    m_doneProcessingDebuggerEvents = true;
}

void JavaScriptDebugServer::stepOutOfFunction()
{
    if (!m_paused)
        return;

    m_pauseOnCallFrame = m_currentCallFrame ? m_currentCallFrame->caller() : 0;
    m_doneProcessingDebuggerEvents = true;
}

JavaScriptCallFrame* JavaScriptDebugServer::currentCallFrame()
{
    if (!m_paused)
        return 0;
    return m_currentCallFrame.get();
}

static void dispatchDidParseSource(const ListenerSet& listeners, ExecState* exec, const JSC::SourceProvider& source, int startingLineNumber, const String& sourceURL, int sourceID)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        copy[i]->didParseSource(exec, source, startingLineNumber, sourceURL, sourceID);
}

static void dispatchFailedToParseSource(const ListenerSet& listeners, ExecState* exec, const SourceProvider& source, int startingLineNumber, const String& sourceURL, int errorLine, const String& errorMessage)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        copy[i]->failedToParseSource(exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
}

static Page* toPage(JSGlobalObject* globalObject)
{
    ASSERT_ARG(globalObject, globalObject);

    JSDOMWindow* window = asJSDOMWindow(globalObject);
    Frame* frame = window->impl()->frame();
    return frame ? frame->page() : 0;
}

void JavaScriptDebugServer::sourceParsed(ExecState* exec, int sourceID, const UString& sourceURL, const SourceProvider& source, int startingLineNumber, int errorLine, const UString& errorMessage)
{
    if (m_callingListeners)
        return;

    Page* page = toPage(exec->dynamicGlobalObject());
    if (!page)
        return;

    m_callingListeners = true;

    ASSERT(hasListeners());

    bool isError = errorLine != -1;

    if (!m_listeners.isEmpty()) {
        if (isError)
            dispatchFailedToParseSource(m_listeners, exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
        else
            dispatchDidParseSource(m_listeners, exec, source, startingLineNumber, sourceURL, sourceID);
    }

    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
        ASSERT(!pageListeners->isEmpty());
        if (isError)
            dispatchFailedToParseSource(*pageListeners, exec, source, startingLineNumber, sourceURL, errorLine, errorMessage);
        else
            dispatchDidParseSource(*pageListeners, exec, source, startingLineNumber, sourceURL, sourceID);
    }

    m_callingListeners = false;
}

static void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptDebugServer::JavaScriptExecutionCallback callback)
{
    Vector<JavaScriptDebugListener*> copy;
    copyToVector(listeners, copy);
    for (size_t i = 0; i < copy.size(); ++i)
        (copy[i]->*callback)();
}

void JavaScriptDebugServer::dispatchFunctionToListeners(JavaScriptExecutionCallback callback, Page* page)
{
    if (m_callingListeners)
        return;

    m_callingListeners = true;

    ASSERT(hasListeners());

    WebCore::dispatchFunctionToListeners(m_listeners, callback);
    if (ListenerSet* pageListeners = m_pageListenersMap.get(page)) {
        ASSERT(!pageListeners->isEmpty());
        WebCore::dispatchFunctionToListeners(*pageListeners, callback);
    }

    m_callingListeners = false;
}

void JavaScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused)
{
    setMainThreadCallbacksPaused(paused);

    const HashSet<Page*>& pages = pageGroup.pages();

    HashSet<Page*>::const_iterator end = pages.end();
    for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it)
        setJavaScriptPaused(*it, paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(Page* page, bool paused)
{
    ASSERT_ARG(page, page);

    page->setDefersLoading(paused);

    for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext())
        setJavaScriptPaused(frame, paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
{
    ASSERT_ARG(frame, frame);

    if (!frame->script()->isEnabled())
        return;

    frame->script()->setPaused(paused);

    if (JSDOMWindow* window = toJSDOMWindow(frame)) {
        if (paused) {
            OwnPtr<PausedTimeouts> timeouts;
            window->pauseTimeouts(timeouts);
            m_pausedTimeouts.set(frame, timeouts.release());
        } else {
            OwnPtr<PausedTimeouts> timeouts(m_pausedTimeouts.take(frame));
            window->resumeTimeouts(timeouts);
        }
    }

    setJavaScriptPaused(frame->view(), paused);
}

void JavaScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused)
{
#if !PLATFORM(MAC)
    if (!view)
        return;

    const HashSet<Widget*>* children = view->children();
    ASSERT(children);

    HashSet<Widget*>::const_iterator end = children->end();
    for (HashSet<Widget*>::const_iterator it = children->begin(); it != end; ++it) {
        Widget* widget = *it;
        if (!widget->isPluginView())
            continue;
        static_cast<PluginView*>(widget)->setJavaScriptPaused(paused);
    }
#endif
}

void JavaScriptDebugServer::pauseIfNeeded(Page* page)
{
    if (m_paused)
        return;

    if (!page || !hasListenersInterestedInPage(page))
        return;

    bool pauseNow = m_pauseOnNextStatement;
    pauseNow |= (m_pauseOnCallFrame == m_currentCallFrame);
    pauseNow |= (m_currentCallFrame->line() > 0 && hasBreakpoint(m_currentCallFrame->sourceIdentifier(), m_currentCallFrame->line()));
    if (!pauseNow)
        return;

    m_pauseOnCallFrame = 0;
    m_pauseOnNextStatement = false;
    m_paused = true;

    dispatchFunctionToListeners(&JavaScriptDebugListener::didPause, page);

    setJavaScriptPaused(page->group(), true);

    TimerBase::fireTimersInNestedEventLoop();

    EventLoop loop;
    m_doneProcessingDebuggerEvents = false;
    while (!m_doneProcessingDebuggerEvents && !loop.ended())
        loop.cycle();

    setJavaScriptPaused(page->group(), false);

    m_paused = false;
}

void JavaScriptDebugServer::callEvent(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::atStatement(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::returnEvent(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));

    // Treat stepping over a return statement like stepping out.
    if (m_currentCallFrame == m_pauseOnCallFrame)
        m_pauseOnCallFrame = m_currentCallFrame->caller();
    m_currentCallFrame = m_currentCallFrame->caller();
}

void JavaScriptDebugServer::exception(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    if (m_pauseOnExceptions)
        m_pauseOnNextStatement = true;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::willExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    m_currentCallFrame = JavaScriptCallFrame::create(debuggerCallFrame, m_currentCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

void JavaScriptDebugServer::didExecuteProgram(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));

    // Treat stepping over the end of a program like stepping out.
    if (m_currentCallFrame == m_pauseOnCallFrame)
        m_pauseOnCallFrame = m_currentCallFrame->caller();
    m_currentCallFrame = m_currentCallFrame->caller();
}

void JavaScriptDebugServer::didReachBreakpoint(const DebuggerCallFrame& debuggerCallFrame, int sourceID, int lineNumber)
{
    if (m_paused)
        return;

    ASSERT(m_currentCallFrame);
    if (!m_currentCallFrame)
        return;

    m_pauseOnNextStatement = true;
    m_currentCallFrame->update(debuggerCallFrame, sourceID, lineNumber);
    pauseIfNeeded(toPage(debuggerCallFrame.dynamicGlobalObject()));
}

} // namespace WebCore
<|endoftext|>


<commit_before>#include "./SDARecoTimeAtThr.h"
#include "../JPetRecoSignalTools/JPetRecoSignalTools.h"
#include "sstream"
#include <stdlib.h>

ClassImp(SDARecoTimeAtThr);

SDARecoTimeAtThr::SDARecoTimeAtThr(const char* name, const char* title,
                           const char* in_file_suffix, const char* out_file_suffix, const std::vector<double>& thr) :
  JPetCommonAnalysisModule(name, title, in_file_suffix, out_file_suffix)
{
  setVersion(MODULE_VERSION);
  fThresholds = thr;
}

SDARecoTimeAtThr::~SDARecoTimeAtThr()
{
}

void SDARecoTimeAtThr::begin()
{
	INFO(
      Form("Amount of signals in file: %d", fEventNb ) );
      fSignalsBelowThreshold = 0;
}

void SDARecoTimeAtThr::exec()
{

  // first take signal from fEvent
  fReader->getEntry(fEvent);
  const JPetRecoSignal signal = (JPetRecoSignal&) fReader->getData();

  //to save Reco signal one needs to copy it to non const variable
  JPetRecoSignal signalWithOffset = signal;
  //Calculate time at threshold
  for(unsigned int i = 0; i < fThresholds.size(); i++)
  {
	  double timeAtThr = JPetRecoSignalTools::calculateTimeAtThreshold(signal, fThresholds[i]);
	    //Checking if times crossed threshold, if not its value is set to 999999
	  if (timeAtThr == JPetRecoSignalTools::ERRORS::badTimeAtThr) {
        	INFO( Form("Signal has smaller amplitude than given threshold: %f for event %d ",fThresholds[i] , fEvent) );
	        fSignalsBelowThreshold++;
		signalWithOffset.setRecoTimeAtThreshold(fThresholds[i], 0);
		break;
	  }
	  std::cout << timeAtThr << std::endl;
	  //setting time at threshold for new signal of signal
	signalWithOffset.setRecoTimeAtThreshold(fThresholds[i], timeAtThr);
  }
  //saving singal into output root file
  if (0 != signalWithOffset.getRecoTimeAtThreshold(fThresholds[0]) )
	fWriter->write(signalWithOffset);
  // increase event counter
  fEvent++;
}

void SDARecoTimeAtThr::end()
{
double goodPercent = (fEventNb-fSignalsBelowThreshold) * 100.0/fEventNb;

	INFO(
	Form("Time at threshold calculation complete \nAmount of bad signals: %d \n %f %% of data is good" , fSignalsBelowThreshold, goodPercent) );

}
<commit_msg>Clean commented code<commit_after>#include "./SDARecoTimeAtThr.h"
#include "../JPetRecoSignalTools/JPetRecoSignalTools.h"
#include "sstream"
#include <stdlib.h>

ClassImp(SDARecoTimeAtThr);

SDARecoTimeAtThr::SDARecoTimeAtThr(const char* name, const char* title,
                           const char* in_file_suffix, const char* out_file_suffix, const std::vector<double>& thr) :
  JPetCommonAnalysisModule(name, title, in_file_suffix, out_file_suffix)
{
  setVersion(MODULE_VERSION);
  fThresholds = thr;
}

SDARecoTimeAtThr::~SDARecoTimeAtThr()
{
}

void SDARecoTimeAtThr::begin()
{
	INFO(
      Form("Amount of signals in file: %d", fEventNb ) );
      fSignalsBelowThreshold = 0;
}

void SDARecoTimeAtThr::exec()
{

  // first take signal from fEvent
  fReader->getEntry(fEvent);
  const JPetRecoSignal signal = (JPetRecoSignal&) fReader->getData();

  //to save Reco signal one needs to copy it to non const variable
  JPetRecoSignal signalWithOffset = signal;
  //Calculate time at threshold
  for(unsigned int i = 0; i < fThresholds.size(); i++)
  {
	  double timeAtThr = JPetRecoSignalTools::calculateTimeAtThreshold(signal, fThresholds[i]);
	    //Checking if times crossed threshold, if not its value is set to 999999
	  if (timeAtThr == JPetRecoSignalTools::ERRORS::badTimeAtThr) {
        	INFO( Form("Signal has smaller amplitude than given threshold: %f for event %d ",fThresholds[i] , fEvent) );
	        fSignalsBelowThreshold++;
		signalWithOffset.setRecoTimeAtThreshold(fThresholds[i], 0);
		break;
	  }
	  //setting time at threshold for new signal of signal
	signalWithOffset.setRecoTimeAtThreshold(fThresholds[i], timeAtThr);
  }
  //saving singal into output root file
  if (0 != signalWithOffset.getRecoTimeAtThreshold(fThresholds[0]) )
	fWriter->write(signalWithOffset);
  // increase event counter
  fEvent++;
}

void SDARecoTimeAtThr::end()
{
double goodPercent = (fEventNb-fSignalsBelowThreshold) * 100.0/fEventNb;

	INFO(
	Form("Time at threshold calculation complete \nAmount of bad signals: %d \n %f %% of data is good" , fSignalsBelowThreshold, goodPercent) );

}
<|endoftext|>


<commit_before>#include "CommandSequence.h"
#include "Servo.h"
#include "UserLeds.h"

#include <BlackGPIO.h>

#include <cmath>
#include <iostream>

#include <signal.h>

using namespace avc;
using namespace std;

/**
 * Definition of the RC car to control.
 */
class RcCar : public CommandSequence {

private:
  Servo _steer;
  Servo _esc;
  int _wayPoint;

public:
  RcCar() :
    CommandSequence("RcCar"),
    _steer(BlackLib::P9_14, -40.0, 40.0),
    _esc(BlackLib::P9_21, -1.0, +1.0),
    _wayPoint(1)
  {
  }

  ~RcCar() {
    _steer.set(0);
    _esc.set(0);
    _steer.disable();
    _esc.disable();
  }

  void nextWaypoint() {
    UserLeds& leds = UserLeds::getInstance();
    leds.setState(_wayPoint++);
  }

  void doInitialize() {
    _wayPoint = 1;
    CommandSequence::doInitialize();
  }

  void seekSpeed(float power, float maxStep = 0.05) {
    _esc.seek(power, maxStep);
  }

  void seekSteer(float ang, float maxStep = 2.0) {
    _steer.seek(ang, maxStep);
  }

  void coast() {
    _esc.set(0.0);
  }

  void setSteer(float angle) {
    _steer.set(0.0);
  }

  float getAngle() {
    // TODO - Need gyro reading or some other way to get angle of car
    return 0.0;
  }

  bool detectedCorner() {
    // TODO - Need to figure out this from vision
    return false;
  }

  std::ostream& print(std::ostream& out, const Command& cmd) const {
    out << cmd << "  Car(steer=" << _steer.get() << ", power="
	<< _esc.get() << ")";
    return out;
  }

};

/**
 * Command to drive straight down the road until the turn point is detected.
 */
class DriveToTurn : public Command {

public:
  DriveToTurn(RcCar& car, float power, float timeout = 10.0) :
    Command("DriveToTurn", timeout),
    _car(car),
    _power(power)
  {
  }

  void doInitialize() {
    _car.print(cout, *this) << "\n";
  }

  Command::State doExecute() {
    _car.seekSpeed(_power);
    _car.setSteer(0.0);
    bool foundCorner = _car.detectedCorner();
    // TODO: Remove this time out override once we can detect the corner
    foundCorner = ((getElapsedTime() / getTimeout()) >= 0.5);
    _car.print(cout, *this) << "\n";
    return (foundCorner ? Command::NORMAL_END : Command::STILL_RUNNING);
  }

  void doEnd(Command::State reason) {
    _car.print(cout, *this) << "\n";
    _car.coast();
    _car.nextWaypoint();
  }

private:
  RcCar& _car;
  float _power;
};

/**
 * Command to make a turn.
 */
class MakeTurn : public Command {

public:

  MakeTurn(RcCar& car, float relativeAng = 90.0) :
    Command("MakeTurn", 1.0),
    _car(car),
    _relativeAng(relativeAng),
    _targetAng(0)
  {
  }

  ~MakeTurn() { }

  void doInitialize() {
    _car.print(cout, *this) << "\n";
    _targetAng = _car.getAngle() + _relativeAng;
  }

  Command::State doExecute() {
    _car.seekSpeed(0.15);

    float carAng = _car.getAngle();
    float err = _targetAng - carAng;

    // TODO: Delete once we figure out how to get angle (the
    // statement below makes
    float percentTimeElapsed = getElapsedTime() / getTimeout();
    err = (percentTimeElapsed >= 0.5) ? 0.0 : (1.1 - percentTimeElapsed) * _relativeAng;

    // Limit to 25 degree steer in either direction
    float steer = min(25.0f, max(-25.0f, err));
    _car.seekSteer(steer);

    _car.print(cout, *this) << "  err: " << err << "\n";

    // Done if within 3 degrees
    return ((abs(err) < 3.0) ? Command::NORMAL_END : Command::STILL_RUNNING);
  }

  void doEnd(Command::State reason) {
    _car.print(cout, *this) << "\n";
    _car.setSteer(0);
    _car.coast();
  }

private:
  RcCar& _car;
  // How much to turn (in signed degrees)
  float _relativeAng;
  float _targetAng;
};

namespace {
  // Flag will be set when user terminates via ^C or uses kill on process
  bool hasBeenInterrupted = false;

  void interrupted(int sig) {
    hasBeenInterrupted = true;
  }
}

int main(int argc, const char** argv) {
  signal(SIGINT, interrupted);
  signal(SIGTERM, interrupted);
  UserLeds& leds = UserLeds::getInstance();
  int waitCnt = 0;

  // Start button connected to P9 pin 23 (GPIO_49)
  BlackLib::BlackGPIO startButton(BlackLib::GPIO_49, BlackLib::input);
  bool startWasHigh = startButton.isHigh();

  cout << "Entering main loop - waiting for trigger ...\n";

  while (hasBeenInterrupted == false) {

    bool startIsHigh = startButton.isHigh();

    // Run auton when button is pressed and then released
    if ((startWasHigh == true) && (startIsHigh == false)) {
      leds.setState(0xf);
      cout << "Button released, starting auton\n";
      RcCar car;

      // Short drive to first corner
      car.add(new DriveToTurn(car, 0.5, 1.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Long drive to second corner
      car.add(new DriveToTurn(car, 0.5, 3.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Medium drive to third corner
      car.add(new DriveToTurn(car, 0.5, 2.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Long drive to fourth corner
      car.add(new DriveToTurn(car, 0.5, 3.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Short drive to finish line
      car.add(new DriveToTurn(car, 0.5, 1.0));

      Timer autonTimer;
      Command::run(car);
      cout << "Auton completed in " << autonTimer.secsElapsed() << " seconds\n";
    } else {
      Timer::sleep(0.05);
      int ledState = waitCnt & 0xf;
      leds.setState(ledState);
      if (ledState == 0) {
	      waitCnt = 1;
      } else {
	      waitCnt <<= 1;
      }
    }
    leds.setState(0x0);
    // Save prior state
    startWasHigh = startIsHigh;
  }

  cout << "Terminated by external signal\n";

  return 0;
}
<commit_msg>Updated the example commands to remove stopping the motors at each end point<commit_after>#include "CommandSequence.h"
#include "Servo.h"
#include "UserLeds.h"

#include <BlackGPIO.h>

#include <cmath>
#include <iostream>

#include <signal.h>

using namespace avc;
using namespace std;

/**
 * Definition of the RC car to control.
 */
class RcCar : public CommandSequence {

private:
  Servo _steer;
  Servo _esc;
  int _wayPoint;

public:
  RcCar() :
    CommandSequence("RcCar"),
    _steer(BlackLib::P9_14, -40.0, 40.0),
    _esc(BlackLib::P9_21, -1.0, +1.0),
    _wayPoint(1)
  {
  }

  ~RcCar() {
    _steer.set(0);
    _esc.set(0);
    _steer.disable();
    _esc.disable();
  }

  void nextWaypoint() {
    UserLeds& leds = UserLeds::getInstance();
    leds.setState(_wayPoint++);
  }

  void doInitialize() {
    _wayPoint = 1;
    CommandSequence::doInitialize();
  }

  void seekSpeed(float power, float maxStep = 0.05) {
    _esc.seek(power, maxStep);
  }

  void seekSteer(float ang, float maxStep = 2.0) {
    _steer.seek(ang, maxStep);
  }

  void coast() {
    _esc.set(0.0);
  }

  void setSteer(float angle) {
    _steer.set(0.0);
  }

  float getAngle() {
    // TODO - Need gyro reading or some other way to get angle of car
    return 0.0;
  }

  bool detectedCorner() {
    // TODO - Need to figure out this from vision
    return false;
  }

  std::ostream& print(std::ostream& out, const Command& cmd) const {
    out << cmd << "  Car(steer=" << _steer.get() << ", power="
	<< _esc.get() << ")";
    return out;
  }

};

/**
 * Command to drive straight down the road until the turn point is detected.
 */
class DriveToTurn : public Command {

public:
  DriveToTurn(RcCar& car, float power, float timeout = 10.0) :
    Command("DriveToTurn", timeout),
    _car(car),
    _power(power)
  {
  }

  void doInitialize() {
    _car.print(cout, *this) << "\n";
  }

  Command::State doExecute() {
    _car.seekSpeed(_power);
    _car.setSteer(0.0);
    bool foundCorner = _car.detectedCorner();
    // TODO: Remove this time out override once we can detect the corner
    foundCorner = ((getElapsedTime() / getTimeout()) >= 0.5);
    _car.print(cout, *this) << "\n";
    return (foundCorner ? Command::NORMAL_END : Command::STILL_RUNNING);
  }

  void doEnd(Command::State reason) {
    _car.print(cout, *this) << "\n";
    _car.nextWaypoint();
  }

private:
  RcCar& _car;
  float _power;
};

/**
 * Command to make a turn.
 */
class MakeTurn : public Command {

public:

  MakeTurn(RcCar& car, float relativeAng = 90.0) :
    Command("MakeTurn", 1.0),
    _car(car),
    _relativeAng(relativeAng),
    _targetAng(0)
  {
  }

  ~MakeTurn() { }

  void doInitialize() {
    _car.print(cout, *this) << "\n";
    _targetAng = _car.getAngle() + _relativeAng;
  }

  Command::State doExecute() {
    _car.seekSpeed(0.15);

    float carAng = _car.getAngle();
    float err = _targetAng - carAng;

    // TODO: Delete once we figure out how to get angle (the
    // statement below makes
    float percentTimeElapsed = getElapsedTime() / getTimeout();
    err = (percentTimeElapsed >= 0.5) ? 0.0 : (1.1 - percentTimeElapsed) * _relativeAng;

    // Limit to 25 degree steer in either direction
    float steer = min(25.0f, max(-25.0f, err));
    _car.seekSteer(steer);

    _car.print(cout, *this) << "  err: " << err << "\n";

    // Done if within 3 degrees
    return ((abs(err) < 3.0) ? Command::NORMAL_END : Command::STILL_RUNNING);
  }

  void doEnd(Command::State reason) {
    _car.print(cout, *this) << "\n";
    _car.setSteer(0);
  }

private:
  RcCar& _car;
  // How much to turn (in signed degrees)
  float _relativeAng;
  float _targetAng;
};

namespace {
  // Flag will be set when user terminates via ^C or uses kill on process
  bool hasBeenInterrupted = false;

  void interrupted(int sig) {
    hasBeenInterrupted = true;
  }
}

int main(int argc, const char** argv) {
  signal(SIGINT, interrupted);
  signal(SIGTERM, interrupted);
  UserLeds& leds = UserLeds::getInstance();
  int waitCnt = 0;

  // Start button connected to P9 pin 23 (GPIO_49)
  BlackLib::BlackGPIO startButton(BlackLib::GPIO_49, BlackLib::input);
  bool startWasHigh = startButton.isHigh();

  cout << "Entering main loop - waiting for trigger ...\n";

  while (hasBeenInterrupted == false) {

    bool startIsHigh = startButton.isHigh();

    // Run auton when button is pressed and then released
    if ((startWasHigh == true) && (startIsHigh == false)) {
      leds.setState(0xf);
      cout << "Button released, starting auton\n";
      RcCar car;

      // Short drive to first corner
      car.add(new DriveToTurn(car, 0.5, 1.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Long drive to second corner
      car.add(new DriveToTurn(car, 0.5, 3.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Medium drive to third corner
      car.add(new DriveToTurn(car, 0.5, 2.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Long drive to fourth corner
      car.add(new DriveToTurn(car, 0.5, 3.0));
      // Make a right hand turn
      car.add(new MakeTurn(car, 90.0));
      // Short drive to finish line
      car.add(new DriveToTurn(car, 0.5, 1.0));
      // And stop (should probably just have a command for this)
      car.add(new DriveToTurn(car, 0.0, 1.0));

      Timer autonTimer;
      Command::run(car);
      cout << "Auton completed in " << autonTimer.secsElapsed() << " seconds\n";
    } else {
      Timer::sleep(0.05);
      int ledState = waitCnt & 0xf;
      leds.setState(ledState);
      if (ledState == 0) {
	      waitCnt = 1;
      } else {
	      waitCnt <<= 1;
      }
    }
    leds.setState(0x0);
    // Save prior state
    startWasHigh = startIsHigh;
  }

  cout << "Terminated by external signal\n";

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <vector>

#include "pin.H"

#include "AnalysisProcessor.h"
#include "IRBuilder.h"
#include "IRBuilderFactory.h"
#include "Inst.h"
#include "PINContextHandler.h"
#include "ProcessingPyConf.h"
#include "Trigger.h"
#include <boost/filesystem.hpp>

using boost::filesystem::absolute;
using boost::filesystem::path;

/* Pin options: -script */
KNOB<std::string>   KnobPythonModule(KNOB_MODE_WRITEONCE, "pintool", "script", "", "Python script");

AnalysisProcessor   ap;
Trigger             analysisTrigger = Trigger();
ProcessingPyConf    processingPyConf(&ap, &analysisTrigger);

static void callbackBefore(IRBuilder *irb, CONTEXT *ctx, BOOL hasEA, ADDRINT ea, THREADID threadId)
{
  /* Some configurations must be applied before processing */
  processingPyConf.applyConfBeforeProcessing(irb);

  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  if (hasEA)
    irb->setup(ea);

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Setup Information into Irb */
  irb->setThreadID(ap.getThreadID());

  /* Python callback before IR processing */
  processingPyConf.callbackBeforeIRProc(irb, &ap);

  Inst *inst = irb->process(ap);
  ap.addInstructionToTrace(inst);

  /* Export some information from Irb to Inst */
  inst->setOpcode(irb->getOpcode());
  inst->setOpcodeCategory(irb->getOpcodeCategory());
  inst->setOperands(irb->getOperands());

  /* Python callback before instruction processing */
  processingPyConf.callbackBefore(inst, &ap);
}

static void callbackAfter(CONTEXT *ctx, THREADID threadId)
{
  Inst *inst;

  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Get the last instruction */
  inst = ap.getLastInstruction();

  /* Update statistics */
  ap.incNumberOfBranchesTaken(inst->isBranch());

  /* Python callback after instruction processing */
  processingPyConf.callbackAfter(inst, &ap);
}

static void callbackSnapshot(UINT64 mem, UINT32 writeSize)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* If the snapshot is not enable we don't save the memory */
  if (ap.isSnapshotLocked())
    return;

  uint32_t i = 0;
  for (; i < writeSize ; i++)
    ap.addSnapshotModification(mem+i, *(reinterpret_cast<UINT8*>(mem+i)));
}

static void TRACE_Instrumentation(TRACE trace, VOID *programName)
{
  boost::filesystem::path pname(reinterpret_cast<char*>(programName));

  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)){
    for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {

      /* ---- Speed up process ---- */
      IMG currentImgName = IMG_FindByAddress(INS_Address(ins));
      if (!analysisTrigger.getState() && !IMG_Valid(currentImgName))
        break;
      boost::filesystem::path pcurrent(IMG_Name(currentImgName));
      if (!analysisTrigger.getState() && strcmp(pname.leaf().c_str(), pcurrent.leaf().c_str()))
        break;
      /* ---- End of speed up process ---- */

      IRBuilder *irb = createIRBuilder(ins);

      /* Callback before */
      if (INS_MemoryOperandCount(ins) > 0)
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) callbackBefore,
            IARG_PTR, irb,
            IARG_CONTEXT,
            IARG_BOOL, true,
            IARG_MEMORYOP_EA, 0,
            IARG_THREAD_ID,
            IARG_END);
      else
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) callbackBefore,
            IARG_PTR, irb,
            IARG_CONTEXT,
            IARG_BOOL, false,
            IARG_ADDRINT, 0,
            IARG_THREAD_ID,
            IARG_END);

      /* Callback after */
      /* Syscall after context must be catcher with IDREF.CALLBACK.SYSCALL_EXIT */
      if (INS_IsSyscall(ins) == false){
        IPOINT where = IPOINT_AFTER;
        if (INS_HasFallThrough(ins) == false)
          where = IPOINT_TAKEN_BRANCH;
        INS_InsertCall(ins, where, (AFUNPTR)callbackAfter, IARG_CONTEXT, IARG_THREAD_ID, IARG_END);
      }

      /* I/O memory monitoring for snapshot */
      if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0))
        INS_InsertCall(
          ins, IPOINT_BEFORE, (AFUNPTR)callbackSnapshot,
          IARG_MEMORYOP_EA, 0,
          IARG_UINT32, INS_MemoryWriteSize(ins),
          IARG_END);

    }
  }
}

static void toggleWrapper(bool flag)
{
  analysisTrigger.update(flag);
}

static void callbackRoutineEntry(THREADID threadId, PyObject *callback)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;
  processingPyConf.callbackRoutine(threadId, callback);
}

static void callbackRoutineExit(THREADID threadId, PyObject *callback)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;
  processingPyConf.callbackRoutine(threadId, callback);
}

static void IMG_Instrumentation(IMG img, VOID *)
{
  /* Lock / Unlock the Analysis */
  if (PyTritonOptions::startAnalysisFromSymbol != nullptr){

    RTN targetRTN = RTN_FindByName(img, PyTritonOptions::startAnalysisFromSymbol);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);

      RTN_InsertCall(targetRTN,
          IPOINT_BEFORE,
          (AFUNPTR) toggleWrapper,
          IARG_BOOL, true,
          IARG_END);

      RTN_InsertCall(targetRTN,
          IPOINT_AFTER,
          (AFUNPTR) toggleWrapper,
          IARG_BOOL, false,
          IARG_END);

      RTN_Close(targetRTN);
    }
  }

  /* Callback on routine entry */
  std::map<const char *, PyObject *>::iterator it;
  for (it = PyTritonOptions::callbackRoutineEntry.begin(); it != PyTritonOptions::callbackRoutineEntry.end(); it++){
    RTN targetRTN = RTN_FindByName(img, it->first);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);
      RTN_InsertCall(targetRTN, IPOINT_BEFORE, (AFUNPTR)callbackRoutineEntry, IARG_THREAD_ID, IARG_PTR, it->second, IARG_END);
      RTN_Close(targetRTN);
    }
  }

  /* Callback on routine exit */
  for (it = PyTritonOptions::callbackRoutineExit.begin(); it != PyTritonOptions::callbackRoutineExit.end(); it++){
    RTN targetRTN = RTN_FindByName(img, it->first);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);
      RTN_InsertCall(targetRTN, IPOINT_AFTER, (AFUNPTR)callbackRoutineExit, IARG_THREAD_ID, IARG_PTR, it->second, IARG_END);
      RTN_Close(targetRTN);
    }
  }
}

/* Callback at the end of the execution */
static void Fini(INT32, VOID *)
{
  /* Python callback at the end of execution */
  processingPyConf.callbackFini();

  /* End of Python */
  Py_Finalize();
}

/* Callback at the syscall entry */
static void callbackSyscallEntry(THREADID threadId, CONTEXT *ctx, SYSCALL_STANDARD std, VOID *v)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Python callback at the end of execution */
  processingPyConf.callbackSyscallEntry(threadId, std);
}

/* Callback at the syscall exit */
static void callbackSyscallExit(THREADID threadId, CONTEXT *ctx, SYSCALL_STANDARD std, VOID *v)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Python callback at the end of execution */
  processingPyConf.callbackSyscallExit(threadId, std);
}

/*
 * Usage function if Pin fail to start.
 * Display the help message.
 */
static int32_t Usage()
{
  std::cerr << KNOB_BASE::StringKnobSummary() << std::endl;
  return -1;
}

/* Get the name of the target binary */
static char *getProgramName(char *argv[])
{
  uint64_t offset;
  for (offset = 0; argv[offset]; offset++){
    if (!strcmp(argv[offset], "--") && argv[offset+1])
      return argv[offset+1];
  }
  return nullptr;
}

int main(int argc, char *argv[])
{
  PIN_InitSymbols();
  PIN_SetSyntaxIntel();
  if(PIN_Init(argc, argv))
      return Usage();

  /* Init Python Bindings */
  initBindings();

  /* Image callback */
  IMG_AddInstrumentFunction(IMG_Instrumentation, nullptr);

  /* Instruction callback */
  TRACE_AddInstrumentFunction(TRACE_Instrumentation, getProgramName(argv));

  /* End instrumentation callback */
  PIN_AddFiniFunction(Fini, nullptr);

  /* Syscall entry callback */
  PIN_AddSyscallEntryFunction(callbackSyscallEntry, 0);

  /* Syscall exit callback */
  PIN_AddSyscallExitFunction(callbackSyscallExit, 0);

  /* Exec the python bindings file */
  if (!execBindings(KnobPythonModule.Value().c_str())) {
    std::cerr << "Error: Script file can't be found!" << std::endl;
    exit(1);
  }

  return 0;
}

<commit_msg>Fix bug speed up process<commit_after>#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <vector>

#include "pin.H"

#include "AnalysisProcessor.h"
#include "IRBuilder.h"
#include "IRBuilderFactory.h"
#include "Inst.h"
#include "PINContextHandler.h"
#include "ProcessingPyConf.h"
#include "Trigger.h"
#include <boost/filesystem.hpp>

using boost::filesystem::absolute;
using boost::filesystem::path;

/* Pin options: -script */
KNOB<std::string>   KnobPythonModule(KNOB_MODE_WRITEONCE, "pintool", "script", "", "Python script");

AnalysisProcessor   ap;
Trigger             analysisTrigger = Trigger();
ProcessingPyConf    processingPyConf(&ap, &analysisTrigger);

static void callbackBefore(IRBuilder *irb, CONTEXT *ctx, BOOL hasEA, ADDRINT ea, THREADID threadId)
{
  /* Some configurations must be applied before processing */
  processingPyConf.applyConfBeforeProcessing(irb);

  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  if (hasEA)
    irb->setup(ea);

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Setup Information into Irb */
  irb->setThreadID(ap.getThreadID());

  /* Python callback before IR processing */
  processingPyConf.callbackBeforeIRProc(irb, &ap);

  Inst *inst = irb->process(ap);
  ap.addInstructionToTrace(inst);

  /* Export some information from Irb to Inst */
  inst->setOpcode(irb->getOpcode());
  inst->setOpcodeCategory(irb->getOpcodeCategory());
  inst->setOperands(irb->getOperands());

  /* Python callback before instruction processing */
  processingPyConf.callbackBefore(inst, &ap);
}

static void callbackAfter(CONTEXT *ctx, THREADID threadId)
{
  Inst *inst;

  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Get the last instruction */
  inst = ap.getLastInstruction();

  /* Update statistics */
  ap.incNumberOfBranchesTaken(inst->isBranch());

  /* Python callback after instruction processing */
  processingPyConf.callbackAfter(inst, &ap);
}

static void callbackSnapshot(UINT64 mem, UINT32 writeSize)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* If the snapshot is not enable we don't save the memory */
  if (ap.isSnapshotLocked())
    return;

  uint32_t i = 0;
  for (; i < writeSize ; i++)
    ap.addSnapshotModification(mem+i, *(reinterpret_cast<UINT8*>(mem+i)));
}

static void TRACE_Instrumentation(TRACE trace, VOID *programName)
{
  boost::filesystem::path pname(reinterpret_cast<char*>(programName));

  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)){
    for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {

      /* ---- Speed up process ---- */
      IMG currentImgName = IMG_FindByAddress(INS_Address(ins));
      if (!analysisTrigger.getState() || !IMG_Valid(currentImgName))
        break;
      boost::filesystem::path pcurrent(IMG_Name(currentImgName));
      if (!analysisTrigger.getState() || strcmp(pname.leaf().c_str(), pcurrent.leaf().c_str()))
        break;
      /* ---- End of speed up process ---- */

      IRBuilder *irb = createIRBuilder(ins);

      /* Callback before */
      if (INS_MemoryOperandCount(ins) > 0)
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) callbackBefore,
            IARG_PTR, irb,
            IARG_CONTEXT,
            IARG_BOOL, true,
            IARG_MEMORYOP_EA, 0,
            IARG_THREAD_ID,
            IARG_END);
      else
        INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) callbackBefore,
            IARG_PTR, irb,
            IARG_CONTEXT,
            IARG_BOOL, false,
            IARG_ADDRINT, 0,
            IARG_THREAD_ID,
            IARG_END);

      /* Callback after */
      /* Syscall after context must be catcher with IDREF.CALLBACK.SYSCALL_EXIT */
      if (INS_IsSyscall(ins) == false){
        IPOINT where = IPOINT_AFTER;
        if (INS_HasFallThrough(ins) == false)
          where = IPOINT_TAKEN_BRANCH;
        INS_InsertCall(ins, where, (AFUNPTR)callbackAfter, IARG_CONTEXT, IARG_THREAD_ID, IARG_END);
      }

      /* I/O memory monitoring for snapshot */
      if (INS_OperandCount(ins) > 1 && INS_MemoryOperandIsWritten(ins, 0))
        INS_InsertCall(
          ins, IPOINT_BEFORE, (AFUNPTR)callbackSnapshot,
          IARG_MEMORYOP_EA, 0,
          IARG_UINT32, INS_MemoryWriteSize(ins),
          IARG_END);

    }
  }
}

static void toggleWrapper(bool flag)
{
  analysisTrigger.update(flag);
}

static void callbackRoutineEntry(THREADID threadId, PyObject *callback)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;
  processingPyConf.callbackRoutine(threadId, callback);
}

static void callbackRoutineExit(THREADID threadId, PyObject *callback)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;
  processingPyConf.callbackRoutine(threadId, callback);
}

static void IMG_Instrumentation(IMG img, VOID *)
{
  /* Lock / Unlock the Analysis */
  if (PyTritonOptions::startAnalysisFromSymbol != nullptr){

    RTN targetRTN = RTN_FindByName(img, PyTritonOptions::startAnalysisFromSymbol);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);

      RTN_InsertCall(targetRTN,
          IPOINT_BEFORE,
          (AFUNPTR) toggleWrapper,
          IARG_BOOL, true,
          IARG_END);

      RTN_InsertCall(targetRTN,
          IPOINT_AFTER,
          (AFUNPTR) toggleWrapper,
          IARG_BOOL, false,
          IARG_END);

      RTN_Close(targetRTN);
    }
  }

  /* Callback on routine entry */
  std::map<const char *, PyObject *>::iterator it;
  for (it = PyTritonOptions::callbackRoutineEntry.begin(); it != PyTritonOptions::callbackRoutineEntry.end(); it++){
    RTN targetRTN = RTN_FindByName(img, it->first);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);
      RTN_InsertCall(targetRTN, IPOINT_BEFORE, (AFUNPTR)callbackRoutineEntry, IARG_THREAD_ID, IARG_PTR, it->second, IARG_END);
      RTN_Close(targetRTN);
    }
  }

  /* Callback on routine exit */
  for (it = PyTritonOptions::callbackRoutineExit.begin(); it != PyTritonOptions::callbackRoutineExit.end(); it++){
    RTN targetRTN = RTN_FindByName(img, it->first);
    if (RTN_Valid(targetRTN)){
      RTN_Open(targetRTN);
      RTN_InsertCall(targetRTN, IPOINT_AFTER, (AFUNPTR)callbackRoutineExit, IARG_THREAD_ID, IARG_PTR, it->second, IARG_END);
      RTN_Close(targetRTN);
    }
  }
}

/* Callback at the end of the execution */
static void Fini(INT32, VOID *)
{
  /* Python callback at the end of execution */
  processingPyConf.callbackFini();

  /* End of Python */
  Py_Finalize();
}

/* Callback at the syscall entry */
static void callbackSyscallEntry(THREADID threadId, CONTEXT *ctx, SYSCALL_STANDARD std, VOID *v)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Python callback at the end of execution */
  processingPyConf.callbackSyscallEntry(threadId, std);
}

/* Callback at the syscall exit */
static void callbackSyscallExit(THREADID threadId, CONTEXT *ctx, SYSCALL_STANDARD std, VOID *v)
{
  if (!analysisTrigger.getState())
  /* Analysis locked */
    return;

  /* Update the current context handler */
  ap.updateCurrentCtxH(new PINContextHandler(ctx, threadId));

  /* Python callback at the end of execution */
  processingPyConf.callbackSyscallExit(threadId, std);
}

/*
 * Usage function if Pin fail to start.
 * Display the help message.
 */
static int32_t Usage()
{
  std::cerr << KNOB_BASE::StringKnobSummary() << std::endl;
  return -1;
}

/* Get the name of the target binary */
static char *getProgramName(char *argv[])
{
  uint64_t offset;
  for (offset = 0; argv[offset]; offset++){
    if (!strcmp(argv[offset], "--") && argv[offset+1])
      return argv[offset+1];
  }
  return nullptr;
}

int main(int argc, char *argv[])
{
  PIN_InitSymbols();
  PIN_SetSyntaxIntel();
  if(PIN_Init(argc, argv))
      return Usage();

  /* Init Python Bindings */
  initBindings();

  /* Image callback */
  IMG_AddInstrumentFunction(IMG_Instrumentation, nullptr);

  /* Instruction callback */
  TRACE_AddInstrumentFunction(TRACE_Instrumentation, getProgramName(argv));

  /* End instrumentation callback */
  PIN_AddFiniFunction(Fini, nullptr);

  /* Syscall entry callback */
  PIN_AddSyscallEntryFunction(callbackSyscallEntry, 0);

  /* Syscall exit callback */
  PIN_AddSyscallExitFunction(callbackSyscallExit, 0);

  /* Exec the python bindings file */
  if (!execBindings(KnobPythonModule.Value().c_str())) {
    std::cerr << "Error: Script file can't be found!" << std::endl;
    exit(1);
  }

  return 0;
}

<|endoftext|>


<commit_before>/*
 * util.hpp
 *
 *  Created on: Feb 28, 2015
 *      Author: hugo
 */

#ifndef MFLASH_CPP_CORE_UTIL_HPP_
#define MFLASH_CPP_CORE_UTIL_HPP_

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>

#include "../core/type.hpp"

using namespace std;

namespace mflash {

const int MFLASH_MATRIX_THREADS = 1;
const int MFLASH_VECTOR_THREADS = 1;
const double MAPPING_PERCENTAGE = 0.1;

const string FILE_SEPARATOR = "/";
const string DIRECTORY = ".G-FLASH";
const string GRAPH = "graph";
const string STREAM_FILE = "edge_stream";

const int64 DEFAULT_BYTES_BLOCK = sizeof(int64) * 5; // 40 BYTES

int64 MEMORY_SIZE_BYTES = 1 * 1073741824L; //2GB

int64 get_mapping_limit(int64 block_size_bytes) {
	return 1048576; //MAPPING_PERCENTAGE * block_size_bytes;
}

string get_parent_directory(string graph) {
	int64 pos = graph.find_last_of(FILE_SEPARATOR);

	return graph.substr(0, pos) + FILE_SEPARATOR;
}

string get_mflash_directory(string graph) {
	string path = get_parent_directory(graph) + DIRECTORY;

	/*	boost::filesystem::path dir(path);

	 if( !boost::filesystem::exists(path) ){
	 boost::filesystem::create_directories(path);
	 }*/
	return path;
}

string get_stream_file(string graph) {
	return get_parent_directory(graph) + DIRECTORY + FILE_SEPARATOR
			+ STREAM_FILE;
}

string get_block_file(string graph, int64 i, int64 j) {
	std::stringstream file;
	file << get_mflash_directory(graph) << FILE_SEPARATOR << i << "_" << j
			<< ".block";
	return file.str();
}

string get_partition_file(string graph, int64 partition_id) {
	std::stringstream file;
	file << get_mflash_directory(graph) << FILE_SEPARATOR << partition_id << ".partition";
	return file.str();
}

bool exist_file(string file) {
	ifstream f(file.c_str());
	if (f.good()) {
		f.close();
		return true;
	} else {
		f.close();
		return false;
	}
}

int64 file_size(string file) {
	if (exist_file(file)) {
		ifstream in(file, std::ifstream::ate | std::ifstream::binary);
		int64 size = in.tellg();
		in.close();
		return size;
	}
	return 0;
}

ios::openmode get_file_properties(string file, bool write) {

	if (!write) {
		return ios::in | ios::binary | ios::ate;
	}

	ios::openmode properties = ios::out | ios::binary | ios::ate;
	if (exist_file(file)) {
		properties |= ios::in;
	}

	return properties;
}
/*string get_mflash_directory(string graph) {
 string path = get_parent_directory(graph);

 boost::filesystem::path dir(path);

 if( !boost::filesystem::exists(path) ){
 boost::filesystem::create_directories(path);
 }
 return path;
 }

 string get_block_file(string graph, int64 i, int64 j){
 std::stringstream file;
 file << get_mflash_directory(graph) << FILE_SEPARATOR << i << "_" << j << ".block";
 return file.str();
 }

 bool exist_file(string file){
 return boost::filesystem::exists(boost::filesystem::path(file));
 }

 int64 file_size(string file){
 return boost::filesystem::file_size(boost::filesystem::path(file));
 }*/

void quicksort(double values[], int64 indexes[], int64 left, int64 right,
		bool asc) {
	double pivot = values[left + (right - left) / 2];
	int i = left;
	int j = right;

	int operator_ = asc ? 1 : -1;

	while (i <= j) {
		while (operator_ * values[i] < operator_ * pivot) {
			i++;
		}
		while (operator_ * values[j] > operator_ * pivot) {
			j--;
		}
		if (i <= j) {

			int64 idxTmp = indexes[i];
			double valueTmp = values[i];

			values[i] = values[j];
			values[j] = valueTmp;

			indexes[i] = indexes[j];
			indexes[j] = idxTmp;

			i++;
			j--;
		}
	}

	if (left < j)
		quicksort(values, indexes, left, j, asc);
	if (i < right)
		quicksort(values, indexes, i, right, asc);

}

int64* sort_and_get_indexes(int64 n, double values[], bool asc) {
	int64 *indexes = new int64[n];

	for (int64 i = 0; i < n; i++) {
		indexes[i] = i;
	}

	quicksort(values, indexes, 0, n - 1, asc);

	return indexes;
}

/*
int stick_this_thread_to_core(int core_id) {
	int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
	if (core_id < 0 || core_id >= num_cores)
		return EINVAL;

	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	CPU_SET(core_id, &cpuset);

	pthread_t current_thread = pthread_self();
	return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
*/
}

#endif /* MFLASH_CPP_CORE_UTIL_HPP_ */
<commit_msg>It was enabled the directory creation. \n Methods to get edge size was added<commit_after>/*
 * util.hpp
 *
 *  Created on: Feb 28, 2015
 *      Author: hugo
 */

#ifndef MFLASH_CPP_CORE_UTIL_HPP_
#define MFLASH_CPP_CORE_UTIL_HPP_

#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
#include <assert.h>
#include <boost/filesystem.hpp>

#include "../core/type.hpp"
#include "../../log/easylogging++.h"

using namespace std;

namespace mflash {

const int MFLASH_MATRIX_THREADS = 1;
const int MFLASH_VECTOR_THREADS = 1;
const double MAPPING_PERCENTAGE = 0.1;

const string FILE_SEPARATOR = "/";
const string DIRECTORY = ".M-FLASH";
const string GRAPH = "graph";
const string STREAM_FILE = "edge_stream";

const int64 DEFAULT_BYTES_BLOCK = sizeof(int64) * 5; // 40 BYTES

int64 MEMORY_SIZE_BYTES = 1 * 1073741824L; //2GB

int64 get_mapping_limit(int64 block_size_bytes) {
	return 1048576; //MAPPING_PERCENTAGE * block_size_bytes;
}

string get_parent_directory(string graph) {
	int64 pos = graph.find_last_of(FILE_SEPARATOR);

	return graph.substr(0, pos) + FILE_SEPARATOR;
}

string get_mflash_directory(string graph) {
	string path = get_parent_directory(graph) + DIRECTORY;

		boost::filesystem::path dir(path);

	 if( !boost::filesystem::exists(path) ){
	 boost::filesystem::create_directories(path);
	 }
	return path;
}

string get_stream_file(string graph) {
	return get_parent_directory(graph) + DIRECTORY + FILE_SEPARATOR
			+ STREAM_FILE;
}

string get_block_file(string graph, int64 i, int64 j) {
	std::stringstream file;
	file << get_mflash_directory(graph) << FILE_SEPARATOR << i << "_" << j
			<< ".block";
	return file.str();
}

string get_partition_file(string graph, int64 partition_id) {
	std::stringstream file;
	file << get_mflash_directory(graph) << FILE_SEPARATOR << partition_id << ".partition";
	return file.str();
}

bool exist_file(string file) {
	ifstream f(file.c_str());
	if (f.good()) {
		f.close();
		return true;
	} else {
		f.close();
		return false;
	}
}

int64 file_size(string file) {
	if (exist_file(file)) {
		ifstream in(file, std::ifstream::ate | std::ifstream::binary);
		int64 size = in.tellg();
		in.close();
		return size;
	}
	return 0;
}

ios::openmode get_file_properties(string file, bool write) {

	if (!write) {
		return ios::in | ios::binary | ios::ate;
	}

	ios::openmode properties = ios::out | ios::binary | ios::ate;
	if (exist_file(file)) {
		properties |= ios::in;
	}

	return properties;
}

template <class ID_TYPE, class EdgeType>
int64 getEdgeSize(){
	int64 size = 0;
	#if Edgetype != EmptyField
		size += sizeof(EdgeType)
	#endif
	return size +  (sizeof(ID_TYPE)<<2);

}

template <class EdgeType>
int64 getEdgeDataSize(){
	int64 size = 0;
	#if Edgetype != EmptyField
		size += sizeof(EdgeType)
	#endif
	return size;

}
/*string get_mflash_directory(string graph) {
 string path = get_parent_directory(graph);

 boost::filesystem::path dir(path);

 if( !boost::filesystem::exists(path) ){
 boost::filesystem::create_directories(path);
 }
 return path;
 }

 string get_block_file(string graph, int64 i, int64 j){
 std::stringstream file;
 file << get_mflash_directory(graph) << FILE_SEPARATOR << i << "_" << j << ".block";
 return file.str();
 }

 bool exist_file(string file){
 return boost::filesystem::exists(boost::filesystem::path(file));
 }

 int64 file_size(string file){
 return boost::filesystem::file_size(boost::filesystem::path(file));
 }*/

void quicksort(double values[], int64 indexes[], int64 left, int64 right,
		bool asc) {
	double pivot = values[left + (right - left) / 2];
	int i = left;
	int j = right;

	int operator_ = asc ? 1 : -1;

	while (i <= j) {
		while (operator_ * values[i] < operator_ * pivot) {
			i++;
		}
		while (operator_ * values[j] > operator_ * pivot) {
			j--;
		}
		if (i <= j) {

			int64 idxTmp = indexes[i];
			double valueTmp = values[i];

			values[i] = values[j];
			values[j] = valueTmp;

			indexes[i] = indexes[j];
			indexes[j] = idxTmp;

			i++;
			j--;
		}
	}

	if (left < j)
		quicksort(values, indexes, left, j, asc);
	if (i < right)
		quicksort(values, indexes, i, right, asc);

}

int64* sort_and_get_indexes(int64 n, double values[], bool asc) {
	int64 *indexes = new int64[n];

	for (int64 i = 0; i < n; i++) {
		indexes[i] = i;
	}

	quicksort(values, indexes, 0, n - 1, asc);

	return indexes;
}

/*
int stick_this_thread_to_core(int core_id) {
	int num_cores = sysconf(_SC_NPROCESSORS_ONLN);
	if (core_id < 0 || core_id >= num_cores)
		return EINVAL;

	cpu_set_t cpuset;
	CPU_ZERO(&cpuset);
	CPU_SET(core_id, &cpuset);

	pthread_t current_thread = pthread_self();
	return pthread_setaffinity_np(current_thread, sizeof(cpu_set_t), &cpuset);
}
*/
}

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


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

#include "csvhandle.h"

#include <QTextStream>
#include <QtCore/QtMath>
#include <QTextCodec>

CSVHandle::CSVHandle(QObject *parent) : QObject(parent)
{
}

QStringList CSVHandle::loadCSV(QString path, CSVHandle::seperator sep, bool has_header, int column_word, int column_translation, int column_priority, bool import_priority)
{
    QStringList errors;

    if(column_priority < 0 || column_translation < 0 || column_word < 0)
    {
        errors << tr("All column indices must be positive or zero");
        return errors;
    }

    QFile file(path);

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QString error = QString(tr("Can not open file \"%1\": %2")).arg(path).arg(file.errorString());
        WARNING(error);
        errors << error;
        return errors;
    }

    QTextStream stream(&file);
    stream.setCodec(QTextCodec::codecForName("UTF-8"));

    database.transaction();
    QSqlQuery q(database);
    QString s = "INSERT OR ABORT INTO vocabulary VALUES (?,?,100)";

    int need_num_columns = qMax(column_word, column_translation);
    QChar sep_char = getSeperator(sep);

    if(import_priority)
    {
        need_num_columns = qMax(need_num_columns, column_priority);
        s = "INSERT OR ABORT INTO vocabulary VALUES (?,?,?)";
    }

    if(has_header)
    {
        // Ignore header
        stream.readLine();
    }

    while(!stream.atEnd())
    {
        QString line = stream.readLine();
        QStringList columns = line.split(sep_char, QString::KeepEmptyParts);
        if(columns.size() < need_num_columns+1)
        {
            QString error = QString(tr("Error at \"%1\": Column to small")).arg(line);
            WARNING(error);
            errors << error;
            continue;
        }
        q.prepare(s);
        q.addBindValue(columns[column_word]);
        q.addBindValue(columns[column_translation]);
        if(import_priority)
        {
            bool ok = true;
            int priority = qBound(1, columns[column_priority].toInt(&ok), 100);
            if(!ok)
            {
                priority = 100;
                QString error = QString(tr("Can not convert \"%1\" to priority")).arg(columns[column_priority]);
                WARNING(error);
                errors << error;
            }
            q.addBindValue(priority);
        }

        if(!q.exec())
        {
            QString error = s.append(": ").append(q.lastError().text());
            WARNING(error);
            errors << error;
        }
    }

    if(!database.commit())
    {
        errors << database.lastError().text();
    }
    return errors;
}

QStringList CSVHandle::saveCSV(QString path, CSVHandle::seperator sep, bool write_header)
{
    QStringList errors;

    QFile file(path);

    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QString error = QString(tr("Can not open file \"%1\": %2")).arg(path).arg(file.errorString());
        WARNING(error);
        errors << error;
        return errors;
    }

    QTextStream stream(&file);
    stream.setCodec(QTextCodec::codecForName("UTF-8"));

    QSqlQuery q(database);
    QString s = "SELECT word,translation,priority FROM vocabulary";

    if(!q.exec(s))
    {
        QString error = s.append(": ").append(q.lastError().text());
        WARNING(error);
        errors << error;
        file.close();
        return errors;
    }
    if(!q.isSelect())
    {
        QString error = s.append(": No select");
        WARNING(error);
        errors << error;
        file.close();
        return errors;
    }

    QChar sep_char = getSeperator(sep);

    if(write_header)
    {
        stream << QString(tr("word%1translation%1priority\n")).arg(sep_char);
    }

    while(q.next())
    {
        QString line;
        line.append(q.value(0).toString());
        line.append(sep_char);
        line.append(q.value(1).toString());
        line.append(sep_char);
        line.append(q.value(2).toString());
        line.append('\n');
        stream << line;
    }

    file.close();
    return errors;
}

QChar CSVHandle::getSeperator(CSVHandle::seperator sep)
{
    switch(sep)
    {
    case TAB:
        return QChar('\t');
        break;
    case SPACE:
        return QChar(' ');
        break;
    case COMMA:
        return QChar(',');
        break;
    case SEMICOLON:
        return QChar(';');
        break;
    }
    Q_UNREACHABLE();
}

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

#include "csvhandle.h"

#include <QTextStream>
#include <QtCore/QtMath>
#include <QTextCodec>

CSVHandle::CSVHandle(QObject *parent) : QObject(parent)
{
}

QStringList CSVHandle::loadCSV(QString path, CSVHandle::seperator sep, bool has_header, int column_word, int column_translation, int column_priority, bool import_priority)
{
    QStringList errors;

    if(column_priority < 0 || column_translation < 0 || column_word < 0)
    {
        errors << tr("All column indices must be positive or zero");
        return errors;
    }

    QFile file(path);

    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QString error = QString(tr("Can not open file \"%1\": %2")).arg(path).arg(file.errorString());
        WARNING(error);
        errors << error;
        return errors;
    }

    QTextStream stream(&file);
    stream.setCodec(QTextCodec::codecForName("UTF-8"));

    database.transaction();
    QSqlQuery q(database);
    QString s = "INSERT OR ABORT INTO vocabulary VALUES (?,?,100)";

    int need_num_columns = qMax(column_word, column_translation);
    QChar sep_char = getSeperator(sep);

    if(import_priority)
    {
        need_num_columns = qMax(need_num_columns, column_priority);
        s = "INSERT OR ABORT INTO vocabulary VALUES (?,?,?)";
    }

    if(has_header)
    {
        // Ignore header
        stream.readLine();
    }

    while(!stream.atEnd())
    {
        QString line = stream.readLine();
        if(line.isEmpty())
        {
            continue;
        }
        QStringList columns = line.split(sep_char, QString::KeepEmptyParts);
        if(columns.size() < need_num_columns+1)
        {
            QString error = QString(tr("Error at \"%1\": Column to small")).arg(line);
            WARNING(error);
            errors << error;
            continue;
        }
        q.prepare(s);
        q.addBindValue(columns[column_word]);
        q.addBindValue(columns[column_translation]);
        if(import_priority)
        {
            bool ok = true;
            int priority = qBound(1, columns[column_priority].toInt(&ok), 100);
            if(!ok)
            {
                priority = 100;
                QString error = QString(tr("Can not convert \"%1\" to priority")).arg(columns[column_priority]);
                WARNING(error);
                errors << error;
            }
            q.addBindValue(priority);
        }

        if(!q.exec())
        {
            QString error = s.append(": ").append(q.lastError().text());
            WARNING(error);
            errors << error;
        }
    }

    if(!database.commit())
    {
        errors << database.lastError().text();
    }
    return errors;
}

QStringList CSVHandle::saveCSV(QString path, CSVHandle::seperator sep, bool write_header)
{
    QStringList errors;

    QFile file(path);

    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QString error = QString(tr("Can not open file \"%1\": %2")).arg(path).arg(file.errorString());
        WARNING(error);
        errors << error;
        return errors;
    }

    QTextStream stream(&file);
    stream.setCodec(QTextCodec::codecForName("UTF-8"));

    QSqlQuery q(database);
    QString s = "SELECT word,translation,priority FROM vocabulary";

    if(!q.exec(s))
    {
        QString error = s.append(": ").append(q.lastError().text());
        WARNING(error);
        errors << error;
        file.close();
        return errors;
    }
    if(!q.isSelect())
    {
        QString error = s.append(": No select");
        WARNING(error);
        errors << error;
        file.close();
        return errors;
    }

    QChar sep_char = getSeperator(sep);

    if(write_header)
    {
        stream << QString(tr("word%1translation%1priority\n")).arg(sep_char);
    }

    while(q.next())
    {
        QString line;
        line.append(q.value(0).toString());
        line.append(sep_char);
        line.append(q.value(1).toString());
        line.append(sep_char);
        line.append(q.value(2).toString());
        line.append('\n');
        stream << line;
    }

    file.close();
    return errors;
}

QChar CSVHandle::getSeperator(CSVHandle::seperator sep)
{
    switch(sep)
    {
    case TAB:
        return QChar('\t');
        break;
    case SPACE:
        return QChar(' ');
        break;
    case COMMA:
        return QChar(',');
        break;
    case SEMICOLON:
        return QChar(';');
        break;
    }
    Q_UNREACHABLE();
}

<|endoftext|>


<commit_before>/*
 * Unit tests for the Raft library.
 *
 * Copyright (C) 2017 Nextworks
 * Author: Vincenzo Maffione <v.maffione@gmail.com>
 *
 * This file is part of rlite.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <iostream>
#include <list>
#include <string>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <functional>
#include <queue>
#include <random>
#include <ctime>
#include <memory>

#include "rlite/cpputils.hpp"
#include "rlite/raft.hpp"

using namespace std;

static string
logfile(const string &replica)
{
    return string("/tmp/raft_test_") + replica + "_log";
}

class TestReplica : public RaftSM {
    uint32_t output_counter = 18;

public:
    TestReplica() = default;
    RL_NONCOPIABLE(TestReplica);
    TestReplica(const std::string &smname, const ReplicaId &myname,
                std::string logname)
        : RaftSM(smname, myname, logname,
                 /*cmd_size=*/sizeof(uint32_t), std::cerr, std::cout)
    {
    }
    ~TestReplica() { shutdown(); }
    virtual int apply(const char *const serbuf) override
    {
        uint32_t cmd = *(reinterpret_cast<const uint32_t *>(serbuf));
        if (++output_counter != cmd) {
            cout << "Mismatch: expected " << output_counter << ", got " << cmd
                 << endl;
            return -1;
        }
        return 0;
    }
};

struct TestEvent {
    unsigned int abstime = 0;
    RaftSM *sm           = nullptr;
    RaftTimerType ttype  = RaftTimerType::Invalid;
    bool client          = false;

    /* A Raft timer event. */
    TestEvent(unsigned int t, RaftSM *_sm, RaftTimerType ty)
        : abstime(t), sm(_sm), ttype(ty)
    {
    }

    /* A client submission event. */
    TestEvent(unsigned int t) : abstime(t), client(true) {}

    bool operator<(const TestEvent &o) const { return abstime < o.abstime; }
    bool operator>=(const TestEvent &o) const { return !(*this < o); }

    static uint32_t get_next_command() { return ++input_counter; }

private:
    static uint32_t input_counter;
};

uint32_t TestEvent::input_counter = 18;

int
main()
{
    list<string> names = {"r1", "r2", "r3", "r4", "r5"};
    map<string, std::unique_ptr<RaftSM>> replicas;
    list<TestEvent> events;
    unsigned int t = 0; /* time */
    RaftSMOutput output;

    srand(time(0));

    /* Clean up leftover logfiles, if any. */
    for (const auto &local : names) {
        remove(logfile(local).c_str());
    }

    /* Push some client submission. */
    events.push_back(TestEvent(350));
    events.push_back(TestEvent(360));
    events.push_back(TestEvent(370));
    events.sort();

    for (const auto &local : names) {
        string logfilename = logfile(local);
        list<string> peers;
        std::unique_ptr<RaftSM> sm;

        for (const auto &peer : names) {
            if (peer != local) {
                peers.push_back(peer);
            }
        }

        sm = make_unique<TestReplica>(
            /*smname=*/local + "-sm", /*myname=*/local, logfilename);
        if (sm->init(peers, &output)) {
            return -1;
        }
        replicas[local] = std::move(sm);
    }

    for (;;) {
        unsigned int t_next = t + 1;
        RaftSMOutput output_next;

        cout << "| t = " << t << " |" << endl;

        /* Process current output messages. */
        for (const auto &p : output.output_messages) {
            auto *rv  = dynamic_cast<RaftRequestVote *>(p.second.get());
            auto *rvr = dynamic_cast<RaftRequestVoteResp *>(p.second.get());
            auto *ae  = dynamic_cast<RaftAppendEntries *>(p.second.get());
            auto *aer = dynamic_cast<RaftAppendEntriesResp *>(p.second.get());
            int r     = 0;

            assert(replicas.count(p.first));
            if (rv) {
                r = replicas[p.first]->request_vote_input(*rv, &output_next);
            } else if (rvr) {
                r = replicas[p.first]->request_vote_resp_input(*rvr,
                                                               &output_next);
            } else if (ae) {
                r = replicas[p.first]->append_entries_input(*ae, &output_next);
            } else if (aer) {
                r = replicas[p.first]->append_entries_resp_input(*aer,
                                                                 &output_next);
            } else {
                assert(false);
            }

            if (r) {
                return r;
            }
        }

        /* Process current timer commands. */
        for (const RaftTimerCmd &cmd : output.timer_commands) {
            for (auto it = events.begin(); it != events.end(); it++) {
                if (it->sm == cmd.sm && it->ttype == cmd.type) {
                    events.erase(it);
                    break;
                }
            }
            if (cmd.action == RaftTimerAction::Restart) {
                events.push_back(
                    TestEvent(t + cmd.milliseconds, cmd.sm, cmd.type));
                events.sort();
            } else {
                assert(cmd.action == RaftTimerAction::Stop);
            }
        }

        /* Process all the timers expired so far, updating the associated
         * Raft state machine. */
        while (!events.empty()) {
            const TestEvent &next = events.front();
            if (t < next.abstime) {
                if (output_next.output_messages.empty() &&
                    output_next.timer_commands.empty()) {
                    /* No need to go step by step, we can jump to the next
                     * event. */
                    t_next = next.abstime;
                }
                break;
            }
            if (next.client) {
                /* This event is a client submission. */
                bool submitted = false;
                for (const auto &kv : replicas) {
                    if (kv.second->leader()) {
                        LogIndex request_id;
                        uint32_t cmd = TestEvent::get_next_command();

                        if (kv.second->submit(reinterpret_cast<char *>(&cmd),
                                              &request_id, &output_next)) {
                            return -1;
                        }
                        submitted = true;
                        cout << "Command " << cmd << " submitted" << endl;
                    }
                }
                if (!submitted) {
                    cout << "Dropped client request (no leader)" << endl;
                }
            } else {
                /* This event is a timer firing. */
                if (next.sm->timer_expired(next.ttype, &output_next)) {
                    return -1;
                }
            }
            events.pop_front();
        }
        t      = t_next;
        output = std::move(output_next);

        {
            string input;
            cin >> input;
        }
    }

    return 0;
}
<commit_msg>lib: raft: test: refactor to use more event types<commit_after>/*
 * Unit tests for the Raft library.
 *
 * Copyright (C) 2017 Nextworks
 * Author: Vincenzo Maffione <v.maffione@gmail.com>
 *
 * This file is part of rlite.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <iostream>
#include <list>
#include <string>
#include <cstdint>
#include <cassert>
#include <cstring>
#include <functional>
#include <queue>
#include <random>
#include <ctime>
#include <memory>

#include "rlite/cpputils.hpp"
#include "rlite/raft.hpp"

using namespace std;

static string
logfile(const string &replica)
{
    return string("/tmp/raft_test_") + replica + "_log";
}

class TestReplica : public RaftSM {
    uint32_t output_counter = 18;

public:
    TestReplica() = default;
    RL_NONCOPIABLE(TestReplica);
    TestReplica(const std::string &smname, const ReplicaId &myname,
                std::string logname)
        : RaftSM(smname, myname, logname,
                 /*cmd_size=*/sizeof(uint32_t), std::cerr, std::cout)
    {
    }
    ~TestReplica() { shutdown(); }
    virtual int apply(const char *const serbuf) override
    {
        uint32_t cmd = *(reinterpret_cast<const uint32_t *>(serbuf));
        if (++output_counter != cmd) {
            cout << "Mismatch: expected " << output_counter << ", got " << cmd
                 << endl;
            return -1;
        }
        return 0;
    }
};

enum class TestEventType {
    RaftTimer = 0,
    ClientRequest,
    SMFailure,
    SMRespawn,
};

struct TestEvent {
    TestEventType event_type;
    unsigned int abstime = 0;
    RaftSM *sm           = nullptr;
    RaftTimerType ttype  = RaftTimerType::Invalid;

    bool operator<(const TestEvent &o) const { return abstime < o.abstime; }
    bool operator>=(const TestEvent &o) const { return !(*this < o); }

    static uint32_t get_next_command() { return ++input_counter; }

    static TestEvent CreateTimerEvent(unsigned int t, RaftSM *_sm,
                                      RaftTimerType ty)
    {
        TestEvent e;
        e.event_type = TestEventType::RaftTimer;
        e.abstime    = t;
        e.sm         = _sm;
        e.ttype      = ty;
        return e;
    }

    static TestEvent CreateRequestEvent(unsigned int t)
    {
        TestEvent e;
        e.event_type = TestEventType::ClientRequest;
        e.abstime    = t;
        return e;
    }

    static TestEvent CreateFailureEvent(unsigned int t, RaftSM *_sm)
    {
        TestEvent e;
        e.event_type = TestEventType::SMFailure;
        e.abstime    = t;
        e.sm         = _sm;
        return e;
    }

    static TestEvent CreateRespawnEvent(unsigned int t, RaftSM *_sm)
    {
        TestEvent e;
        e.event_type = TestEventType::SMRespawn;
        e.abstime    = t;
        e.sm         = _sm;
        return e;
    }

private:
    static uint32_t input_counter;
};

uint32_t TestEvent::input_counter = 18;

int
main()
{
    list<string> names = {"r1", "r2", "r3", "r4", "r5"};
    map<string, std::unique_ptr<RaftSM>> replicas;
    list<TestEvent> events;
    unsigned int t           = 0; /* time */
    const unsigned int t_max = 500;
    RaftSMOutput output;

    srand(time(0));

    /* Clean up leftover logfiles, if any. */
    for (const auto &local : names) {
        remove(logfile(local).c_str());
    }

    /* Push some client submission. */
    events.push_back(TestEvent::CreateRequestEvent(350));
    events.push_back(TestEvent::CreateRequestEvent(360));
    events.push_back(TestEvent::CreateRequestEvent(370));
    events.sort();

    for (const auto &local : names) {
        string logfilename = logfile(local);
        list<string> peers;
        std::unique_ptr<RaftSM> sm;

        for (const auto &peer : names) {
            if (peer != local) {
                peers.push_back(peer);
            }
        }

        sm = make_unique<TestReplica>(
            /*smname=*/local + "-sm", /*myname=*/local, logfilename);
        if (sm->init(peers, &output)) {
            return -1;
        }
        replicas[local] = std::move(sm);
    }

    while (t <= t_max) {
        unsigned int t_next = t + 1;
        RaftSMOutput output_next;

        cout << "| t = " << t << " |" << endl;

        /* Process current output messages. */
        for (const auto &p : output.output_messages) {
            auto *rv  = dynamic_cast<RaftRequestVote *>(p.second.get());
            auto *rvr = dynamic_cast<RaftRequestVoteResp *>(p.second.get());
            auto *ae  = dynamic_cast<RaftAppendEntries *>(p.second.get());
            auto *aer = dynamic_cast<RaftAppendEntriesResp *>(p.second.get());
            int r     = 0;

            assert(replicas.count(p.first));
            if (rv) {
                r = replicas[p.first]->request_vote_input(*rv, &output_next);
            } else if (rvr) {
                r = replicas[p.first]->request_vote_resp_input(*rvr,
                                                               &output_next);
            } else if (ae) {
                r = replicas[p.first]->append_entries_input(*ae, &output_next);
            } else if (aer) {
                r = replicas[p.first]->append_entries_resp_input(*aer,
                                                                 &output_next);
            } else {
                assert(false);
            }

            if (r) {
                return r;
            }
        }

        /* Process current timer commands. */
        for (const RaftTimerCmd &cmd : output.timer_commands) {
            for (auto it = events.begin(); it != events.end(); it++) {
                if (it->sm == cmd.sm && it->ttype == cmd.type) {
                    events.erase(it);
                    break;
                }
            }
            if (cmd.action == RaftTimerAction::Restart) {
                events.push_back(TestEvent::CreateTimerEvent(
                    t + cmd.milliseconds, cmd.sm, cmd.type));
                events.sort();
            } else {
                assert(cmd.action == RaftTimerAction::Stop);
            }
        }

        /* Process all the timers expired so far, updating the associated
         * Raft state machine. */
        while (!events.empty()) {
            const TestEvent &next = events.front();
            if (t < next.abstime) {
                if (output_next.output_messages.empty() &&
                    output_next.timer_commands.empty()) {
                    /* No need to go step by step, we can jump to the next
                     * event. */
                    t_next = next.abstime;
                }
                break;
            }
            switch (next.event_type) {
            case TestEventType::RaftTimer: {
                /* This event is a timer firing. */
                if (next.sm->timer_expired(next.ttype, &output_next)) {
                    return -1;
                }
                break;
            }

            case TestEventType::ClientRequest: {
                /* This event is a client submission. */
                bool submitted = false;
                for (const auto &kv : replicas) {
                    if (kv.second->leader()) {
                        LogIndex request_id;
                        uint32_t cmd = TestEvent::get_next_command();

                        if (kv.second->submit(reinterpret_cast<char *>(&cmd),
                                              &request_id, &output_next)) {
                            return -1;
                        }
                        submitted = true;
                        cout << "Command " << cmd << " submitted" << endl;
                    }
                }
                if (!submitted) {
                    cout << "Dropped client request (no leader)" << endl;
                }
            }
            case TestEventType::SMFailure: {
                break;
            }
            case TestEventType::SMRespawn: {
                break;
            }
            }
            events.pop_front();
        }
        t      = t_next;
        output = std::move(output_next);
    }

    return 0;
}
<|endoftext|>