<commit_before>//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "stdlib.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "lldb/Core/Log.h"
#include "lldb/Expression/ASTResultSynthesizer.h"

using namespace llvm;
using namespace clang;
using namespace lldb_private;

ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
                                           TypeFromUser desired_type) :
    m_ast_context (NULL),
    m_passthrough (passthrough),
    m_passthrough_sema (NULL),
    m_sema (NULL),
    m_desired_type (desired_type)
{
    if (!m_passthrough)
        return;

    m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
}

ASTResultSynthesizer::~ASTResultSynthesizer()
{
}

void
ASTResultSynthesizer::Initialize(ASTContext &Context)
{
    m_ast_context = &Context;

    if (m_passthrough)
        m_passthrough->Initialize(Context);
}

void
ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
    {
        if (log)
        {
            if (named_decl->getIdentifier())
                log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
            else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
                log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
            else
                log->Printf("TransformTopLevelDecl(<complex>)");
        }

    }

    if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
    {
        RecordDecl::decl_iterator decl_iterator;

        for (decl_iterator = linkage_spec_decl->decls_begin();
             decl_iterator != linkage_spec_decl->decls_end();
             ++decl_iterator)
        {
            TransformTopLevelDecl(*decl_iterator);
        }
    }
    else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
    {
        if (m_ast_context &&
            !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
        {
            SynthesizeObjCMethodResult(method_decl);
        }
    }
    else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
    {
        if (m_ast_context &&
            !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
        {
            SynthesizeFunctionResult(function_decl);
        }
    }
}

void
ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
{
    DeclGroupRef::iterator decl_iterator;

    for (decl_iterator = D.begin();
         decl_iterator != D.end();
         ++decl_iterator)
    {
        Decl *decl = *decl_iterator;

        TransformTopLevelDecl(decl);
    }

    if (m_passthrough)
        m_passthrough->HandleTopLevelDecl(D);
}

bool
ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    if (!m_sema)
        return false;

    FunctionDecl *function_decl = FunDecl;

    if (!function_decl)
        return false;

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        Ctx.getTranslationUnitDecl()->print(os);

        os.flush();

        log->Printf("AST context before transforming:\n%s", s.c_str());
    }

    Stmt *function_body = function_decl->getBody();
    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);

    bool ret = SynthesizeBodyResult (compound_stmt,
                                     function_decl);

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        function_decl->print(os);

        os.flush();

        log->Printf ("Transformed function AST:\n%s", s.c_str());
    }

    return ret;
}

bool
ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    if (!m_sema)
        return false;

    if (!MethodDecl)
        return false;

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        Ctx.getTranslationUnitDecl()->print(os);

        os.flush();

        log->Printf("AST context before transforming:\n%s", s.c_str());
    }

    Stmt *method_body = MethodDecl->getBody();
    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);

    bool ret = SynthesizeBodyResult (compound_stmt,
                                     MethodDecl);

    if (log)
    {
        std::string s;
        raw_string_ostream os(s);

        MethodDecl->print(os);

        os.flush();

        log->Printf("Transformed function AST:\n%s", s.c_str());
    }

    return ret;
}

bool
ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
                                            DeclContext *DC)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(Body);

    if (!compound_stmt)
        return false;

    if (compound_stmt->body_empty())
        return false;

    Stmt **last_stmt_ptr = compound_stmt->body_end() - 1;
    Stmt *last_stmt = *last_stmt_ptr;

    while (dyn_cast<NullStmt>(last_stmt))
    {
        if (last_stmt_ptr != compound_stmt->body_begin())
        {
            last_stmt_ptr--;
            last_stmt = *last_stmt_ptr;
        }
        else
        {
            return false;
        }
    }

    Expr *last_expr = dyn_cast<Expr>(last_stmt);

    if (!last_expr)
        // No auxiliary variable necessary; expression returns void
        return true;

    // is_lvalue is used to record whether the expression returns an assignable Lvalue or an
    // Rvalue.  This is relevant because they are handled differently.
    //
    // For Lvalues
    //
    //   - In AST result synthesis (here!) the expression E is transformed into an initialization
    //     T *$__lldb_expr_result_ptr = &E.
    //
    //   - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
    //     passed into the expression.
    //
    //   - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at
    //     an entry in the struct ($__lldb_arg) passed into the expression.  (Other persistent
    //     variables are treated similarly, having been materialized as references, but in those
    //     cases the value of the reference itself is never modified.)
    //
    //   - During materialization, $0 (the result persistent variable) is ignored.
    //
    //   - During dematerialization, $0 is marked up as a load address with value equal to the
    //     contents of the structure entry.
    //
    // For Rvalues
    //
    //   - In AST result synthesis the expression E is transformed into an initialization
    //     static T $__lldb_expr_result = E.
    //
    //   - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
    //     passed into the expression.
    //
    //   - In IR transformations, an instruction is inserted at the beginning of the function to
    //     dereference the pointer resident in the slot.  Reads and writes to $__lldb_expr_result
    //     are redirected at that dereferenced version.  Guard variables for the static variable
    //     are excised.
    //
    //   - During materialization, $0 (the result persistent variable) is populated with the location
    //     of a newly-allocated area of memory.
    //
    //   - During dematerialization, $0 is ignored.

    bool is_lvalue =
        (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
        (last_expr->getObjectKind() == OK_Ordinary);

    QualType expr_qual_type = last_expr->getType();
    const clang::Type *expr_type = expr_qual_type.getTypePtr();

    if (!expr_type)
        return false;

    if (expr_type->isVoidType())
        return true;

    if (log)
    {
        std::string s = expr_qual_type.getAsString();

        log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
    }

    clang::VarDecl *result_decl = NULL;

    if (is_lvalue)
    {
        IdentifierInfo &result_ptr_id = Ctx.Idents.get("$__lldb_expr_result_ptr");

        QualType ptr_qual_type = Ctx.getPointerType(expr_qual_type);

        result_decl = VarDecl::Create(Ctx,
                                      DC,
                                      SourceLocation(),
                                      SourceLocation(),
                                      &result_ptr_id,
                                      ptr_qual_type,
                                      NULL,
                                      SC_Static,
                                      SC_Static);

        if (!result_decl)
            return false;

        ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);

        m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, true);
    }
    else
    {
        IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");

        result_decl = VarDecl::Create(Ctx,
                                      DC,
                                      SourceLocation(),
                                      SourceLocation(),
                                      &result_id,
                                      expr_qual_type,
                                      NULL,
                                      SC_Static,
                                      SC_Static);

        if (!result_decl)
            return false;

        m_sema->AddInitializerToDecl(result_decl, last_expr, true, true);
    }

    DC->addDecl(result_decl);

    ///////////////////////////////
    // call AddInitializerToDecl
    //

    //m_sema->AddInitializerToDecl(result_decl, last_expr);

    /////////////////////////////////
    // call ConvertDeclToDeclGroup
    //

    Sema::DeclGroupPtrTy result_decl_group_ptr;

    result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);

    ////////////////////////
    // call ActOnDeclStmt
    //

    StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
                                                                       SourceLocation(),
                                                                       SourceLocation()));

    ////////////////////////////////////////////////
    // replace the old statement with the new one
    //

    *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());

    return true;
}

void
ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
{
    if (m_passthrough)
        m_passthrough->HandleTranslationUnit(Ctx);
}

void
ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
{
    if (m_passthrough)
        m_passthrough->HandleTagDeclDefinition(D);
}

void
ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
{
    if (m_passthrough)
        m_passthrough->CompleteTentativeDefinition(D);
}

void
ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
{
    if (m_passthrough)
        m_passthrough->HandleVTable(RD, DefinitionRequired);
}

void
ASTResultSynthesizer::PrintStats()
{
    if (m_passthrough)
        m_passthrough->PrintStats();
}

void
ASTResultSynthesizer::InitializeSema(Sema &S)
{
    m_sema = &S;

    if (m_passthrough_sema)
        m_passthrough_sema->InitializeSema(S);
}

void
ASTResultSynthesizer::ForgetSema()
{
    m_sema = NULL;

    if (m_passthrough_sema)
        m_passthrough_sema->ForgetSema();
}
<commit_msg>Removed a redundant dyn_cast.  Thanks to Felipe Cabecinhas.<commit_after>//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "stdlib.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Stmt.h"
#include "clang/Parse/Parser.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "lldb/Core/Log.h"
#include "lldb/Expression/ASTResultSynthesizer.h"

using namespace llvm;
using namespace clang;
using namespace lldb_private;

ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
                                           TypeFromUser desired_type) :
    m_ast_context (NULL),
    m_passthrough (passthrough),
    m_passthrough_sema (NULL),
    m_sema (NULL),
    m_desired_type (desired_type)
{
    if (!m_passthrough)
        return;

    m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
}

ASTResultSynthesizer::~ASTResultSynthesizer()
{
}

void
ASTResultSynthesizer::Initialize(ASTContext &Context)
{
    m_ast_context = &Context;

    if (m_passthrough)
        m_passthrough->Initialize(Context);
}

void
ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
    {
        if (log)
        {
            if (named_decl->getIdentifier())
                log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
            else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
                log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
            else
                log->Printf("TransformTopLevelDecl(<complex>)");
        }

    }

    if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
    {
        RecordDecl::decl_iterator decl_iterator;

        for (decl_iterator = linkage_spec_decl->decls_begin();
             decl_iterator != linkage_spec_decl->decls_end();
             ++decl_iterator)
        {
            TransformTopLevelDecl(*decl_iterator);
        }
    }
    else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
    {
        if (m_ast_context &&
            !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
        {
            SynthesizeObjCMethodResult(method_decl);
        }
    }
    else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
    {
        if (m_ast_context &&
            !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
        {
            SynthesizeFunctionResult(function_decl);
        }
    }
}

void
ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
{
    DeclGroupRef::iterator decl_iterator;

    for (decl_iterator = D.begin();
         decl_iterator != D.end();
         ++decl_iterator)
    {
        Decl *decl = *decl_iterator;

        TransformTopLevelDecl(decl);
    }

    if (m_passthrough)
        m_passthrough->HandleTopLevelDecl(D);
}

bool
ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    if (!m_sema)
        return false;

    FunctionDecl *function_decl = FunDecl;

    if (!function_decl)
        return false;

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        Ctx.getTranslationUnitDecl()->print(os);

        os.flush();

        log->Printf("AST context before transforming:\n%s", s.c_str());
    }

    Stmt *function_body = function_decl->getBody();
    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);

    bool ret = SynthesizeBodyResult (compound_stmt,
                                     function_decl);

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        function_decl->print(os);

        os.flush();

        log->Printf ("Transformed function AST:\n%s", s.c_str());
    }

    return ret;
}

bool
ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    if (!m_sema)
        return false;

    if (!MethodDecl)
        return false;

    if (log && log->GetVerbose())
    {
        std::string s;
        raw_string_ostream os(s);

        Ctx.getTranslationUnitDecl()->print(os);

        os.flush();

        log->Printf("AST context before transforming:\n%s", s.c_str());
    }

    Stmt *method_body = MethodDecl->getBody();
    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);

    bool ret = SynthesizeBodyResult (compound_stmt,
                                     MethodDecl);

    if (log)
    {
        std::string s;
        raw_string_ostream os(s);

        MethodDecl->print(os);

        os.flush();

        log->Printf("Transformed function AST:\n%s", s.c_str());
    }

    return ret;
}

bool
ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
                                            DeclContext *DC)
{
    lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

    ASTContext &Ctx(*m_ast_context);

    if (!Body)
        return false;

    if (Body->body_empty())
        return false;

    Stmt **last_stmt_ptr = Body->body_end() - 1;
    Stmt *last_stmt = *last_stmt_ptr;

    while (dyn_cast<NullStmt>(last_stmt))
    {
        if (last_stmt_ptr != Body->body_begin())
        {
            last_stmt_ptr--;
            last_stmt = *last_stmt_ptr;
        }
        else
        {
            return false;
        }
    }

    Expr *last_expr = dyn_cast<Expr>(last_stmt);

    if (!last_expr)
        // No auxiliary variable necessary; expression returns void
        return true;

    // is_lvalue is used to record whether the expression returns an assignable Lvalue or an
    // Rvalue.  This is relevant because they are handled differently.
    //
    // For Lvalues
    //
    //   - In AST result synthesis (here!) the expression E is transformed into an initialization
    //     T *$__lldb_expr_result_ptr = &E.
    //
    //   - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
    //     passed into the expression.
    //
    //   - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at
    //     an entry in the struct ($__lldb_arg) passed into the expression.  (Other persistent
    //     variables are treated similarly, having been materialized as references, but in those
    //     cases the value of the reference itself is never modified.)
    //
    //   - During materialization, $0 (the result persistent variable) is ignored.
    //
    //   - During dematerialization, $0 is marked up as a load address with value equal to the
    //     contents of the structure entry.
    //
    // For Rvalues
    //
    //   - In AST result synthesis the expression E is transformed into an initialization
    //     static T $__lldb_expr_result = E.
    //
    //   - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
    //     passed into the expression.
    //
    //   - In IR transformations, an instruction is inserted at the beginning of the function to
    //     dereference the pointer resident in the slot.  Reads and writes to $__lldb_expr_result
    //     are redirected at that dereferenced version.  Guard variables for the static variable
    //     are excised.
    //
    //   - During materialization, $0 (the result persistent variable) is populated with the location
    //     of a newly-allocated area of memory.
    //
    //   - During dematerialization, $0 is ignored.

    bool is_lvalue =
        (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
        (last_expr->getObjectKind() == OK_Ordinary);

    QualType expr_qual_type = last_expr->getType();
    const clang::Type *expr_type = expr_qual_type.getTypePtr();

    if (!expr_type)
        return false;

    if (expr_type->isVoidType())
        return true;

    if (log)
    {
        std::string s = expr_qual_type.getAsString();

        log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
    }

    clang::VarDecl *result_decl = NULL;

    if (is_lvalue)
    {
        IdentifierInfo &result_ptr_id = Ctx.Idents.get("$__lldb_expr_result_ptr");

        QualType ptr_qual_type = Ctx.getPointerType(expr_qual_type);

        result_decl = VarDecl::Create(Ctx,
                                      DC,
                                      SourceLocation(),
                                      SourceLocation(),
                                      &result_ptr_id,
                                      ptr_qual_type,
                                      NULL,
                                      SC_Static,
                                      SC_Static);

        if (!result_decl)
            return false;

        ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);

        m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, true);
    }
    else
    {
        IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");

        result_decl = VarDecl::Create(Ctx,
                                      DC,
                                      SourceLocation(),
                                      SourceLocation(),
                                      &result_id,
                                      expr_qual_type,
                                      NULL,
                                      SC_Static,
                                      SC_Static);

        if (!result_decl)
            return false;

        m_sema->AddInitializerToDecl(result_decl, last_expr, true, true);
    }

    DC->addDecl(result_decl);

    ///////////////////////////////
    // call AddInitializerToDecl
    //

    //m_sema->AddInitializerToDecl(result_decl, last_expr);

    /////////////////////////////////
    // call ConvertDeclToDeclGroup
    //

    Sema::DeclGroupPtrTy result_decl_group_ptr;

    result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);

    ////////////////////////
    // call ActOnDeclStmt
    //

    StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
                                                                       SourceLocation(),
                                                                       SourceLocation()));

    ////////////////////////////////////////////////
    // replace the old statement with the new one
    //

    *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());

    return true;
}

void
ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
{
    if (m_passthrough)
        m_passthrough->HandleTranslationUnit(Ctx);
}

void
ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
{
    if (m_passthrough)
        m_passthrough->HandleTagDeclDefinition(D);
}

void
ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
{
    if (m_passthrough)
        m_passthrough->CompleteTentativeDefinition(D);
}

void
ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
{
    if (m_passthrough)
        m_passthrough->HandleVTable(RD, DefinitionRequired);
}

void
ASTResultSynthesizer::PrintStats()
{
    if (m_passthrough)
        m_passthrough->PrintStats();
}

void
ASTResultSynthesizer::InitializeSema(Sema &S)
{
    m_sema = &S;

    if (m_passthrough_sema)
        m_passthrough_sema->InitializeSema(S);
}

void
ASTResultSynthesizer::ForgetSema()
{
    m_sema = NULL;

    if (m_passthrough_sema)
        m_passthrough_sema->ForgetSema();
}
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_roostats
/// \notebook -js
/// 'Bernstein Correction' RooStats tutorial macro
///
/// This tutorial shows usage of a the BernsteinCorrection utility in RooStats.
/// The idea is that one has a distribution coming either from data or Monte Carlo
/// (called "reality" in the macro) and a nominal model that is not sufficiently
/// flexible to take into account the real distribution.  One wants to take into
/// account the systematic associated with this imperfect modeling by augmenting
/// the nominal model with some correction term (in this case a polynomial).
/// The BernsteinCorrection utility will import into your workspace a corrected model
/// given by nominal(x) * poly_N(x), where poly_N is an n-th order polynomial in
/// the Bernstein basis.  The degree N of the polynomial is chosen by specifying the tolerance
/// one has in adding an extra term to the polynomial.
/// The Bernstein basis is nice because it only has positive-definite terms
/// and works well with PDFs.
/// Finally, the macro makes a plot of:
///  - the data (drawn from 'reality'),
///  - the best fit of the nominal model (blue)
///  - and the best fit corrected model.
///
/// \macro_image
/// \macro_output
/// \macro_code
///
/// \author Kyle Cranmer

#include "RooDataSet.h"
#include "RooRealVar.h"
#include "RooConstVar.h"
#include "RooBernstein.h"
#include "TCanvas.h"
#include "RooAbsPdf.h"
#include "RooFit.h"
#include "RooFitResult.h"
#include "RooPlot.h"
#include <string>
#include <vector>
#include <stdio.h>
#include <sstream>
#include <iostream>

#include "RooProdPdf.h"
#include "RooAddPdf.h"
#include "RooGaussian.h"
#include "RooNLLVar.h"
#include "RooMinuit.h"
#include "RooProfileLL.h"
#include "RooWorkspace.h"

#include "RooStats/BernsteinCorrection.h"

// use this order for safety on library loading
using namespace RooFit;
using namespace RooStats;

//____________________________________
void rs_bernsteinCorrection(){

   // set range of observable
   Double_t lowRange = -1, highRange =5;

   // make a RooRealVar for the observable
   RooRealVar x("x", "x", lowRange, highRange);

   // true model
   RooGaussian narrow("narrow","",x,RooConst(0.), RooConst(.8));
   RooGaussian wide("wide","",x,RooConst(0.), RooConst(2.));
   RooAddPdf reality("reality","",RooArgList(narrow, wide), RooConst(0.8));

   RooDataSet* data = reality.generate(x,1000);

   // nominal model
   RooRealVar sigma("sigma","",1.,0,10);
   RooGaussian nominal("nominal","",x,RooConst(0.), sigma);

   RooWorkspace* wks = new RooWorkspace("myWorksspace");

   wks->import(*data, Rename("data"));
   wks->import(nominal);

   // use Minuit2
   ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2");

   // The tolerance sets the probability to add an unnecessary term.
   // lower tolerance will add fewer terms, while higher tolerance
   // will add more terms and provide a more flexible function.
   Double_t tolerance = 0.05;
   BernsteinCorrection bernsteinCorrection(tolerance);
   Int_t degree = bernsteinCorrection.ImportCorrectedPdf(wks,"nominal","x","data");

   if (degree < 0) {
      Error("rs_bernsteinCorrection","Bernstein correction failed ! ");
      return;
   }

   cout << " Correction based on Bernstein Poly of degree " << degree << endl;

   RooPlot* frame = x.frame();
   data->plotOn(frame);
   // plot the best fit nominal model in blue
   TString minimType =  ROOT::Math::MinimizerOptions::DefaultMinimizerType();
   nominal.fitTo(*data,PrintLevel(0),Minimizer(minimType));
   nominal.plotOn(frame);

   // plot the best fit corrected model in red
   RooAbsPdf* corrected = wks->pdf("corrected");
   if (!corrected) return;

   // fit corrected model
   corrected->fitTo(*data,PrintLevel(0),Minimizer(minimType) );
   corrected->plotOn(frame,LineColor(kRed));

   // plot the correction term (* norm constant) in dashed green
   // should make norm constant just be 1, not depend on binning of data
   RooAbsPdf* poly = wks->pdf("poly");
   if (poly)
   poly->plotOn(frame,LineColor(kGreen), LineStyle(kDashed));

   // this is a switch to check the sampling distribution
   // of -2 log LR for two comparisons:
   // the first is for n-1 vs. n degree polynomial corrections
   // the second is for n vs. n+1 degree polynomial corrections
   // Here we choose n to be the one chosen by the tolerance
   // criterion above, eg. n = "degree" in the code.
   // Setting this to true is takes about 10 min.
   bool checkSamplingDist = true;
   int numToyMC = 20;  // increase this value for sensible results

   TCanvas* c1 = new TCanvas();
   if(checkSamplingDist) {
      c1->Divide(1,2);
      c1->cd(1);
   }
   frame->Draw();
   gPad->Update();

   if(checkSamplingDist) {
      // check sampling dist
      ROOT::Math::MinimizerOptions::SetDefaultPrintLevel(-1);
      TH1F* samplingDist = new TH1F("samplingDist","",20,0,10);
      TH1F* samplingDistExtra = new TH1F("samplingDistExtra","",20,0,10);
      bernsteinCorrection.CreateQSamplingDist(wks,"nominal","x","data",samplingDist, samplingDistExtra, degree,numToyMC);

      c1->cd(2);
      samplingDistExtra->SetLineColor(kRed);
      samplingDistExtra->Draw();
      samplingDist->Draw("same");
   }
}

<commit_msg>Only enable Minuit2 if ROOT was configured with it!<commit_after>/// \file
/// \ingroup tutorial_roostats
/// \notebook -js
/// 'Bernstein Correction' RooStats tutorial macro
///
/// This tutorial shows usage of a the BernsteinCorrection utility in RooStats.
/// The idea is that one has a distribution coming either from data or Monte Carlo
/// (called "reality" in the macro) and a nominal model that is not sufficiently
/// flexible to take into account the real distribution.  One wants to take into
/// account the systematic associated with this imperfect modeling by augmenting
/// the nominal model with some correction term (in this case a polynomial).
/// The BernsteinCorrection utility will import into your workspace a corrected model
/// given by nominal(x) * poly_N(x), where poly_N is an n-th order polynomial in
/// the Bernstein basis.  The degree N of the polynomial is chosen by specifying the tolerance
/// one has in adding an extra term to the polynomial.
/// The Bernstein basis is nice because it only has positive-definite terms
/// and works well with PDFs.
/// Finally, the macro makes a plot of:
///  - the data (drawn from 'reality'),
///  - the best fit of the nominal model (blue)
///  - and the best fit corrected model.
///
/// \macro_image
/// \macro_output
/// \macro_code
///
/// \author Kyle Cranmer

#include "RooDataSet.h"
#include "RooRealVar.h"
#include "RooConstVar.h"
#include "RooBernstein.h"
#include "TCanvas.h"
#include "RooAbsPdf.h"
#include "RooFit.h"
#include "RooFitResult.h"
#include "RooPlot.h"
#include <string>
#include <vector>
#include <stdio.h>
#include <sstream>
#include <iostream>

#include "RooProdPdf.h"
#include "RooAddPdf.h"
#include "RooGaussian.h"
#include "RooNLLVar.h"
#include "RooMinuit.h"
#include "RooProfileLL.h"
#include "RooWorkspace.h"

#include "RooStats/BernsteinCorrection.h"

// use this order for safety on library loading
using namespace RooFit;
using namespace RooStats;

//____________________________________
void rs_bernsteinCorrection(){

   // set range of observable
   Double_t lowRange = -1, highRange =5;

   // make a RooRealVar for the observable
   RooRealVar x("x", "x", lowRange, highRange);

   // true model
   RooGaussian narrow("narrow","",x,RooConst(0.), RooConst(.8));
   RooGaussian wide("wide","",x,RooConst(0.), RooConst(2.));
   RooAddPdf reality("reality","",RooArgList(narrow, wide), RooConst(0.8));

   RooDataSet* data = reality.generate(x,1000);

   // nominal model
   RooRealVar sigma("sigma","",1.,0,10);
   RooGaussian nominal("nominal","",x,RooConst(0.), sigma);

   RooWorkspace* wks = new RooWorkspace("myWorksspace");

   wks->import(*data, Rename("data"));
   wks->import(nominal);

   if (TClass::GetClass("ROOT::Minuit2::Minuit2Minimizer")) {
      // use Minuit2 if ROOT was built with support for it:
      ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2");
   }

   // The tolerance sets the probability to add an unnecessary term.
   // lower tolerance will add fewer terms, while higher tolerance
   // will add more terms and provide a more flexible function.
   Double_t tolerance = 0.05;
   BernsteinCorrection bernsteinCorrection(tolerance);
   Int_t degree = bernsteinCorrection.ImportCorrectedPdf(wks,"nominal","x","data");

   if (degree < 0) {
      Error("rs_bernsteinCorrection","Bernstein correction failed ! ");
      return;
   }

   cout << " Correction based on Bernstein Poly of degree " << degree << endl;

   RooPlot* frame = x.frame();
   data->plotOn(frame);
   // plot the best fit nominal model in blue
   TString minimType =  ROOT::Math::MinimizerOptions::DefaultMinimizerType();
   nominal.fitTo(*data,PrintLevel(0),Minimizer(minimType));
   nominal.plotOn(frame);

   // plot the best fit corrected model in red
   RooAbsPdf* corrected = wks->pdf("corrected");
   if (!corrected) return;

   // fit corrected model
   corrected->fitTo(*data,PrintLevel(0),Minimizer(minimType) );
   corrected->plotOn(frame,LineColor(kRed));

   // plot the correction term (* norm constant) in dashed green
   // should make norm constant just be 1, not depend on binning of data
   RooAbsPdf* poly = wks->pdf("poly");
   if (poly)
   poly->plotOn(frame,LineColor(kGreen), LineStyle(kDashed));

   // this is a switch to check the sampling distribution
   // of -2 log LR for two comparisons:
   // the first is for n-1 vs. n degree polynomial corrections
   // the second is for n vs. n+1 degree polynomial corrections
   // Here we choose n to be the one chosen by the tolerance
   // criterion above, eg. n = "degree" in the code.
   // Setting this to true is takes about 10 min.
   bool checkSamplingDist = true;
   int numToyMC = 20;  // increase this value for sensible results

   TCanvas* c1 = new TCanvas();
   if(checkSamplingDist) {
      c1->Divide(1,2);
      c1->cd(1);
   }
   frame->Draw();
   gPad->Update();

   if(checkSamplingDist) {
      // check sampling dist
      ROOT::Math::MinimizerOptions::SetDefaultPrintLevel(-1);
      TH1F* samplingDist = new TH1F("samplingDist","",20,0,10);
      TH1F* samplingDistExtra = new TH1F("samplingDistExtra","",20,0,10);
      bernsteinCorrection.CreateQSamplingDist(wks,"nominal","x","data",samplingDist, samplingDistExtra, degree,numToyMC);

      c1->cd(2);
      samplingDistExtra->SetLineColor(kRed);
      samplingDistExtra->Draw();
      samplingDist->Draw("same");
   }
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: opump.cxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 23:44:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_io.hxx"

#include <stdio.h>

#include <osl/diagnose.h>

#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XActiveDataControl.hpp>
#include <com/sun/star/io/XConnectable.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/registry/XRegistryKey.hpp>

#include <uno/dispatcher.h>
#include <uno/mapping.hxx>
#include <cppuhelper/implbase5.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/interfacecontainer.hxx>
#include <osl/mutex.hxx>
#include <osl/thread.h>

using namespace osl;
using namespace std;
using namespace rtl;
using namespace cppu;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;
using namespace com::sun::star::io;

#include "factreg.hxx"

namespace io_stm {

    class Pump : public WeakImplHelper5<
          XActiveDataSource, XActiveDataSink, XActiveDataControl, XConnectable, XServiceInfo >
    {
        Mutex                                   m_aMutex;
        oslThread                               m_aThread;

        Reference< XConnectable >               m_xPred;
        Reference< XConnectable >               m_xSucc;
        Reference< XInputStream >               m_xInput;
        Reference< XOutputStream >              m_xOutput;
        OInterfaceContainerHelper               m_cnt;
        sal_Bool                                m_closeFired;

        void run();
        static void static_run( void* pObject );

        void close();
        void fireClose();
        void fireStarted();
        void fireTerminated();
        void fireError( const Any &a );

    public:
        Pump();
        virtual ~Pump();

        // XActiveDataSource
        virtual void SAL_CALL setOutputStream( const Reference< ::com::sun::star::io::XOutputStream >& xOutput ) throw();
        virtual Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream() throw();

        // XActiveDataSink
        virtual void SAL_CALL setInputStream( const Reference< ::com::sun::star::io::XInputStream >& xStream ) throw();
        virtual Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream() throw();

        // XActiveDataControl
        virtual void SAL_CALL addListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
        virtual void SAL_CALL removeListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
        virtual void SAL_CALL start() throw( RuntimeException );
        virtual void SAL_CALL terminate() throw();

        // XConnectable
        virtual void SAL_CALL setPredecessor( const Reference< ::com::sun::star::io::XConnectable >& xPred ) throw();
        virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getPredecessor() throw();
        virtual void SAL_CALL setSuccessor( const Reference< ::com::sun::star::io::XConnectable >& xSucc ) throw();
        virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getSuccessor() throw();

    public: // XServiceInfo
        virtual OUString    SAL_CALL getImplementationName() throw(  );
        virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw(  );
        virtual sal_Bool     SAL_CALL supportsService(const OUString& ServiceName) throw(  );
    };

Pump::Pump() : m_aThread( 0 ),
               m_cnt( m_aMutex ),
               m_closeFired( sal_False )
{
    g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}

Pump::~Pump()
{
    // exit gracefully
    if( m_aThread )
    {
        osl_joinWithThread( m_aThread );
        osl_destroyThread( m_aThread );
    }
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

void Pump::fireError( const  Any & exception )
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->error( exception );
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::fireClose()
{
    sal_Bool bFire = sal_False;
    {
        MutexGuard guard( m_aMutex );
        if( ! m_closeFired  )
        {
            m_closeFired = sal_True;
            bFire = sal_True;
        }
    }

    if( bFire )
    {
        OInterfaceIteratorHelper iter( m_cnt );
        while( iter.hasMoreElements() )
        {
            try
            {
                static_cast< XStreamListener * > ( iter.next() )->closed( );
            }
            catch ( RuntimeException &e )
            {
                OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
                OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
            }
        }
    }
}

void Pump::fireStarted()
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->started( );
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::fireTerminated()
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->terminated();
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::close()
{
    // close streams and release references
    Reference< XInputStream > rInput;
    Reference< XOutputStream > rOutput;
    {
        MutexGuard guard( m_aMutex );
        rInput = m_xInput;
        m_xInput.clear();

        rOutput = m_xOutput;
        m_xOutput.clear();
        m_xSucc.clear();
        m_xPred.clear();
    }
    if( rInput.is() )
    {
        try
        {
            rInput->closeInput();
        }
        catch( Exception & )
        {
            // go down calm
        }
    }
    if( rOutput.is() )
    {
        try
        {
            rOutput->closeOutput();
        }
        catch( Exception & )
        {
            // go down calm
        }
    }
}

void Pump::static_run( void* pObject )
{
    ((Pump*)pObject)->run();
    ((Pump*)pObject)->release();
}

void Pump::run()
{
    try
    {
        fireStarted();
        try
        {
            Reference< XInputStream > rInput;
            Reference< XOutputStream > rOutput;
            {
                Guard< Mutex > aGuard( m_aMutex );
                rInput = m_xInput;
                rOutput = m_xOutput;
            }

            if( ! rInput.is() )
            {
                NotConnectedException exception(
                    OUString::createFromAscii( "no input stream set" ) , Reference<XInterface>((OWeakObject*)this) );
                throw exception;
            }
            Sequence< sal_Int8 > aData;
            while( rInput->readSomeBytes( aData, 65536 ) )
            {
                if( ! rOutput.is() )
                {
                    NotConnectedException exception(
                        OUString::createFromAscii( "no output stream set" ) , Reference<XInterface>( (OWeakObject*)this) );
                    throw exception;
                }
                rOutput->writeBytes( aData );
                osl_yieldThread();
            }
        }
        catch ( IOException & e )
        {
            fireError( makeAny( e ) );
        }
        catch ( RuntimeException & e )
        {
            fireError( makeAny( e ) );
        }
        catch ( Exception & e )
        {
            fireError( makeAny( e ) );
        }

        close();
        fireClose();
    }
    catch ( com::sun::star::uno::Exception &e )
    {
        // we are the last on the stack.
        // this is to avoid crashing the program, when e.g. a bridge crashes
        OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
        OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception", sMessage.getStr() );
    }
}

// ------------------------------------------------------------

/*
 * XConnectable
 */

void Pump::setPredecessor( const Reference< XConnectable >& xPred ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xPred = xPred;
}

// ------------------------------------------------------------

Reference< XConnectable > Pump::getPredecessor() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xPred;
}

// ------------------------------------------------------------

void Pump::setSuccessor( const Reference< XConnectable >& xSucc ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xSucc = xSucc;
}

// ------------------------------------------------------------

Reference< XConnectable > Pump::getSuccessor() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xSucc;
}

// -----------------------------------------------------------------

/*
 * XActiveDataControl
 */

void Pump::addListener( const Reference< XStreamListener >& xListener ) throw()
{
    m_cnt.addInterface( xListener );
}

// ------------------------------------------------------------

void Pump::removeListener( const Reference< XStreamListener >& xListener ) throw()
{
    m_cnt.removeInterface( xListener );
}

// ------------------------------------------------------------

void Pump::start() throw( RuntimeException )
{
    Guard< Mutex > aGuard( m_aMutex );
    m_aThread = osl_createSuspendedThread((oslWorkerFunction)Pump::static_run,this);
    if( m_aThread )
    {
        // will be released by OPump::static_run
        acquire();
        osl_resumeThread( m_aThread );
    }
    else
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM( "Pump::start Couldn't create worker thread" )),
            *this);
    }
}

// ------------------------------------------------------------

void Pump::terminate() throw()
{
    close();

    // wait for the worker to die
    if( m_aThread )
        osl_joinWithThread( m_aThread );

    fireTerminated();
    fireClose();
}

// ------------------------------------------------------------

/*
 * XActiveDataSink
 */

void Pump::setInputStream( const Reference< XInputStream >& xStream ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xInput = xStream;
    Reference< XConnectable > xConnect( xStream, UNO_QUERY );
    if( xConnect.is() )
        xConnect->setSuccessor( this );
    // data transfer starts in XActiveDataControl::start
}

// ------------------------------------------------------------

Reference< XInputStream > Pump::getInputStream() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xInput;
}

// ------------------------------------------------------------

/*
 * XActiveDataSource
 */

void Pump::setOutputStream( const Reference< XOutputStream >& xOut ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xOutput = xOut;
    Reference< XConnectable > xConnect( xOut, UNO_QUERY );
    if( xConnect.is() )
        xConnect->setPredecessor( this );
    // data transfer starts in XActiveDataControl::start
}

// ------------------------------------------------------------

Reference< XOutputStream > Pump::getOutputStream() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xOutput;
}

// XServiceInfo
OUString Pump::getImplementationName() throw(  )
{
    return OPumpImpl_getImplementationName();
}

// XServiceInfo
sal_Bool Pump::supportsService(const OUString& ServiceName) throw(  )
{
    Sequence< OUString > aSNL = getSupportedServiceNames();
    const OUString * pArray = aSNL.getConstArray();

    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
        if( pArray[i] == ServiceName )
            return sal_True;

    return sal_False;
}

// XServiceInfo
Sequence< OUString > Pump::getSupportedServiceNames(void) throw(  )
{
    return OPumpImpl_getSupportedServiceNames();
}

Reference< XInterface > SAL_CALL OPumpImpl_CreateInstance( const Reference< XComponentContext > & ) throw (Exception)
{
    return Reference< XInterface >( *new Pump );
}

OUString OPumpImpl_getImplementationName()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.Pump") );
}

Sequence<OUString> OPumpImpl_getSupportedServiceNames(void)
{
    OUString s( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.Pump" ) );
    Sequence< OUString > seq( &s , 1 );
    return seq;
}

}

<commit_msg>INTEGRATION: CWS changefileheader (1.12.28); FILE MERGED 2008/03/31 12:33:31 rt 1.12.28.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: opump.cxx,v $
 * $Revision: 1.13 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_io.hxx"

#include <stdio.h>

#include <osl/diagnose.h>

#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XActiveDataSink.hpp>
#include <com/sun/star/io/XActiveDataControl.hpp>
#include <com/sun/star/io/XConnectable.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/registry/XRegistryKey.hpp>

#include <uno/dispatcher.h>
#include <uno/mapping.hxx>
#include <cppuhelper/implbase5.hxx>
#include <cppuhelper/factory.hxx>
#include <cppuhelper/interfacecontainer.hxx>
#include <osl/mutex.hxx>
#include <osl/thread.h>

using namespace osl;
using namespace std;
using namespace rtl;
using namespace cppu;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;
using namespace com::sun::star::io;

#include "factreg.hxx"

namespace io_stm {

    class Pump : public WeakImplHelper5<
          XActiveDataSource, XActiveDataSink, XActiveDataControl, XConnectable, XServiceInfo >
    {
        Mutex                                   m_aMutex;
        oslThread                               m_aThread;

        Reference< XConnectable >               m_xPred;
        Reference< XConnectable >               m_xSucc;
        Reference< XInputStream >               m_xInput;
        Reference< XOutputStream >              m_xOutput;
        OInterfaceContainerHelper               m_cnt;
        sal_Bool                                m_closeFired;

        void run();
        static void static_run( void* pObject );

        void close();
        void fireClose();
        void fireStarted();
        void fireTerminated();
        void fireError( const Any &a );

    public:
        Pump();
        virtual ~Pump();

        // XActiveDataSource
        virtual void SAL_CALL setOutputStream( const Reference< ::com::sun::star::io::XOutputStream >& xOutput ) throw();
        virtual Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream() throw();

        // XActiveDataSink
        virtual void SAL_CALL setInputStream( const Reference< ::com::sun::star::io::XInputStream >& xStream ) throw();
        virtual Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream() throw();

        // XActiveDataControl
        virtual void SAL_CALL addListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
        virtual void SAL_CALL removeListener( const Reference< ::com::sun::star::io::XStreamListener >& xListener ) throw();
        virtual void SAL_CALL start() throw( RuntimeException );
        virtual void SAL_CALL terminate() throw();

        // XConnectable
        virtual void SAL_CALL setPredecessor( const Reference< ::com::sun::star::io::XConnectable >& xPred ) throw();
        virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getPredecessor() throw();
        virtual void SAL_CALL setSuccessor( const Reference< ::com::sun::star::io::XConnectable >& xSucc ) throw();
        virtual Reference< ::com::sun::star::io::XConnectable > SAL_CALL getSuccessor() throw();

    public: // XServiceInfo
        virtual OUString    SAL_CALL getImplementationName() throw(  );
        virtual Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw(  );
        virtual sal_Bool     SAL_CALL supportsService(const OUString& ServiceName) throw(  );
    };

Pump::Pump() : m_aThread( 0 ),
               m_cnt( m_aMutex ),
               m_closeFired( sal_False )
{
    g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
}

Pump::~Pump()
{
    // exit gracefully
    if( m_aThread )
    {
        osl_joinWithThread( m_aThread );
        osl_destroyThread( m_aThread );
    }
    g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
}

void Pump::fireError( const  Any & exception )
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->error( exception );
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::fireClose()
{
    sal_Bool bFire = sal_False;
    {
        MutexGuard guard( m_aMutex );
        if( ! m_closeFired  )
        {
            m_closeFired = sal_True;
            bFire = sal_True;
        }
    }

    if( bFire )
    {
        OInterfaceIteratorHelper iter( m_cnt );
        while( iter.hasMoreElements() )
        {
            try
            {
                static_cast< XStreamListener * > ( iter.next() )->closed( );
            }
            catch ( RuntimeException &e )
            {
                OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
                OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
            }
        }
    }
}

void Pump::fireStarted()
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->started( );
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::fireTerminated()
{
    OInterfaceIteratorHelper iter( m_cnt );
    while( iter.hasMoreElements() )
    {
        try
        {
            static_cast< XStreamListener * > ( iter.next() )->terminated();
        }
        catch ( RuntimeException &e )
        {
            OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
            OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception during calling listeners", sMessage.getStr() );
        }
    }
}

void Pump::close()
{
    // close streams and release references
    Reference< XInputStream > rInput;
    Reference< XOutputStream > rOutput;
    {
        MutexGuard guard( m_aMutex );
        rInput = m_xInput;
        m_xInput.clear();

        rOutput = m_xOutput;
        m_xOutput.clear();
        m_xSucc.clear();
        m_xPred.clear();
    }
    if( rInput.is() )
    {
        try
        {
            rInput->closeInput();
        }
        catch( Exception & )
        {
            // go down calm
        }
    }
    if( rOutput.is() )
    {
        try
        {
            rOutput->closeOutput();
        }
        catch( Exception & )
        {
            // go down calm
        }
    }
}

void Pump::static_run( void* pObject )
{
    ((Pump*)pObject)->run();
    ((Pump*)pObject)->release();
}

void Pump::run()
{
    try
    {
        fireStarted();
        try
        {
            Reference< XInputStream > rInput;
            Reference< XOutputStream > rOutput;
            {
                Guard< Mutex > aGuard( m_aMutex );
                rInput = m_xInput;
                rOutput = m_xOutput;
            }

            if( ! rInput.is() )
            {
                NotConnectedException exception(
                    OUString::createFromAscii( "no input stream set" ) , Reference<XInterface>((OWeakObject*)this) );
                throw exception;
            }
            Sequence< sal_Int8 > aData;
            while( rInput->readSomeBytes( aData, 65536 ) )
            {
                if( ! rOutput.is() )
                {
                    NotConnectedException exception(
                        OUString::createFromAscii( "no output stream set" ) , Reference<XInterface>( (OWeakObject*)this) );
                    throw exception;
                }
                rOutput->writeBytes( aData );
                osl_yieldThread();
            }
        }
        catch ( IOException & e )
        {
            fireError( makeAny( e ) );
        }
        catch ( RuntimeException & e )
        {
            fireError( makeAny( e ) );
        }
        catch ( Exception & e )
        {
            fireError( makeAny( e ) );
        }

        close();
        fireClose();
    }
    catch ( com::sun::star::uno::Exception &e )
    {
        // we are the last on the stack.
        // this is to avoid crashing the program, when e.g. a bridge crashes
        OString sMessage = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
        OSL_ENSURE( !"com.sun.star.comp.stoc.Pump: unexpected exception", sMessage.getStr() );
    }
}

// ------------------------------------------------------------

/*
 * XConnectable
 */

void Pump::setPredecessor( const Reference< XConnectable >& xPred ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xPred = xPred;
}

// ------------------------------------------------------------

Reference< XConnectable > Pump::getPredecessor() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xPred;
}

// ------------------------------------------------------------

void Pump::setSuccessor( const Reference< XConnectable >& xSucc ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xSucc = xSucc;
}

// ------------------------------------------------------------

Reference< XConnectable > Pump::getSuccessor() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xSucc;
}

// -----------------------------------------------------------------

/*
 * XActiveDataControl
 */

void Pump::addListener( const Reference< XStreamListener >& xListener ) throw()
{
    m_cnt.addInterface( xListener );
}

// ------------------------------------------------------------

void Pump::removeListener( const Reference< XStreamListener >& xListener ) throw()
{
    m_cnt.removeInterface( xListener );
}

// ------------------------------------------------------------

void Pump::start() throw( RuntimeException )
{
    Guard< Mutex > aGuard( m_aMutex );
    m_aThread = osl_createSuspendedThread((oslWorkerFunction)Pump::static_run,this);
    if( m_aThread )
    {
        // will be released by OPump::static_run
        acquire();
        osl_resumeThread( m_aThread );
    }
    else
    {
        throw RuntimeException(
            OUString( RTL_CONSTASCII_USTRINGPARAM( "Pump::start Couldn't create worker thread" )),
            *this);
    }
}

// ------------------------------------------------------------

void Pump::terminate() throw()
{
    close();

    // wait for the worker to die
    if( m_aThread )
        osl_joinWithThread( m_aThread );

    fireTerminated();
    fireClose();
}

// ------------------------------------------------------------

/*
 * XActiveDataSink
 */

void Pump::setInputStream( const Reference< XInputStream >& xStream ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xInput = xStream;
    Reference< XConnectable > xConnect( xStream, UNO_QUERY );
    if( xConnect.is() )
        xConnect->setSuccessor( this );
    // data transfer starts in XActiveDataControl::start
}

// ------------------------------------------------------------

Reference< XInputStream > Pump::getInputStream() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xInput;
}

// ------------------------------------------------------------

/*
 * XActiveDataSource
 */

void Pump::setOutputStream( const Reference< XOutputStream >& xOut ) throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    m_xOutput = xOut;
    Reference< XConnectable > xConnect( xOut, UNO_QUERY );
    if( xConnect.is() )
        xConnect->setPredecessor( this );
    // data transfer starts in XActiveDataControl::start
}

// ------------------------------------------------------------

Reference< XOutputStream > Pump::getOutputStream() throw()
{
    Guard< Mutex > aGuard( m_aMutex );
    return m_xOutput;
}

// XServiceInfo
OUString Pump::getImplementationName() throw(  )
{
    return OPumpImpl_getImplementationName();
}

// XServiceInfo
sal_Bool Pump::supportsService(const OUString& ServiceName) throw(  )
{
    Sequence< OUString > aSNL = getSupportedServiceNames();
    const OUString * pArray = aSNL.getConstArray();

    for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
        if( pArray[i] == ServiceName )
            return sal_True;

    return sal_False;
}

// XServiceInfo
Sequence< OUString > Pump::getSupportedServiceNames(void) throw(  )
{
    return OPumpImpl_getSupportedServiceNames();
}

Reference< XInterface > SAL_CALL OPumpImpl_CreateInstance( const Reference< XComponentContext > & ) throw (Exception)
{
    return Reference< XInterface >( *new Pump );
}

OUString OPumpImpl_getImplementationName()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.Pump") );
}

Sequence<OUString> OPumpImpl_getSupportedServiceNames(void)
{
    OUString s( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.Pump" ) );
    Sequence< OUString > seq( &s , 1 );
    return seq;
}

}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: semaphor.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 14:32:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _OSL_SEMAPHORE_HXX_
#define _OSL_SEMAPHORE_HXX_

#ifdef __cplusplus

#include <osl/semaphor.h>

namespace osl
{

    class Semaphore {

    public:

        /** Creates a semaphore.

            @param InitialCount denotes the starting value the semaphore. If you set it to
            zero, the first acquire() blocks. Otherwise InitialCount acquire()s  are
            immedeatly  successfull.
            @return 0 if the semaphore could not be created, otherwise a handle to the sem.
        */

        Semaphore(sal_uInt32 initialCount)
        {
            semaphore = osl_createSemaphore(initialCount);
        }

        /** Release the OS-structures and free semaphore data-structure
            @return fbbb
        */
        ~Semaphore()
        {
            osl_destroySemaphore(semaphore);
        }

        /** acquire() decreases the count. It will block if it tries to
            decrease below zero.
            @return False if the system-call failed.
        */
        sal_Bool acquire()
        {
            return osl_acquireSemaphore(semaphore);
        }

        /** tryToAcquire() tries to decreases the count. It will
            return with False if it would decrease the count below zero.
            (When acquire() would block.) If it could successfully
            decrease the count, it will return True.
        */
        sal_Bool tryToAcquire()
        {
            return osl_tryToAcquireSemaphore(semaphore);
        }

        /** release() increases the count.
            @return False if the system-call failed.
        */
        sal_Bool release()
        {
            return osl_releaseSemaphore(semaphore);
        }

    private:
        oslSemaphore semaphore;

        /** The underlying oslSemaphore has no reference count.

        Since the underlying oslSemaphore is not a reference counted object, copy
        constructed Semaphore may work on an already destructed oslSemaphore object.

        */
        Semaphore(const Semaphore&);

        /** The underlying oslSemaphore has no reference count.

        When destructed, the Semaphore object destroys the undelying oslSemaphore,
        which might cause severe problems in case it's a temporary object.

        */
        Semaphore(oslSemaphore Semaphore);

        /** This assignment operator is private for the same reason as
            the copy constructor.
        */
        Semaphore& operator= (const Semaphore&);

        /** This assignment operator is private for the same reason as
            the constructor taking a oslSemaphore argument.
        */
        Semaphore& operator= (oslSemaphore);
    };
}

#endif  /* __cplusplus */
#endif  /* _OSL_SEMAPHORE_HXX_  */
<commit_msg>INTEGRATION: CWS changefileheader (1.8.378); FILE MERGED 2008/03/31 13:23:36 rt 1.8.378.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: semaphor.hxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _OSL_SEMAPHORE_HXX_
#define _OSL_SEMAPHORE_HXX_

#ifdef __cplusplus

#include <osl/semaphor.h>

namespace osl
{

    class Semaphore {

    public:

        /** Creates a semaphore.

            @param InitialCount denotes the starting value the semaphore. If you set it to
            zero, the first acquire() blocks. Otherwise InitialCount acquire()s  are
            immedeatly  successfull.
            @return 0 if the semaphore could not be created, otherwise a handle to the sem.
        */

        Semaphore(sal_uInt32 initialCount)
        {
            semaphore = osl_createSemaphore(initialCount);
        }

        /** Release the OS-structures and free semaphore data-structure
            @return fbbb
        */
        ~Semaphore()
        {
            osl_destroySemaphore(semaphore);
        }

        /** acquire() decreases the count. It will block if it tries to
            decrease below zero.
            @return False if the system-call failed.
        */
        sal_Bool acquire()
        {
            return osl_acquireSemaphore(semaphore);
        }

        /** tryToAcquire() tries to decreases the count. It will
            return with False if it would decrease the count below zero.
            (When acquire() would block.) If it could successfully
            decrease the count, it will return True.
        */
        sal_Bool tryToAcquire()
        {
            return osl_tryToAcquireSemaphore(semaphore);
        }

        /** release() increases the count.
            @return False if the system-call failed.
        */
        sal_Bool release()
        {
            return osl_releaseSemaphore(semaphore);
        }

    private:
        oslSemaphore semaphore;

        /** The underlying oslSemaphore has no reference count.

        Since the underlying oslSemaphore is not a reference counted object, copy
        constructed Semaphore may work on an already destructed oslSemaphore object.

        */
        Semaphore(const Semaphore&);

        /** The underlying oslSemaphore has no reference count.

        When destructed, the Semaphore object destroys the undelying oslSemaphore,
        which might cause severe problems in case it's a temporary object.

        */
        Semaphore(oslSemaphore Semaphore);

        /** This assignment operator is private for the same reason as
            the copy constructor.
        */
        Semaphore& operator= (const Semaphore&);

        /** This assignment operator is private for the same reason as
            the constructor taking a oslSemaphore argument.
        */
        Semaphore& operator= (oslSemaphore);
    };
}

#endif  /* __cplusplus */
#endif  /* _OSL_SEMAPHORE_HXX_  */
<|endoftext|>


<commit_before>/*
 * msrSyncBlockCode.cpp
 *
 *  Created on: 26 mars 2013
 *      Author: dom
 */

#include <iostream>
#include <sstream>
#include <boost/asio.hpp>
#include "scheduler.h"
#include "network.h"
#include "msrSyncBlockCode.h"
#include "msrSyncMessages.h"
#include "msrSyncEvents.h"
#include "configStat.h"

#include "trace.h"

using namespace std;
using namespace BlinkyBlocks;

#define COLOR_CHANGE_PERIOD_USEC (2*1000*1000)
#define SIMULATION_DURATION_USEC (10*60*1000*1000)

#define SYNCHRONIZATION
#define SYNC_PERIOD (10*1000*1000)
#define COM_DELAY (6*1000)

#define LIMIT_NUM_ROUNDS 10

//#define PRINT_NODE_INFO
#define INFO_NODE_ID 2

msrSyncBlockCode::msrSyncBlockCode(BlinkyBlocksBlock *host): BlinkyBlocksBlockCode(host) {
  a = 1;
  b = 0;
  round = 0;

  OUTPUT << "msrSyncBlockCode constructor" << endl;
}

msrSyncBlockCode::~msrSyncBlockCode() {
  OUTPUT << "msrSyncBlockCode destructor" << endl;
}

void msrSyncBlockCode::init() {
  //BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;

  /*uint64_t time = 0;
    while (time<SIMULATION_DURATION_USEC) {
    uint64_t globalTime =  bb->getSchedulerTimeForLocalTime(time);
    Color c = getColor(time/COLOR_CHANGE_PERIOD_USEC);
    BlinkyBlocks::getScheduler()->schedule(new SetColorEvent(globalTime,bb,c));
    time += COLOR_CHANGE_PERIOD_USEC;
    }*/

#ifdef SYNCHRONIZATION
  if(hostBlock->blockId == 1) { // Time leader
    BlinkyBlocks::getScheduler()->schedule(new MsrSyncEvent(BaseSimulator::getScheduler()->now(),hostBlock));
  }
#endif
}

void msrSyncBlockCode::startup() {
  stringstream info;
  //BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;

  info << "  Starting msrSyncBlockCode in block " << hostBlock->blockId;
  BlinkyBlocks::getScheduler()->trace(info.str(),hostBlock->blockId);
  init();
}

void msrSyncBlockCode::processLocalEvent(EventPtr pev) {
  stringstream info;
  BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;
  info.str("");

  OUTPUT << bb->blockId << " processLocalEvent: date: "<< BaseSimulator::getScheduler()->now() << " process event " << pev->getEventName() << "(" << pev->eventType << ")" << ", random number : " << pev->randomNumber << endl;

  switch (pev->eventType) {
  case EVENT_SET_COLOR:
    {
      Color color = (boost::static_pointer_cast<SetColorEvent>(pev))->color;
      bb->setColor(color);
      info << "set color "<< color << endl;
    }
    break;
  case EVENT_MSRSYNC:
    {
      round++;
      info << "MASTER sync " << round;
#ifdef PRINT_NODE_INFO
      cout << "MASTER SYNC " << getTime() << endl;
#endif
      synchronize(NULL,getTime());
      // schedule the next sync round
      if (round < LIMIT_NUM_ROUNDS) {
	uint64_t nextSync = hostBlock->getSchedulerTimeForLocalTime(hostBlock->getTime()+SYNC_PERIOD);
	//cout << nextSync << " " << BaseSimulator::getScheduler()->now() << endl;
	// or based on global time now ? BaseSimulator::getScheduler()->now()+SYNC_PERIOD
	BlinkyBlocks::getScheduler()->schedule(new MsrSyncEvent(nextSync,hostBlock));
      }
    }
    break;
  case EVENT_NI_RECEIVE:
    {
      MessagePtr message = (boost::static_pointer_cast<NetworkInterfaceReceiveEvent>(pev))->message;
      P2PNetworkInterface * recvInterface = message->destinationInterface;
      switch(message->type) {
      case SYNC_MSG_ID : {
	SyncMessagePtr recvMessage = boost::static_pointer_cast<SyncMessage>(message);
	info << "sync msg " << recvMessage->getRound();
	//cout << "@" << hostBlock->blockId << ": " << getTime() << "/" << globalTime << endl;
	if (recvMessage->getRound() > round) {
	  round = recvMessage->getRound();
	  uint64_t globalTime = recvMessage->getTime() + COM_DELAY;
	  uint64_t localTime = hostBlock->getTime();
	  // window of 5 last measures
	  syncPoints.push_back(make_pair(localTime,globalTime));
#ifdef PRINT_NODE_INFO
	  if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "Reception time: " << BaseSimulator::getScheduler()->now()/1000 << endl;
	    cout << "a: " << a << endl;
	    cout << "estimation: " << getTime()/1000 << "(" << hostBlock->getTime()/1000 << ")" << ", reception: " << recvMessage->getTime()/1000 << ", => " << globalTime/1000 << endl;
	  }
#endif
	  error.push_back(abs(((double)getTime()-(double)globalTime)/1000));
	  if (syncPoints.size() > 5) {
	    syncPoints.erase(syncPoints.begin());
	  }
	  adjust();
#ifdef PRINT_NODE_INFO
	  if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "@" << hostBlock->blockId << " a: " << a << endl;
	  }
#endif
	  synchronize(recvInterface, globalTime);
	}

	if (round == LIMIT_NUM_ROUNDS) {
	  // display error vector
#ifdef PRINT_NODE_INFO
	  if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "@" << hostBlock->blockId << " error: ";
	    for (vector<uint64_t>::iterator it = error.begin() ; it != error.end(); it++){
	      cout << *it << " ";
	    }
	    cout << endl;
	  }
#endif
	}
      }
	break;
      default:
	ERRPUT << "*** ERROR *** : unknown message" << message->id << endl;
      }
    }
    break;
  default:
    ERRPUT << "*** ERROR *** : unknown local event" << endl;
    break;
  }

  if (info.str() != "") {
    BlinkyBlocks::getScheduler()->trace(info.str(),hostBlock->blockId);
  }
}

Color msrSyncBlockCode::getColor(uint64_t time) {
  Color colors[6] = {RED,GREEN,YELLOW,BLUE,GREY,PINK};
  int c = time%6;
  return colors[c];
}

uint64_t msrSyncBlockCode::getTime() {
  return a*(double)hostBlock->getTime() + b;
}

void msrSyncBlockCode::synchronize(P2PNetworkInterface *exception, uint64_t globalTime) {
  list <P2PNetworkInterface*>::iterator it;
  for (it = hostBlock->getP2PNetworkInterfaceList().begin(); it !=hostBlock->getP2PNetworkInterfaceList().end(); it++) {
    if ((*it)->connectedInterface && (*it != exception)) {
      SyncMessage *message = new SyncMessage(globalTime,round);
      BaseSimulator::getScheduler()->schedule(new NetworkInterfaceEnqueueOutgoingEvent(BaseSimulator::getScheduler()->now(), message,*it));
    }
  }
}

void msrSyncBlockCode::adjust() {
  // Linear regression (same as in hardware bb)
  // https://github.com/claytronics/oldbb/blob/master/build/src-bobby/system/clock.bb
  // x: local time
  // y: global time
  double xAvg = 0, yAvg = 0;
  double sum1 = 0, sum2 = 0;

  if (syncPoints.size() == 0) {
    a = 1;
    return;
  }

  if (syncPoints.size() == 1) {
    if (syncPoints.begin()->first != 0) {
      a = syncPoints.begin()->second / syncPoints.begin()->first;
    } else {
      a = 1;
    }
    //A = 1;
    return;
  }

  for (vector<pair<uint64_t,uint64_t> >::iterator it = syncPoints.begin() ; it != syncPoints.end(); it++){
    xAvg += it->first;
    yAvg += it->second;
  }

  xAvg = xAvg/syncPoints.size();
  yAvg = yAvg/syncPoints.size();
  for (vector<pair<uint64_t,uint64_t> >::iterator it = syncPoints.begin() ; it != syncPoints.end(); it++){
    sum1 += (it->first - xAvg) * (it->second - yAvg);
    sum2 += pow(it->first - xAvg,2);
  }

  a = sum1/sum2;
  // b ?
}

BlinkyBlocks::BlinkyBlocksBlockCode* msrSyncBlockCode::buildNewBlockCode(BlinkyBlocksBlock *host) {
  return(new msrSyncBlockCode(host));
}
<commit_msg>study noise impact on clock synchronization<commit_after>/*
 * msrSyncBlockCode.cpp
 *
 *  Created on: 26 mars 2013
 *      Author: dom
 */

#include <iostream>
#include <sstream>
#include <boost/asio.hpp>
#include "scheduler.h"
#include "network.h"
#include "msrSyncBlockCode.h"
#include "msrSyncMessages.h"
#include "msrSyncEvents.h"
#include "configStat.h"

#include "trace.h"

using namespace std;
using namespace BlinkyBlocks;

#define COLOR_CHANGE_PERIOD_USEC (2*1000*1000)
#define SIMULATION_DURATION_USEC (10*60*1000*1000)

#define SYNCHRONIZATION
#define SYNC_PERIOD (10*1000*1000)
#define COM_DELAY (6*1000)

#define LIMIT_NUM_ROUNDS 10

#define PRINT_NODE_INFO
#define INFO_NODE_ID 200

msrSyncBlockCode::msrSyncBlockCode(BlinkyBlocksBlock *host): BlinkyBlocksBlockCode(host) {
  a = 1;
  b = 0;
  round = 0;

  OUTPUT << "msrSyncBlockCode constructor" << endl;
}

msrSyncBlockCode::~msrSyncBlockCode() {
  OUTPUT << "msrSyncBlockCode destructor" << endl;
}

void msrSyncBlockCode::init() {
  //BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;

  /*uint64_t time = 0;
    while (time<SIMULATION_DURATION_USEC) {
    uint64_t globalTime =  bb->getSchedulerTimeForLocalTime(time);
    Color c = getColor(time/COLOR_CHANGE_PERIOD_USEC);
    BlinkyBlocks::getScheduler()->schedule(new SetColorEvent(globalTime,bb,c));
    time += COLOR_CHANGE_PERIOD_USEC;
    }*/

#ifdef SYNCHRONIZATION
  if(hostBlock->blockId == 1) { // Time leader
    BlinkyBlocks::getScheduler()->schedule(new MsrSyncEvent(BaseSimulator::getScheduler()->now(),hostBlock));
  }
#endif
}

void msrSyncBlockCode::startup() {
  stringstream info;
  //BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;

  info << "  Starting msrSyncBlockCode in block " << hostBlock->blockId;
  BlinkyBlocks::getScheduler()->trace(info.str(),hostBlock->blockId);
  init();
}

void msrSyncBlockCode::processLocalEvent(EventPtr pev) {
  stringstream info;
  BlinkyBlocksBlock *bb = (BlinkyBlocksBlock*) hostBlock;
  info.str("");

  OUTPUT << bb->blockId << " processLocalEvent: date: "<< BaseSimulator::getScheduler()->now() << " process event " << pev->getEventName() << "(" << pev->eventType << ")" << ", random number : " << pev->randomNumber << endl;

  switch (pev->eventType) {
  case EVENT_SET_COLOR:
    {
      Color color = (boost::static_pointer_cast<SetColorEvent>(pev))->color;
      bb->setColor(color);
      info << "set color "<< color << endl;
    }
    break;
  case EVENT_MSRSYNC:
    {
      round++;
      info << "MASTER sync " << round;
#ifdef PRINT_NODE_INFO
      // cout << "MASTER SYNC " << getTime() << endl;
#endif
      synchronize(NULL,getTime());
      // schedule the next sync round
      if (round < LIMIT_NUM_ROUNDS) {
	uint64_t nextSync = hostBlock->getSchedulerTimeForLocalTime(hostBlock->getTime()+SYNC_PERIOD);
	//cout << nextSync << " " << BaseSimulator::getScheduler()->now() << endl;
	// or based on global time now ? BaseSimulator::getScheduler()->now()+SYNC_PERIOD
	BlinkyBlocks::getScheduler()->schedule(new MsrSyncEvent(nextSync,hostBlock));
      }
    }
    break;
  case EVENT_NI_RECEIVE:
    {
      MessagePtr message = (boost::static_pointer_cast<NetworkInterfaceReceiveEvent>(pev))->message;
      P2PNetworkInterface * recvInterface = message->destinationInterface;
      switch(message->type) {
      case SYNC_MSG_ID : {
	SyncMessagePtr recvMessage = boost::static_pointer_cast<SyncMessage>(message);
	info << "sync msg " << recvMessage->getRound();
	//cout << "@" << hostBlock->blockId << ": " << getTime() << "/" << globalTime << endl;
	if (recvMessage->getRound() > round) {
	  round = recvMessage->getRound();
	  uint64_t globalTime = recvMessage->getTime() + COM_DELAY;
	  uint64_t localTime = hostBlock->getTime();
	  // window of 5 last measures
	  syncPoints.push_back(make_pair(localTime,globalTime));
#ifdef PRINT_NODE_INFO
	  if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "Reception time: " << BaseSimulator::getScheduler()->now()/1000 << endl;
	    cout << "a: " << a << endl;
	    cout << "estimation: " << getTime()/1000 << "(" << hostBlock->getTime()/1000 << ")" << ", reception: " << recvMessage->getTime()/1000 << ", => " << globalTime/1000 << endl;
	  }
#endif
	  error.push_back(abs(((double)getTime()-(double)globalTime)/1000));
	  if (syncPoints.size() > 5) {
	    syncPoints.erase(syncPoints.begin());
	  }
	  adjust();
#ifdef PRINT_NODE_INFO
	  if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "@" << hostBlock->blockId << " a: " << a << endl;
	  }
#endif
	  synchronize(recvInterface, globalTime);

	  if (round == LIMIT_NUM_ROUNDS) {
	    // display error vector
#ifdef PRINT_NODE_INFO
	    // if (hostBlock->blockId == INFO_NODE_ID) {
	    cout << "@" << hostBlock->blockId << " error: ";
	    for (vector<uint64_t>::iterator it = error.begin() ; it != error.end(); it++){
	      cout << *it << " ";
	    }
	    cout << endl;
	    // }
#endif
	  }
	}
      }
	break;
      default:
	ERRPUT << "*** ERROR *** : unknown message" << message->id << endl;
      }
    }
    break;
  default:
    ERRPUT << "*** ERROR *** : unknown local event" << endl;
    break;
  }

  if (info.str() != "") {
    BlinkyBlocks::getScheduler()->trace(info.str(),hostBlock->blockId);
  }
}

Color msrSyncBlockCode::getColor(uint64_t time) {
  Color colors[6] = {RED,GREEN,YELLOW,BLUE,GREY,PINK};
  int c = time%6;
  return colors[c];
}

uint64_t msrSyncBlockCode::getTime() {
  return a*(double)hostBlock->getTime() + b;
}

void msrSyncBlockCode::synchronize(P2PNetworkInterface *exception, uint64_t globalTime) {
  list <P2PNetworkInterface*>::iterator it;
  for (it = hostBlock->getP2PNetworkInterfaceList().begin(); it !=hostBlock->getP2PNetworkInterfaceList().end(); it++) {
    if ((*it)->connectedInterface && (*it != exception)) {
      SyncMessage *message = new SyncMessage(globalTime,round);
      BaseSimulator::getScheduler()->schedule(new NetworkInterfaceEnqueueOutgoingEvent(BaseSimulator::getScheduler()->now(), message,*it));
    }
  }
}

void msrSyncBlockCode::adjust() {
  // Linear regression (same as in hardware bb)
  // https://github.com/claytronics/oldbb/blob/master/build/src-bobby/system/clock.bb
  // x: local time
  // y: global time
  double xAvg = 0, yAvg = 0;
  double sum1 = 0, sum2 = 0;

  if (syncPoints.size() == 0) {
    a = 1;
    return;
  }

  if (syncPoints.size() == 1) {
    if (syncPoints.begin()->first != 0) {
      a = syncPoints.begin()->second / syncPoints.begin()->first;
    } else {
      a = 1;
    }
    //A = 1;
    return;
  }

  for (vector<pair<uint64_t,uint64_t> >::iterator it = syncPoints.begin() ; it != syncPoints.end(); it++){
    xAvg += it->first;
    yAvg += it->second;
  }

  xAvg = xAvg/syncPoints.size();
  yAvg = yAvg/syncPoints.size();
  for (vector<pair<uint64_t,uint64_t> >::iterator it = syncPoints.begin() ; it != syncPoints.end(); it++){
    sum1 += (it->first - xAvg) * (it->second - yAvg);
    sum2 += pow(it->first - xAvg,2);
  }

  a = sum1/sum2;
  // b ?
}

BlinkyBlocks::BlinkyBlocksBlockCode* msrSyncBlockCode::buildNewBlockCode(BlinkyBlocksBlock *host) {
  return(new msrSyncBlockCode(host));
}
<|endoftext|>