<commit_before>#include <rtt/os/main.h>

#include <rtt/typekit/RealTimeTypekit.hpp>
<% deployer.rtt_transports.each do |transport_name| %>
#include <rtt/transports/<%= transport_name %>/TransportPlugin.hpp>
<% end %>

<% if component.typekit || !component.used_typekits.empty? %>#include <rtt/types/TypekitPlugin.hpp><% end %>
<% if typekit = component.typekit %>
#include "typekit/Plugin.hpp"
<% deployer.transports.each do |transport_name| %>
#include "typekit/transports/<%= transport_name %>/TransportPlugin.hpp"
<% end %>
<% end %>
<% deployer.used_typekits.each do |tk| %>
#include <<%= tk.name %>/typekit/Plugin.hpp>
    <% deployer.transports.each do |transport_name| %>
#include <<%= tk.name %>/transports/<%= transport_name %>/TransportPlugin.hpp>
    <% end %>
<% end %>

<% task_activities = deployer.task_activities.
        sort_by(&:name) %>

<% task_activities.each do |task| %>
#include <<%= task.context.header_file %>>
<% end %>
<% if deployer.corba_enabled? %>
#include <rtt/transports/corba/ApplicationServer.hpp>
#include <rtt/transports/corba/TaskContextServer.hpp>
<% end %>

<% require 'set'
    activity_headers = task_activities.
        map { |t| t.activity_type.header }.
        compact.
        to_set %>
<% activity_headers.to_a.sort.each do |header| %>
#include <<%= header %>>
<% end %>

<% if deployer.browse %>
#include <ocl/TaskBrowser.hpp>
<% end %>

#include <rtt/Logger.hpp>
#include <rtt/base/ActivityInterface.hpp>
class Deinitializer
{
    friend Deinitializer& operator << (Deinitializer&, RTT::base::ActivityInterface&);

    std::vector<RTT::base::ActivityInterface*> m_activities;

public:
    ~Deinitializer()
    {
        for (std::vector<RTT::base::ActivityInterface*>::const_iterator it = m_activities.begin();
                it != m_activities.end(); ++it)
        {
            (*it)->stop();
        }
    }
};

Deinitializer& operator << (Deinitializer& deinit, RTT::base::ActivityInterface& activity)
{
    deinit.m_activities.push_back(&activity);
    return deinit;
}

using namespace RTT;
int ORO_main(int argc, char* argv[])
{
   <% if deployer.loglevel %>
   if ( log().getLogLevel() < Logger::<%= deployer.loglevel %> ) {
       log().setLogLevel( Logger::<%= deployer.loglevel %> );
   }
   <% end %>

   RTT::types::TypekitRepository::Import( new RTT::types::RealTimeTypekitPlugin );
   <% if deployer.transports.include?('corba') %>
   RTT::types::TypekitRepository::Import( new RTT::corba::CorbaLibPlugin );
   <% end %>

   <% if component.typekit %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %>TypekitPlugin );
   <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %><%= transport_name.capitalize %>TransportPlugin );
   <% end %>
   <% end %>
   <% deployer.used_typekits.each do |tk| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %>TypekitPlugin );
       <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %><%= transport_name.capitalize %>TransportPlugin );
       <% end %>
   <% end %>

<% if deployer.corba_enabled? %>
    RTT::corba::ApplicationServer::InitOrb(argc, argv);
<% end %>

<% task_activities.each do |task| %>
    <%= task.context.class_name %> task_<%= task.name%>("<%= task.name %>");
    <% if task.activity_type %>
    <%= task.activity_type.class_name %>* activity_<%= task.name%> = new <%= task.activity_type.class_name %>(
            <%= task.rtt_scheduler %>,
            <%= task.rtt_priority %>,
            <% if task.period %><%= task.period %>, <% end %>
            task_<%= task.name%>.engine());
    task_<%= task.name %>.setActivity(activity_<%= task.name %>);
    <% if task.period %>
    RTT::os::Thread* thread_<%= task.name %> =
        dynamic_cast<RTT::os::Thread*>(activity_<%= task.name %>->thread());
    thread_<%= task.name %>->setMaxOverrun(<%= task.max_overruns %>);
    <% end %>
    <% else %>
    RTT::base::ActivityInterface* activity_<%= task.name %> = task_<%= task.name %>.getActivity().get();
    <% end # activity_type %>
    <% task.properties.sort_by { |prop| prop.name }.each do |prop|
        if prop.value %>
    task_<%= task.name %>.properties()->getProperty<<%= prop.interface_object.type.cxx_name %>>("<%= prop.name %>")->set(<%= prop.value.inspect %>);
        <% end %>
    <% end %>

    <% if deployer.corba_enabled? %>
    RTT::corba::TaskContextServer::Create( &task_<%= task.name%> );
    <% end %>
<% end %>

<% if !deployer.loggers.empty?
        deployer.loggers.sort_by { |filename, _| filename }.each do |filename, logger|
            logger.config.each do |type, reported_activity, args| %>
                task_<%= logger.task.name %>.connectPeers(&task_<%= reported_activity.name %>);
                task_<%= logger.task.name %>.report<%= type %>(<%= args.map { |v| "\"#{v}\"" }.join(", ") %>);
            <% end %>
        <% end %>
<% end %>

   Deinitializer deinit;

    // Start some activities
<% task_activities.each do |task| %>
    deinit << *activity_<%= task.name%>;

    <% if task.start?
        if task.context.needs_configuration? %>
    if (!task_<%= task.name %>.configure())
    {
        log(Error) << "cannot configure <%= task.name %>" << endlog();
        return -1;
    }
        <% end %>
    if (!task_<%= task.name %>.start())
    {
        log(Error) << "cannot start <%= task.name %>" << endlog();
        return -1;
    }
    <% end %>
<% end %>

<% deployer.peers.sort_by { |a, b| [a.name, b.name] }.each do |a, b| %>
    task_<%= a.name %>.connectPeers(&task_<%= b.name %>);
<% end %>

<% deployer.connections.
    sort_by { |src, dst, policy| [src.name, dst.name] }.
    each do |src, dst, policy|
        if src.kind_of?(TaskDeployment) %>
            task_<%= src.activity.name %>.connectPorts(&task_<%= dst.activity.name %>);
        <% else %>
        {
            <%= policy.to_code("policy") %>
            base::OutputPortInterface* src = dynamic_cast<base::OutputPortInterface*>(
                    task_<%= src.activity.name %>.ports()->getPort("<%= src.name %>"));
            base::InputPortInterface* dst = dynamic_cast<base::InputPortInterface*>(
                    task_<%= dst.activity.name %>.ports()->getPort("<%= dst.name %>"));
            src->createConnection(*dst, policy);
        }
        <% end %>
    <% end %>

<% if deployer.corba_enabled? %>
    RTT::corba::TaskContextServer::RunOrb();
<% elsif deployer.browse %>
    OCL::TaskBrowser browser(& task_<%= deployer.browse.name %>);
    browser.loop();
<% end %>

    return 0;
}

<commit_msg>until we get a corba service on the task contexts, call shutdownorb on SIGINT<commit_after>#include <rtt/os/main.h>

#include <rtt/typekit/RealTimeTypekit.hpp>
<% deployer.rtt_transports.each do |transport_name| %>
#include <rtt/transports/<%= transport_name %>/TransportPlugin.hpp>
<% end %>

<% if component.typekit || !component.used_typekits.empty? %>#include <rtt/types/TypekitPlugin.hpp><% end %>
<% if typekit = component.typekit %>
#include "typekit/Plugin.hpp"
<% deployer.transports.each do |transport_name| %>
#include "typekit/transports/<%= transport_name %>/TransportPlugin.hpp"
<% end %>
<% end %>
<% deployer.used_typekits.each do |tk| %>
#include <<%= tk.name %>/typekit/Plugin.hpp>
    <% deployer.transports.each do |transport_name| %>
#include <<%= tk.name %>/transports/<%= transport_name %>/TransportPlugin.hpp>
    <% end %>
<% end %>

<% task_activities = deployer.task_activities.
        sort_by(&:name) %>

<% task_activities.each do |task| %>
#include <<%= task.context.header_file %>>
<% end %>
<% if deployer.corba_enabled? %>
#include <rtt/transports/corba/ApplicationServer.hpp>
#include <rtt/transports/corba/TaskContextServer.hpp>
#include <signal.h>
<% end %>

<% require 'set'
    activity_headers = task_activities.
        map { |t| t.activity_type.header }.
        compact.
        to_set %>
<% activity_headers.to_a.sort.each do |header| %>
#include <<%= header %>>
<% end %>

<% if deployer.browse %>
#include <ocl/TaskBrowser.hpp>
<% end %>

#include <rtt/Logger.hpp>
#include <rtt/base/ActivityInterface.hpp>
class Deinitializer
{
    friend Deinitializer& operator << (Deinitializer&, RTT::base::ActivityInterface&);

    std::vector<RTT::base::ActivityInterface*> m_activities;

public:
    ~Deinitializer()
    {
        for (std::vector<RTT::base::ActivityInterface*>::const_iterator it = m_activities.begin();
                it != m_activities.end(); ++it)
        {
            (*it)->stop();
        }
    }
};

Deinitializer& operator << (Deinitializer& deinit, RTT::base::ActivityInterface& activity)
{
    deinit.m_activities.push_back(&activity);
    return deinit;
}

void sigint_quit_orb(int)
{
    RTT::corba::TaskContextServer::ShutdownOrb(false);
}

using namespace RTT;
int ORO_main(int argc, char* argv[])
{
   <% if deployer.loglevel %>
   if ( log().getLogLevel() < Logger::<%= deployer.loglevel %> ) {
       log().setLogLevel( Logger::<%= deployer.loglevel %> );
   }
   <% end %>

   RTT::types::TypekitRepository::Import( new RTT::types::RealTimeTypekitPlugin );
   <% if deployer.transports.include?('corba') %>
   RTT::types::TypekitRepository::Import( new RTT::corba::CorbaLibPlugin );
   <% end %>

   <% if component.typekit %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %>TypekitPlugin );
   <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= component.name %><%= transport_name.capitalize %>TransportPlugin );
   <% end %>
   <% end %>
   <% deployer.used_typekits.each do |tk| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %>TypekitPlugin );
       <% deployer.transports.each do |transport_name| %>
   RTT::types::TypekitRepository::Import( new orogen_typekits::<%= tk.name %><%= transport_name.capitalize %>TransportPlugin );
       <% end %>
   <% end %>

<% if deployer.corba_enabled? %>
    RTT::corba::ApplicationServer::InitOrb(argc, argv);
<% end %>

<% task_activities.each do |task| %>
    <%= task.context.class_name %> task_<%= task.name%>("<%= task.name %>");
    <% if task.activity_type %>
    <%= task.activity_type.class_name %>* activity_<%= task.name%> = new <%= task.activity_type.class_name %>(
            <%= task.rtt_scheduler %>,
            <%= task.rtt_priority %>,
            <% if task.period %><%= task.period %>, <% end %>
            task_<%= task.name%>.engine());
    task_<%= task.name %>.setActivity(activity_<%= task.name %>);
    <% if task.period %>
    RTT::os::Thread* thread_<%= task.name %> =
        dynamic_cast<RTT::os::Thread*>(activity_<%= task.name %>->thread());
    thread_<%= task.name %>->setMaxOverrun(<%= task.max_overruns %>);
    <% end %>
    <% else %>
    RTT::base::ActivityInterface* activity_<%= task.name %> = task_<%= task.name %>.getActivity().get();
    <% end # activity_type %>
    <% task.properties.sort_by { |prop| prop.name }.each do |prop|
        if prop.value %>
    task_<%= task.name %>.properties()->getProperty<<%= prop.interface_object.type.cxx_name %>>("<%= prop.name %>")->set(<%= prop.value.inspect %>);
        <% end %>
    <% end %>

    <% if deployer.corba_enabled? %>
    RTT::corba::TaskContextServer::Create( &task_<%= task.name%> );
    <% end %>
<% end %>

<% if !deployer.loggers.empty?
        deployer.loggers.sort_by { |filename, _| filename }.each do |filename, logger|
            logger.config.each do |type, reported_activity, args| %>
                task_<%= logger.task.name %>.connectPeers(&task_<%= reported_activity.name %>);
                task_<%= logger.task.name %>.report<%= type %>(<%= args.map { |v| "\"#{v}\"" }.join(", ") %>);
            <% end %>
        <% end %>
<% end %>

   Deinitializer deinit;

    // Start some activities
<% task_activities.each do |task| %>
    deinit << *activity_<%= task.name%>;

    <% if task.start?
        if task.context.needs_configuration? %>
    if (!task_<%= task.name %>.configure())
    {
        log(Error) << "cannot configure <%= task.name %>" << endlog();
        return -1;
    }
        <% end %>
    if (!task_<%= task.name %>.start())
    {
        log(Error) << "cannot start <%= task.name %>" << endlog();
        return -1;
    }
    <% end %>
<% end %>

<% deployer.peers.sort_by { |a, b| [a.name, b.name] }.each do |a, b| %>
    task_<%= a.name %>.connectPeers(&task_<%= b.name %>);
<% end %>

<% deployer.connections.
    sort_by { |src, dst, policy| [src.name, dst.name] }.
    each do |src, dst, policy|
        if src.kind_of?(TaskDeployment) %>
            task_<%= src.activity.name %>.connectPorts(&task_<%= dst.activity.name %>);
        <% else %>
        {
            <%= policy.to_code("policy") %>
            base::OutputPortInterface* src = dynamic_cast<base::OutputPortInterface*>(
                    task_<%= src.activity.name %>.ports()->getPort("<%= src.name %>"));
            base::InputPortInterface* dst = dynamic_cast<base::InputPortInterface*>(
                    task_<%= dst.activity.name %>.ports()->getPort("<%= dst.name %>"));
            src->createConnection(*dst, policy);
        }
        <% end %>
    <% end %>

<% if deployer.corba_enabled? %>
    struct sigaction sigint_handler;
    sigint_handler.sa_handler = &sigint_quit_orb;
    sigemptyset(&sigint_handler.sa_mask);
    sigint_handler.sa_flags     = 0;
    sigint_handler.sa_restorer  = 0;
    if (-1 == sigaction(SIGINT, &sigint_handler, 0))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    sigset_t unblock_sigint;
    sigemptyset(&unblock_sigint);
    sigaddset(&unblock_sigint, SIGINT);
    if (-1 == sigprocmask(SIG_UNBLOCK, &unblock_sigint, NULL))
    {
        std::cerr << "failed to install SIGINT handler" << std::endl;
        return 1;
    }
    RTT::corba::TaskContextServer::RunOrb();
<% elsif deployer.browse %>
    OCL::TaskBrowser browser(& task_<%= deployer.browse.name %>);
    browser.loop();
<% end %>

    return 0;
}

<|endoftext|>


<commit_before><commit_msg>update to new lircd socket location for lircd >= 0.8.6 BUG: 209100<commit_after><|endoftext|>


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

#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_constants.h"
#include "ipc/ipc_platform_file.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/file_path.h"
#include "ppapi/shared_impl/file_type_conversion.h"

namespace content {

namespace {

bool CanRead(int process_id, const base::FilePath& path) {
  return ChildProcessSecurityPolicyImpl::GetInstance()->
      CanReadFile(process_id, path);
}

bool CanCreateReadWrite(int process_id, const base::FilePath& path) {
  return ChildProcessSecurityPolicyImpl::GetInstance()->
      CanCreateReadWriteFile(process_id, path);
}

}  // namespace

PepperFlashFileMessageFilter::PepperFlashFileMessageFilter(
    PP_Instance instance,
    BrowserPpapiHost* host)
    : plugin_process_handle_(host->GetPluginProcessHandle()) {
  int unused;
  host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused);
  base::FilePath profile_data_directory = host->GetProfileDataDirectory();
  std::string plugin_name = host->GetPluginName();

  if (profile_data_directory.empty() || plugin_name.empty()) {
    // These are used to construct the path. If they are not set it means we
    // will construct a bad path and could provide access to the wrong files.
    // In this case, |plugin_data_directory_| will remain unset and
    // |ValidateAndConvertPepperFilePath| will fail.
    NOTREACHED();
  } else {
    plugin_data_directory_ = GetDataDirName(profile_data_directory).Append(
        base::FilePath::FromUTF8Unsafe(plugin_name));
  }
}

PepperFlashFileMessageFilter::~PepperFlashFileMessageFilter() {
}

// static
base::FilePath PepperFlashFileMessageFilter::GetDataDirName(
    const base::FilePath& profile_path) {
  return profile_path.Append(kPepperDataDirname);
}

scoped_refptr<base::TaskRunner>
PepperFlashFileMessageFilter::OverrideTaskRunnerForMessage(
    const IPC::Message& msg) {
  // The blocking pool provides a pool of threads to run file
  // operations, instead of a single thread which might require
  // queuing time.  Since these messages are synchronous as sent from
  // the plugin, the sending thread cannot send a new message until
  // this one returns, so there is no need to sequence tasks here.  If
  // the plugin has multiple threads, it cannot make assumptions about
  // ordering of IPC message sends, so it cannot make assumptions
  // about ordering of operations caused by those IPC messages.
  return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool());
}

int32_t PepperFlashFileMessageFilter::OnResourceMessageReceived(
   const IPC::Message& msg,
   ppapi::host::HostMessageContext* context) {
  IPC_BEGIN_MESSAGE_MAP(PepperFlashFileMessageFilter, msg)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile,
                                      OnOpenFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile,
                                      OnRenameFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir,
                                      OnDeleteFileOrDir)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir,
                                      OnCreateDir)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile,
                                      OnQueryFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents,
                                      OnGetDirContents)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
        PpapiHostMsg_FlashFile_CreateTemporaryFile,
        OnCreateTemporaryFile)
  IPC_END_MESSAGE_MAP()
  return PP_ERROR_FAILED;
}

int32_t PepperFlashFileMessageFilter::OnOpenFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path,
    int pp_open_flags) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path,
      base::Bind(&CanOpenWithPepperFlags, pp_open_flags));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  int platform_file_flags = 0;
  if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(
          pp_open_flags, &platform_file_flags)) {
    return base::File::FILE_ERROR_FAILED;
  }

  // TODO(rvargas): Convert this code to base::File.
  base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
  base::PlatformFile file_handle = base::CreatePlatformFile(
      full_path, platform_file_flags, NULL, &error);
  if (error != base::PLATFORM_FILE_OK) {
    DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
    return ppapi::FileErrorToPepperError(static_cast<base::File::Error>(error));
  }

  // Make sure we didn't try to open a directory: directory fd shouldn't be
  // passed to untrusted processes because they open security holes.
  base::PlatformFileInfo info;
  if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) {
    // When in doubt, throw it out.
    base::ClosePlatformFile(file_handle);
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
      plugin_process_handle_, true);
  ppapi::host::ReplyMessageContext reply_context =
      context->MakeReplyMessageContext();
  reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
      ppapi::proxy::SerializedHandle::FILE, file));
  SendReply(reply_context, IPC::Message());
  return PP_OK_COMPLETIONPENDING;
}

int32_t PepperFlashFileMessageFilter::OnRenameFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& from_path,
    const ppapi::PepperFilePath& to_path) {
  base::FilePath from_full_path = ValidateAndConvertPepperFilePath(
      from_path, base::Bind(&CanCreateReadWrite));
  base::FilePath to_full_path = ValidateAndConvertPepperFilePath(
      to_path, base::Bind(&CanCreateReadWrite));
  if (from_full_path.empty() || to_full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::Move(from_full_path, to_full_path);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnDeleteFileOrDir(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path,
    bool recursive) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanCreateReadWrite));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::DeleteFile(full_path, recursive);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}
int32_t PepperFlashFileMessageFilter::OnCreateDir(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanCreateReadWrite));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::CreateDirectory(full_path);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnQueryFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanRead));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  base::File::Info info;
  bool result = base::GetFileInfo(full_path, &info);
  context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnGetDirContents(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanRead));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  ppapi::DirContents contents;
  base::FileEnumerator enumerator(full_path, false,
      base::FileEnumerator::FILES |
      base::FileEnumerator::DIRECTORIES |
      base::FileEnumerator::INCLUDE_DOT_DOT);

  while (!enumerator.Next().empty()) {
    base::FileEnumerator::FileInfo info = enumerator.GetInfo();
    ppapi::DirEntry entry = {
      info.GetName(),
      info.IsDirectory()
    };
    contents.push_back(entry);
  }

  context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents);
  return PP_OK;
}

int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile(
    ppapi::host::HostMessageContext* context) {
  ppapi::PepperFilePath dir_path(
      ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, base::FilePath());
  base::FilePath validated_dir_path = ValidateAndConvertPepperFilePath(
      dir_path, base::Bind(&CanCreateReadWrite));
  if (validated_dir_path.empty() ||
      (!base::DirectoryExists(validated_dir_path) &&
       !base::CreateDirectory(validated_dir_path))) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  base::FilePath file_path;
  if (!base::CreateTemporaryFileInDir(validated_dir_path, &file_path)) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_FAILED);
  }

  // TODO(rvargas): Convert this code to base::File.
  base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
  base::PlatformFile file_handle = base::CreatePlatformFile(
      file_path,
      base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ |
      base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY |
      base::PLATFORM_FILE_DELETE_ON_CLOSE, NULL, &error);

  if (error != base::PLATFORM_FILE_OK) {
    DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
    return ppapi::FileErrorToPepperError(static_cast<base::File::Error>(error));
  }

  IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
      plugin_process_handle_, true);
  ppapi::host::ReplyMessageContext reply_context =
      context->MakeReplyMessageContext();
  reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
      ppapi::proxy::SerializedHandle::FILE, file));
  SendReply(reply_context, IPC::Message());
  return PP_OK_COMPLETIONPENDING;
}

base::FilePath PepperFlashFileMessageFilter::ValidateAndConvertPepperFilePath(
    const ppapi::PepperFilePath& pepper_path,
    const CheckPermissionsCallback& check_permissions_callback) const {
  base::FilePath file_path;  // Empty path returned on error.
  switch (pepper_path.domain()) {
    case ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
      if (pepper_path.path().IsAbsolute() &&
          check_permissions_callback.Run(render_process_id_,
                                         pepper_path.path()))
        file_path = pepper_path.path();
      break;
    case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
      // This filter provides the module name portion of the path to prevent
      // plugins from accessing each other's data.
      if (!plugin_data_directory_.empty() &&
          !pepper_path.path().IsAbsolute() &&
          !pepper_path.path().ReferencesParent())
        file_path = plugin_data_directory_.Append(pepper_path.path());
      break;
    default:
      NOTREACHED();
      break;
  }
  return file_path;
}

}  // namespace content
<commit_msg>Remove CreatePlatformFile from pepper<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/pepper/pepper_flash_file_message_filter.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/threading/sequenced_worker_pool.h"
#include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/renderer_host/pepper/pepper_security_helper.h"
#include "content/public/browser/browser_ppapi_host.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_constants.h"
#include "ipc/ipc_platform_file.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/host_message_context.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/file_path.h"
#include "ppapi/shared_impl/file_type_conversion.h"

namespace content {

namespace {

bool CanRead(int process_id, const base::FilePath& path) {
  return ChildProcessSecurityPolicyImpl::GetInstance()->
      CanReadFile(process_id, path);
}

bool CanCreateReadWrite(int process_id, const base::FilePath& path) {
  return ChildProcessSecurityPolicyImpl::GetInstance()->
      CanCreateReadWriteFile(process_id, path);
}

}  // namespace

PepperFlashFileMessageFilter::PepperFlashFileMessageFilter(
    PP_Instance instance,
    BrowserPpapiHost* host)
    : plugin_process_handle_(host->GetPluginProcessHandle()) {
  int unused;
  host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused);
  base::FilePath profile_data_directory = host->GetProfileDataDirectory();
  std::string plugin_name = host->GetPluginName();

  if (profile_data_directory.empty() || plugin_name.empty()) {
    // These are used to construct the path. If they are not set it means we
    // will construct a bad path and could provide access to the wrong files.
    // In this case, |plugin_data_directory_| will remain unset and
    // |ValidateAndConvertPepperFilePath| will fail.
    NOTREACHED();
  } else {
    plugin_data_directory_ = GetDataDirName(profile_data_directory).Append(
        base::FilePath::FromUTF8Unsafe(plugin_name));
  }
}

PepperFlashFileMessageFilter::~PepperFlashFileMessageFilter() {
}

// static
base::FilePath PepperFlashFileMessageFilter::GetDataDirName(
    const base::FilePath& profile_path) {
  return profile_path.Append(kPepperDataDirname);
}

scoped_refptr<base::TaskRunner>
PepperFlashFileMessageFilter::OverrideTaskRunnerForMessage(
    const IPC::Message& msg) {
  // The blocking pool provides a pool of threads to run file
  // operations, instead of a single thread which might require
  // queuing time.  Since these messages are synchronous as sent from
  // the plugin, the sending thread cannot send a new message until
  // this one returns, so there is no need to sequence tasks here.  If
  // the plugin has multiple threads, it cannot make assumptions about
  // ordering of IPC message sends, so it cannot make assumptions
  // about ordering of operations caused by those IPC messages.
  return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool());
}

int32_t PepperFlashFileMessageFilter::OnResourceMessageReceived(
   const IPC::Message& msg,
   ppapi::host::HostMessageContext* context) {
  IPC_BEGIN_MESSAGE_MAP(PepperFlashFileMessageFilter, msg)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile,
                                      OnOpenFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile,
                                      OnRenameFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir,
                                      OnDeleteFileOrDir)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir,
                                      OnCreateDir)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile,
                                      OnQueryFile)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents,
                                      OnGetDirContents)
    PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
        PpapiHostMsg_FlashFile_CreateTemporaryFile,
        OnCreateTemporaryFile)
  IPC_END_MESSAGE_MAP()
  return PP_ERROR_FAILED;
}

int32_t PepperFlashFileMessageFilter::OnOpenFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path,
    int pp_open_flags) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path,
      base::Bind(&CanOpenWithPepperFlags, pp_open_flags));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  int platform_file_flags = 0;
  if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(
          pp_open_flags, &platform_file_flags)) {
    return base::File::FILE_ERROR_FAILED;
  }

  base::File file(full_path, platform_file_flags);
  if (!file.IsValid()) {
    return ppapi::FileErrorToPepperError(file.error_details());
  }

  // Make sure we didn't try to open a directory: directory fd shouldn't be
  // passed to untrusted processes because they open security holes.
  base::File::Info info;
  if (!file.GetInfo(&info) || info.is_directory) {
    // When in doubt, throw it out.
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  IPC::PlatformFileForTransit transit_file =
      IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_);
  ppapi::host::ReplyMessageContext reply_context =
      context->MakeReplyMessageContext();
  reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
      ppapi::proxy::SerializedHandle::FILE, transit_file));
  SendReply(reply_context, IPC::Message());
  return PP_OK_COMPLETIONPENDING;
}

int32_t PepperFlashFileMessageFilter::OnRenameFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& from_path,
    const ppapi::PepperFilePath& to_path) {
  base::FilePath from_full_path = ValidateAndConvertPepperFilePath(
      from_path, base::Bind(&CanCreateReadWrite));
  base::FilePath to_full_path = ValidateAndConvertPepperFilePath(
      to_path, base::Bind(&CanCreateReadWrite));
  if (from_full_path.empty() || to_full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::Move(from_full_path, to_full_path);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnDeleteFileOrDir(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path,
    bool recursive) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanCreateReadWrite));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::DeleteFile(full_path, recursive);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}
int32_t PepperFlashFileMessageFilter::OnCreateDir(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanCreateReadWrite));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  bool result = base::CreateDirectory(full_path);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnQueryFile(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanRead));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  base::File::Info info;
  bool result = base::GetFileInfo(full_path, &info);
  context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info);
  return ppapi::FileErrorToPepperError(result ?
      base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED);
}

int32_t PepperFlashFileMessageFilter::OnGetDirContents(
    ppapi::host::HostMessageContext* context,
    const ppapi::PepperFilePath& path) {
  base::FilePath full_path = ValidateAndConvertPepperFilePath(
      path, base::Bind(&CanRead));
  if (full_path.empty()) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  ppapi::DirContents contents;
  base::FileEnumerator enumerator(full_path, false,
      base::FileEnumerator::FILES |
      base::FileEnumerator::DIRECTORIES |
      base::FileEnumerator::INCLUDE_DOT_DOT);

  while (!enumerator.Next().empty()) {
    base::FileEnumerator::FileInfo info = enumerator.GetInfo();
    ppapi::DirEntry entry = {
      info.GetName(),
      info.IsDirectory()
    };
    contents.push_back(entry);
  }

  context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents);
  return PP_OK;
}

int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile(
    ppapi::host::HostMessageContext* context) {
  ppapi::PepperFilePath dir_path(
      ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, base::FilePath());
  base::FilePath validated_dir_path = ValidateAndConvertPepperFilePath(
      dir_path, base::Bind(&CanCreateReadWrite));
  if (validated_dir_path.empty() ||
      (!base::DirectoryExists(validated_dir_path) &&
       !base::CreateDirectory(validated_dir_path))) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_ACCESS_DENIED);
  }

  base::FilePath file_path;
  if (!base::CreateTemporaryFileInDir(validated_dir_path, &file_path)) {
    return ppapi::FileErrorToPepperError(
        base::File::FILE_ERROR_FAILED);
  }

  base::File file(file_path,
                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ |
                      base::File::FLAG_WRITE | base::File::FLAG_TEMPORARY |
                      base::File::FLAG_DELETE_ON_CLOSE);

  if (!file.IsValid())
    return ppapi::FileErrorToPepperError(file.error_details());

  IPC::PlatformFileForTransit transit_file =
      IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_);
  ppapi::host::ReplyMessageContext reply_context =
      context->MakeReplyMessageContext();
  reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
      ppapi::proxy::SerializedHandle::FILE, transit_file));
  SendReply(reply_context, IPC::Message());
  return PP_OK_COMPLETIONPENDING;
}

base::FilePath PepperFlashFileMessageFilter::ValidateAndConvertPepperFilePath(
    const ppapi::PepperFilePath& pepper_path,
    const CheckPermissionsCallback& check_permissions_callback) const {
  base::FilePath file_path;  // Empty path returned on error.
  switch (pepper_path.domain()) {
    case ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
      if (pepper_path.path().IsAbsolute() &&
          check_permissions_callback.Run(render_process_id_,
                                         pepper_path.path()))
        file_path = pepper_path.path();
      break;
    case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
      // This filter provides the module name portion of the path to prevent
      // plugins from accessing each other's data.
      if (!plugin_data_directory_.empty() &&
          !pepper_path.path().IsAbsolute() &&
          !pepper_path.path().ReferencesParent())
        file_path = plugin_data_directory_.Append(pepper_path.path());
      break;
    default:
      NOTREACHED();
      break;
  }
  return file_path;
}

}  // namespace content
<|endoftext|>


<commit_before>#include "ConsoleReporter.h"
#include <chrono>
#include <cstdio>
#include <iostream>
#include <memory>
#include <mutex>
#include "xUnit++/LineInfo.h"
#include "xUnit++/TestDetails.h"
#include "xUnit++/TestEvent.h"

namespace
{
    std::string FileAndLine(const xUnitpp::TestDetails &td, const xUnitpp::LineInfo &lineInfo)
    {
        auto result = to_string(lineInfo);
        if (result.empty())
        {
            result = to_string(td.LineInfo);
        }

        return result;
    }

    class CachedOutput
    {
        typedef std::map<int, std::shared_ptr<CachedOutput>> OutputCache;

    public:
        CachedOutput(const std::string &name)
            : name(name)
        {
        }

        ~CachedOutput()
        {
            if (!messages.empty())
            {
                std::cout << "\n[" << name << "]\n";

                for (const auto &msg : messages)
                {
                    std::cout << msg << std::endl;
                }
            }
        }

        static void Instant(const std::string &output)
        {
            std::cout << output;
        }

        static CachedOutput &Cache(const xUnitpp::TestDetails &td)
        {
            auto &cache = Cache();

            auto it = cache.find(td.Id);
            if (it == cache.end())
            {
                cache.insert(std::make_pair(td.Id, std::make_shared<CachedOutput>(td.Name)));
            }

            return *cache[td.Id];
        }

        static void Finish(const xUnitpp::TestDetails &td)
        {
            auto &cache = Cache();

            auto it = cache.find(td.Id);
            if (it != cache.end())
            {
                cache.erase(it);
            }
        }

        CachedOutput &operator <<(const std::string &output)
        {
            messages.push_back(output);
            return *this;
        }

    private:
        static OutputCache &Cache()
        {
            static OutputCache cache;
            return cache;
        }

        std::string name;
        std::vector<std::string> messages;
    };
}

namespace xUnitpp
{

ConsoleReporter::ConsoleReporter(bool verbose, bool veryVerbose)
    : mVerbose(verbose)
    , mVeryVerbose(veryVerbose)
{
}

void ConsoleReporter::ReportStart(const TestDetails &testDetails)
{
    if (mVeryVerbose)
    {
        CachedOutput::Instant("Starting test " + testDetails.Name + ".");
    }
}

void ConsoleReporter::ReportEvent(const TestDetails &testDetails, const TestEvent &evt)
{
    CachedOutput::Cache(testDetails) << (FileAndLine(testDetails, evt.LineInfo()) +
        ": " + to_string(evt.Level()) + ": " + to_string(evt));
}

void ConsoleReporter::ReportSkip(const TestDetails &testDetails, const std::string &reason)
{
    CachedOutput::Instant(FileAndLine(testDetails, LineInfo::empty()) +
        ": skipping " + testDetails.Name + ": " + reason);
}

void ConsoleReporter::ReportFinish(const TestDetails &testDetails, Time::Duration timeTaken)
{
    if (mVerbose)
    {
        auto ms = Time::ToMilliseconds(timeTaken);
        CachedOutput::Cache(testDetails) << (testDetails.Name + ": Completed in " +
            (ms.count() == 0 ? (std::to_string(timeTaken.count()) + " nanoseconds.\n") : (std::to_string(ms.count()) + " milliseconds.\n")));
    }

    CachedOutput::Finish(testDetails);
}

void ConsoleReporter::ReportAllTestsComplete(size_t testCount, size_t skipped, size_t failureCount, Time::Duration totalTime)
{
    std::string total = std::to_string(testCount) + " tests, ";
    std::string failures = std::to_string(failureCount) + " failed, ";
    std::string skips = std::to_string(skipped) + " skipped.";

    std::string header;

    if (failureCount > 0)
    {
        header = "\nFAILURE: ";
    }
    else if (skipped > 0)
    {
        header = "\nWARNING: ";
    }
    else
    {
        header = "\nSuccess: ";
    }

    CachedOutput::Instant(header + total + failures + skips);

    header = "Test time: ";

    auto ms = Time::ToMilliseconds(totalTime);

    if (ms.count() > 500)
    {
        CachedOutput::Instant(header + std::to_string(Time::ToSeconds(totalTime).count()) + " seconds.");
    }
    else
    {
        CachedOutput::Instant(header + std::to_string(ms.count()) + " milliseconds.");
    }
}

}
<commit_msg>accidentally removed newline in output<commit_after>#include "ConsoleReporter.h"
#include <chrono>
#include <cstdio>
#include <iostream>
#include <memory>
#include <mutex>
#include "xUnit++/LineInfo.h"
#include "xUnit++/TestDetails.h"
#include "xUnit++/TestEvent.h"

namespace
{
    std::string FileAndLine(const xUnitpp::TestDetails &td, const xUnitpp::LineInfo &lineInfo)
    {
        auto result = to_string(lineInfo);
        if (result.empty())
        {
            result = to_string(td.LineInfo);
        }

        return result;
    }

    class CachedOutput
    {
        typedef std::map<int, std::shared_ptr<CachedOutput>> OutputCache;

    public:
        CachedOutput(const std::string &name)
            : name(name)
        {
        }

        ~CachedOutput()
        {
            if (!messages.empty())
            {
                std::cout << "\n[" << name << "]\n";

                for (const auto &msg : messages)
                {
                    std::cout << msg << std::endl;
                }
            }
        }

        static void Instant(const std::string &output)
        {
            std::cout << output;
        }

        static CachedOutput &Cache(const xUnitpp::TestDetails &td)
        {
            auto &cache = Cache();

            auto it = cache.find(td.Id);
            if (it == cache.end())
            {
                cache.insert(std::make_pair(td.Id, std::make_shared<CachedOutput>(td.Name)));
            }

            return *cache[td.Id];
        }

        static void Finish(const xUnitpp::TestDetails &td)
        {
            auto &cache = Cache();

            auto it = cache.find(td.Id);
            if (it != cache.end())
            {
                cache.erase(it);
            }
        }

        CachedOutput &operator <<(const std::string &output)
        {
            messages.push_back(output);
            return *this;
        }

    private:
        static OutputCache &Cache()
        {
            static OutputCache cache;
            return cache;
        }

        std::string name;
        std::vector<std::string> messages;
    };
}

namespace xUnitpp
{

ConsoleReporter::ConsoleReporter(bool verbose, bool veryVerbose)
    : mVerbose(verbose)
    , mVeryVerbose(veryVerbose)
{
}

void ConsoleReporter::ReportStart(const TestDetails &testDetails)
{
    if (mVeryVerbose)
    {
        CachedOutput::Instant("Starting test " + testDetails.Name + ".");
    }
}

void ConsoleReporter::ReportEvent(const TestDetails &testDetails, const TestEvent &evt)
{
    CachedOutput::Cache(testDetails) << (FileAndLine(testDetails, evt.LineInfo()) +
        ": " + to_string(evt.Level()) + ": " + to_string(evt));
}

void ConsoleReporter::ReportSkip(const TestDetails &testDetails, const std::string &reason)
{
    CachedOutput::Instant(FileAndLine(testDetails, LineInfo::empty()) +
        ": skipping " + testDetails.Name + ": " + reason);
}

void ConsoleReporter::ReportFinish(const TestDetails &testDetails, Time::Duration timeTaken)
{
    if (mVerbose)
    {
        auto ms = Time::ToMilliseconds(timeTaken);
        CachedOutput::Cache(testDetails) << (testDetails.Name + ": Completed in " +
            (ms.count() == 0 ? (std::to_string(timeTaken.count()) + " nanoseconds.\n") : (std::to_string(ms.count()) + " milliseconds.\n")));
    }

    CachedOutput::Finish(testDetails);
}

void ConsoleReporter::ReportAllTestsComplete(size_t testCount, size_t skipped, size_t failureCount, Time::Duration totalTime)
{
    std::string total = std::to_string(testCount) + " tests, ";
    std::string failures = std::to_string(failureCount) + " failed, ";
    std::string skips = std::to_string(skipped) + " skipped.";

    std::string header;

    if (failureCount > 0)
    {
        header = "\nFAILURE: ";
    }
    else if (skipped > 0)
    {
        header = "\nWARNING: ";
    }
    else
    {
        header = "\nSuccess: ";
    }

    CachedOutput::Instant(header + total + failures + skips);

    header = "\nTest time: ";

    auto ms = Time::ToMilliseconds(totalTime);

    if (ms.count() > 500)
    {
        CachedOutput::Instant(header + std::to_string(Time::ToSeconds(totalTime).count()) + " seconds.");
    }
    else
    {
        CachedOutput::Instant(header + std::to_string(ms.count()) + " milliseconds.");
    }
}

}
<|endoftext|>


<commit_before>#include <string>
#include <stdexcept>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

using ::testing::Sequence;
using ::testing::Return;

using ::sauce::Binder;
using ::sauce::Named;

namespace sauce {
namespace test {

struct CustomBuilt {};

struct CustomBuiltProvider: Provider<CustomBuilt> {
  CustomBuilt * provide() {
    return new CustomBuilt();
  }

  void dispose(CustomBuilt * customBuilt) {
    delete customBuilt;
  }
};

void ProviderModule(Binder & binder) {
  binder.bind<CustomBuiltProvider>().to<CustomBuiltProvider()>();
  binder.bind<CustomBuilt>().toProvider<CustomBuiltProvider>();
}

TEST(BindingTest, shouldBindProviders) {
  sauce::shared_ptr<Injector> injector(Modules().add(&ProviderModule).createInjector());
  sauce::shared_ptr<CustomBuilt> customBuilt = injector->get<CustomBuilt>();
}

struct Unbound {};

TEST(BindingTest, shouldThrowExceptionWhenGettingAnUnboundIface) {
  sauce::shared_ptr<Injector> injector(Modules().createInjector());
  ASSERT_THROW((injector->get<Unbound>()), ::sauce::UnboundException);
}

TEST(BindingTest, shouldImplicitlyBindTheInjectorItself) {
  sauce::shared_ptr<Injector> expected = Modules().createInjector();
  sauce::shared_ptr<Injector> actual = expected->get<Injector>();
  ASSERT_EQ(expected, actual);
}

struct Dog;

struct Tail {
  Tail(sauce::shared_ptr<Dog>) {}
};

struct Dog {
  Dog(sauce::shared_ptr<Tail>) {}
};

void CircularModule(Binder & binder) {
  binder.bind<Tail>().in<SingletonScope>().to<Tail(Dog)>();
  binder.bind<Dog>().in<SingletonScope>().to<Dog(Tail)>();
}

TEST(BindingTest, shouldThrowExceptionWhenResolvingCircularDependency) {
  sauce::shared_ptr<Injector> injector(Modules().add(&CircularModule).createInjector());
  ASSERT_THROW(injector->get<Tail>(), ::sauce::CircularDependencyException);
}

TEST(BindingTest, shouldThrowExceptionWhenEagerlyProvidingCircularDependency) {
  sauce::shared_ptr<Injector> injector(Modules().add(&CircularModule).createInjector());
  ASSERT_THROW(injector->eagerlyProvide<SingletonScope>(), ::sauce::CircularDependencyException);
}

struct IncompletelyBound {};

void IncompleteModule(Binder & binder) {
  binder.bind<IncompletelyBound>() /* to ...? */;
}

TEST(BindingTest, shouldThrowExceptionOnPartialBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteModule).createInjector(),
    ::sauce::PartialBindingException);
}

struct Animal {
  virtual std::string says() = 0;
};

struct Cat: Animal {
  std::string says() { return "Meow"; }
};

struct LieutenantShinysides {};
struct Fish: Animal {
  std::string says() { return "Blub blub"; }
};

struct Meatloaf {};
struct Cow: Animal {
  std::string says() { return "Moo"; }
};

struct Pond {
  sauce::shared_ptr<Animal> animal;

  Pond(sauce::shared_ptr<Animal> animal):
    animal(animal) {}
};

void AnimalModule(Binder & binder) {
  binder.bind<Animal>().to<Cat()>();
  binder.bind<Animal>().named<LieutenantShinysides>().to<Fish()>();
  binder.bind<Animal>().named<Meatloaf>().to<Cow()>();

  binder.bind<Pond>().to<Pond(Named<Animal, LieutenantShinysides>)>();
}

TEST(BindingTest, shouldProvidedNamedDependencies) {
  sauce::shared_ptr<Injector> injector(Modules().add(&AnimalModule).createInjector());

  EXPECT_EQ("Meow",      (injector->get<Animal>()->says()));
  EXPECT_EQ("Blub blub", (injector->get<Animal, LieutenantShinysides>()->says()));
  EXPECT_EQ("Moo",       (injector->get<Named<Animal, Meatloaf> >()->says()));

  EXPECT_EQ("Blub blub", (injector->get<Pond>()->animal->says()));
}

void IncompleteNamedModule(Binder & binder) {
  binder.bind<IncompletelyBound>().named<LieutenantShinysides>() /* to ...? */;
}

TEST(BindingTest, shouldThrowExceptionOnPartialNamedBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteNamedModule).createInjector(),
    ::sauce::PartialBindingException);
}

void IncompleteScopeModule(Binder & binder) {
  binder.bind<IncompletelyBound>().in<SingletonScope>();
}

TEST(BindingTest, shouldThrowExceptionOnPartialScopedBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteScopeModule).createInjector(),
    ::sauce::PartialBindingException);
}

}
}
<commit_msg>Tweak<commit_after>#include <string>
#include <stdexcept>

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

using ::testing::Sequence;
using ::testing::Return;

using ::sauce::Binder;
using ::sauce::Named;

namespace sauce {
namespace test {

struct CustomBuilt {};

struct CustomBuiltProvider: Provider<CustomBuilt> {
  CustomBuilt * provide() {
    return new CustomBuilt();
  }

  void dispose(CustomBuilt * customBuilt) {
    delete customBuilt;
  }
};

void ProviderModule(Binder & binder) {
  binder.bind<CustomBuiltProvider>().to<CustomBuiltProvider()>();
  binder.bind<CustomBuilt>().toProvider<CustomBuiltProvider>();
}

TEST(BindingTest, shouldBindProviders) {
  sauce::shared_ptr<Injector> injector(Modules().add(&ProviderModule).createInjector());
  sauce::shared_ptr<CustomBuilt> customBuilt = injector->get<CustomBuilt>();
}

struct Unbound {};

TEST(BindingTest, shouldThrowExceptionWhenGettingAnUnboundIface) {
  sauce::shared_ptr<Injector> injector(Modules().createInjector());
  ASSERT_THROW(injector->get<Unbound>(), ::sauce::UnboundException);
}

TEST(BindingTest, shouldImplicitlyBindTheInjectorItself) {
  sauce::shared_ptr<Injector> expected = Modules().createInjector();
  sauce::shared_ptr<Injector> actual = expected->get<Injector>();
  ASSERT_EQ(expected, actual);
}

struct Dog;

struct Tail {
  Tail(sauce::shared_ptr<Dog>) {}
};

struct Dog {
  Dog(sauce::shared_ptr<Tail>) {}
};

void CircularModule(Binder & binder) {
  binder.bind<Tail>().in<SingletonScope>().to<Tail(Dog)>();
  binder.bind<Dog>().in<SingletonScope>().to<Dog(Tail)>();
}

TEST(BindingTest, shouldThrowExceptionWhenResolvingCircularDependency) {
  sauce::shared_ptr<Injector> injector(Modules().add(&CircularModule).createInjector());
  ASSERT_THROW(injector->get<Tail>(), ::sauce::CircularDependencyException);
}

TEST(BindingTest, shouldThrowExceptionWhenEagerlyProvidingCircularDependency) {
  sauce::shared_ptr<Injector> injector(Modules().add(&CircularModule).createInjector());
  ASSERT_THROW(injector->eagerlyProvide<SingletonScope>(), ::sauce::CircularDependencyException);
}

struct IncompletelyBound {};

void IncompleteModule(Binder & binder) {
  binder.bind<IncompletelyBound>() /* to ...? */;
}

TEST(BindingTest, shouldThrowExceptionOnPartialBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteModule).createInjector(),
    ::sauce::PartialBindingException);
}

struct Animal {
  virtual std::string says() = 0;
};

struct Cat: Animal {
  std::string says() { return "Meow"; }
};

struct LieutenantShinysides {};
struct Fish: Animal {
  std::string says() { return "Blub blub"; }
};

struct Meatloaf {};
struct Cow: Animal {
  std::string says() { return "Moo"; }
};

struct Pond {
  sauce::shared_ptr<Animal> animal;

  Pond(sauce::shared_ptr<Animal> animal):
    animal(animal) {}
};

void AnimalModule(Binder & binder) {
  binder.bind<Animal>().to<Cat()>();
  binder.bind<Animal>().named<LieutenantShinysides>().to<Fish()>();
  binder.bind<Animal>().named<Meatloaf>().to<Cow()>();

  binder.bind<Pond>().to<Pond(Named<Animal, LieutenantShinysides>)>();
}

TEST(BindingTest, shouldProvidedNamedDependencies) {
  sauce::shared_ptr<Injector> injector(Modules().add(&AnimalModule).createInjector());

  EXPECT_EQ("Meow",      (injector->get<Animal>()->says()));
  EXPECT_EQ("Blub blub", (injector->get<Animal, LieutenantShinysides>()->says()));
  EXPECT_EQ("Moo",       (injector->get<Named<Animal, Meatloaf> >()->says()));

  EXPECT_EQ("Blub blub", (injector->get<Pond>()->animal->says()));
}

void IncompleteNamedModule(Binder & binder) {
  binder.bind<IncompletelyBound>().named<LieutenantShinysides>() /* to ...? */;
}

TEST(BindingTest, shouldThrowExceptionOnPartialNamedBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteNamedModule).createInjector(),
    ::sauce::PartialBindingException);
}

void IncompleteScopeModule(Binder & binder) {
  binder.bind<IncompletelyBound>().in<SingletonScope>();
}

TEST(BindingTest, shouldThrowExceptionOnPartialScopedBinding) {
  ASSERT_THROW(
    Modules().add(&IncompleteScopeModule).createInjector(),
    ::sauce::PartialBindingException);
}

}
}
<|endoftext|>


<commit_before>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/contract.hh>
#include <libport/foreach.hh>

#include <object/urbi-exception.hh>

#include <scheduler/scheduler.hh>
#include <scheduler/job.hh>

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job(Job* job)
  {
    job->run();
  }

  void
  Scheduler::add_job(rJob job)
  {
    assert(job);
    assert(!libport::has(jobs_, job));
    assert(!libport::has(pending_, job));
    // If we are currently in a job, add it to the pending_ queue so that
    // the job is started in the course of the current round. To make sure
    // that it is not started too late even if the creator is located after
    // the job that is causing the creation (think "at job handler" for
    // example), insert it right after the current job.
    if (current_job_)
    {
      jobs_type::iterator insert_before = job_p_;
      pending_.insert(++insert_before, job);
    }
    else
    {
      jobs_.push_back(job);
      jobs_to_start_ = true;
    }
  }

  libport::utime_t
  Scheduler::work()
  {
    ++cycle_;
    ECHO("======================================================== cycle "
	  << cycle_);

    libport::utime_t deadline = execute_round();

#ifdef ENABLE_DEBUG_TRACES
    if (deadline)
      ECHO("Scheduler asking to be woken up in "
	    << (deadline - get_time_()) / 1000000L << " seconds");
    else
      ECHO("Scheduler asking to be woken up ASAP");
#endif

    return deadline;
  }

  libport::utime_t
  Scheduler::execute_round()
  {
    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    pending_.clear();
    std::swap(pending_, jobs_);

    // By default, wake us up after one hour and consider that we have no
    // new job to start. Also, run waiting jobs only if the previous round
    // may have add a side effect and reset this indication for the current
    // job.
    libport::utime_t start_time = get_time_();
    libport::utime_t deadline = start_time +  3600000000LL;
    jobs_to_start_ = false;
    bool start_waiting = possible_side_effect_;
    possible_side_effect_ = false;
    bool at_least_one_started = false;

    ECHO(pending_.size() << " jobs in the queue for this round");

    // Do not use libport::foreach here, as the list of jobs may grow if
    // add_job() is called during the iteration.
    for (job_p_ = pending_.begin();
	 job_p_ != pending_.end();
	 ++job_p_)
    {
      rJob& job = *job_p_;
      // If the job has terminated during the previous round, remove the
      // references we have on it by just skipping it.
      if (job->terminated())
	continue;

      // Should the job be started?
      bool start = false;

      // Save the current time since we will use it several times during this job
      // analysis.
      libport::utime_t current_time = get_time_();

      ECHO("Considering " << *job << " in state " << state_name(job->state_get()));

      switch (job->state_get())
      {
      case to_start:
      {
	// New job. Start its coroutine but do not start the job as it would be queued
	// twice otherwise. It will start doing real work at the next cycle, so set
	// deadline to 0. Note that we use "continue" here to avoid having the job
	// requeued because it hasn't been started by setting "start".
	//
	// The code below takes care of destroying the rJob reference to the job, so
	// that it does not stay in the call stack as a local variable. If it did,
	// the job would never be destroyed. However, to prevent the job from being
	// prematurely destroyed, we set current_job_ (global to the scheduler) to
	// the rJob.
	ECHO("Starting job " << *job);
	current_job_ = job;
	ECHO("Job " << *job << " is starting");
	job = 0;
	coroutine_start(coro_, current_job_->coro_get(), run_job, current_job_.get());
	current_job_ = 0;
	deadline = SCHED_IMMEDIATE;
	at_least_one_started = true;
	continue;
      }
      case zombie:
	assert(false);
	break;
      case running:
	start = true;
	break;
      case sleeping:
	{
	  libport::utime_t job_deadline = job->deadline_get();

	  // If the job has been frozen, extend its deadline by the
	  // corresponding amount of time. The deadline will be adjusted
	  // later when the job is unfrozen using notice_not_frozen(),
	  // but in the meantime we do not want to cause an early wakeup.
	  if (libport::utime_t frozen_since = job->frozen_since_get())
	    job_deadline += current_time - frozen_since;

	  if (job_deadline <= current_time)
	    start = true;
	  else
	    deadline = std::min(deadline, job_deadline);
	}
	break;
      case waiting:
	// Since jobs keep their orders in the queue, start waiting jobs if
	// previous jobs in the run have had a possible side effect or if
	// the previous run may have had some. Without it, we may miss some
	// changes if the watching job is after the modifying job in the queue
	// and the watched condition gets true for only one cycle.
	start = start_waiting || possible_side_effect_;
	break;
      case joining:
	break;
      }

      // Tell the job whether it is frozen or not so that it can remember
      // since when it has been in this state.
      if (job->frozen())
	job->notice_frozen(current_time);
      else
	job->notice_not_frozen(current_time);

      // A job with an exception will start unconditionally.
      if (start || job->has_pending_exception())
      {
	at_least_one_started = true;
	ECHO("will resume job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	possible_side_effect_ |= !job->side_effect_free_get();
	assert(!current_job_);
	coroutine_switch_to(coro_, job->coro_get());
	assert(!current_job_);
	possible_side_effect_ |= !job->side_effect_free_get();
	ECHO("back from job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	switch (job->state_get())
	{
	case running:
	  deadline = SCHED_IMMEDIATE;
	  break;
	case sleeping:
	  deadline = std::min(deadline, job->deadline_get());
	  break;
	default:
	  break;
	}
      }
      else
	jobs_.push_back(job);   // Job not started, keep it in queue
    }

    /// If during this cycle a new job has been created by an existing job,
    /// start it. Also start if a possible side effect happened, it may have
    /// occurred later then the waiting jobs in the cycle.
    if (jobs_to_start_ || possible_side_effect_)
      deadline = SCHED_IMMEDIATE;

    /// If we are ready to die and there are no jobs left, then die.
    if (ready_to_die_ && jobs_.empty())
      deadline = SCHED_EXIT;

    // Compute statistics
    if (at_least_one_started)
      stats_.add_sample(get_time_() - start_time);

    return deadline;
  }

  void
  Scheduler::resume_scheduler(rJob job)
  {
    // If the job has not terminated and is side-effect free, then we
    // assume it will not take a long time as we are probably evaluating
    // a condition. In order to reduce the number of cycles spent to evaluate
    // the condition, continue until it asks to be suspended in another
    // way or until it is no longer side-effect free.

    bool side_effect_free_save = job->side_effect_free_get();

    if (job->state_get() == running && side_effect_free_save)
      return;

    // We may have to suspend the job several time in case it makes no sense
    // to start it back. Let's do it in a loop and we'll break when we want
    // to resume the job.

    while (true)
    {
      // Add the job at the end of the scheduler queue unless the job has
      // already terminated.
      if (!job->terminated())
	jobs_.push_back(job);

      // Switch back to the scheduler. But in the case this job has been
      // destroyed, erase the local variable first so that it doesn't keep
      // a reference on it which will never be destroyed.
      assert(current_job_ == job);
      ECHO(*job << " has " << (job->terminated() ? "" : "not ") << "terminated\n\t"
	   << "state: " << state_name(job->state_get()) << std::endl);
      Coro* current_coro = job->coro_get();
      if (job->terminated())
	job = 0;
      current_job_ = 0;
      coroutine_switch_to(current_coro, coro_);

      // If we regain control, we are not dead.
      assert(job);

      // We regained control, we are again in the context of the job.
      assert(!current_job_);
      current_job_ = job;
      ECHO("job " << *job << " resumed");

      // Execute a deferred exception if any; this may break out of this loop
      job->check_for_pending_exception();

      // If we are not frozen, it is time to resume regular execution
      if (!job->frozen())
	break;

      // Ok, we are frozen. Let's requeue ourselves after setting
      // the side_effect_free flag, and we will be in waiting mode.
      job->side_effect_free_set(true);
      job->state_set(waiting);
    }

    // Check that we are not near exhausting the stack space.
    job->check_stack_space();

    // Restore the side_effect_free flag
    job->side_effect_free_set(side_effect_free_save);

    // Resume job execution
  }

  void
  Scheduler::killall_jobs()
  {
    ECHO("killing all jobs!");

    // Mark the scheduler as ready to die when all the jobs are
    // really dead.
    ready_to_die_ = true;

    // Since killing the current job will result in its immediate
    // termination, kill all other jobs before.
    foreach (rJob job, jobs_get())
      if (job != current_job_)
	job->terminate_now();
    if (current_job_)
      current_job_->terminate_now();
  }

  void
  Scheduler::signal_stop(const rTag& tag, boost::any payload)
  {
    // Tell the jobs that a tag has been stopped, ending with
    // the current job to avoid interrupting this method early.
    foreach (rJob job, jobs_get())
    {
      // Job started at this cycle, reset to avoid stack references.
      if (!job)
	continue;
      // Job to be started during this cycle.
      if (job->state_get() == to_start)
      {
	// Check if this job deserves to be removed.
	foreach (const rTag& t, job->tags_get())
	  if (t->derives_from(*tag))
	  {
	    pending_.remove(job);
	    continue;
	  }
      }
      // Any other non-current job.
      else if (job != current_job_)
	job->register_stopped_tag(tag, payload);
    }
    if (current_job_)
      current_job_->register_stopped_tag(tag, payload);
  }

  jobs_type
  Scheduler::jobs_get() const
  {
    // If this method is called from within a job, return the currently
    // executing jobs (pending_), otherwise return the jobs_ content which
    // is complete.
    return current_job_ ? pending_ : jobs_;
  }

  const scheduler_stats_type&
  Scheduler::stats_get() const
  {
    return stats_;
  }

} // namespace scheduler
<commit_msg>Do not reset current_job_ before switching back to the scheduler.<commit_after>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>
#include <cstdlib>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/contract.hh>
#include <libport/foreach.hh>

#include <object/urbi-exception.hh>

#include <scheduler/scheduler.hh>
#include <scheduler/job.hh>

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job(Job* job)
  {
    job->run();
  }

  void
  Scheduler::add_job(rJob job)
  {
    assert(job);
    assert(!libport::has(jobs_, job));
    assert(!libport::has(pending_, job));
    // If we are currently in a job, add it to the pending_ queue so that
    // the job is started in the course of the current round. To make sure
    // that it is not started too late even if the creator is located after
    // the job that is causing the creation (think "at job handler" for
    // example), insert it right after the current job.
    if (current_job_)
    {
      jobs_type::iterator insert_before = job_p_;
      pending_.insert(++insert_before, job);
    }
    else
    {
      jobs_.push_back(job);
      jobs_to_start_ = true;
    }
  }

  libport::utime_t
  Scheduler::work()
  {
    ++cycle_;
    ECHO("======================================================== cycle "
	  << cycle_);

    libport::utime_t deadline = execute_round();

#ifdef ENABLE_DEBUG_TRACES
    if (deadline)
      ECHO("Scheduler asking to be woken up in "
	    << (deadline - get_time_()) / 1000000L << " seconds");
    else
      ECHO("Scheduler asking to be woken up ASAP");
#endif

    return deadline;
  }

  libport::utime_t
  Scheduler::execute_round()
  {
    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    pending_.clear();
    std::swap(pending_, jobs_);

    // By default, wake us up after one hour and consider that we have no
    // new job to start. Also, run waiting jobs only if the previous round
    // may have add a side effect and reset this indication for the current
    // job.
    libport::utime_t start_time = get_time_();
    libport::utime_t deadline = start_time +  3600000000LL;
    jobs_to_start_ = false;
    bool start_waiting = possible_side_effect_;
    possible_side_effect_ = false;
    bool at_least_one_started = false;

    ECHO(pending_.size() << " jobs in the queue for this round");

    // Do not use libport::foreach here, as the list of jobs may grow if
    // add_job() is called during the iteration.
    for (job_p_ = pending_.begin();
	 job_p_ != pending_.end();
	 ++job_p_)
    {
      rJob& job = *job_p_;
      // If the job has terminated during the previous round, remove the
      // references we have on it by just skipping it.
      if (job->terminated())
	continue;

      // Should the job be started?
      bool start = false;

      // Save the current time since we will use it several times during this job
      // analysis.
      libport::utime_t current_time = get_time_();

      ECHO("Considering " << *job << " in state " << state_name(job->state_get()));

      switch (job->state_get())
      {
      case to_start:
      {
	// New job. Start its coroutine but do not start the job as it would be queued
	// twice otherwise. It will start doing real work at the next cycle, so set
	// deadline to 0. Note that we use "continue" here to avoid having the job
	// requeued because it hasn't been started by setting "start".
	//
	// The code below takes care of destroying the rJob reference to the job, so
	// that it does not stay in the call stack as a local variable. If it did,
	// the job would never be destroyed. However, to prevent the job from being
	// prematurely destroyed, we set current_job_ (global to the scheduler) to
	// the rJob.
	ECHO("Starting job " << *job);
	current_job_ = job;
	ECHO("Job " << *job << " is starting");
	job = 0;
	coroutine_start(coro_, current_job_->coro_get(), run_job, current_job_.get());
	current_job_ = 0;
	deadline = SCHED_IMMEDIATE;
	at_least_one_started = true;
	continue;
      }
      case zombie:
	assert(false);
	break;
      case running:
	start = true;
	break;
      case sleeping:
	{
	  libport::utime_t job_deadline = job->deadline_get();

	  // If the job has been frozen, extend its deadline by the
	  // corresponding amount of time. The deadline will be adjusted
	  // later when the job is unfrozen using notice_not_frozen(),
	  // but in the meantime we do not want to cause an early wakeup.
	  if (libport::utime_t frozen_since = job->frozen_since_get())
	    job_deadline += current_time - frozen_since;

	  if (job_deadline <= current_time)
	    start = true;
	  else
	    deadline = std::min(deadline, job_deadline);
	}
	break;
      case waiting:
	// Since jobs keep their orders in the queue, start waiting jobs if
	// previous jobs in the run have had a possible side effect or if
	// the previous run may have had some. Without it, we may miss some
	// changes if the watching job is after the modifying job in the queue
	// and the watched condition gets true for only one cycle.
	start = start_waiting || possible_side_effect_;
	break;
      case joining:
	break;
      }

      // Tell the job whether it is frozen or not so that it can remember
      // since when it has been in this state.
      if (job->frozen())
	job->notice_frozen(current_time);
      else
	job->notice_not_frozen(current_time);

      // A job with an exception will start unconditionally.
      if (start || job->has_pending_exception())
      {
	at_least_one_started = true;
	ECHO("will resume job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	possible_side_effect_ |= !job->side_effect_free_get();
	assert(!current_job_);
	coroutine_switch_to(coro_, job->coro_get());
	assert(current_job_);
	current_job_ = 0;
	possible_side_effect_ |= !job->side_effect_free_get();
	ECHO("back from job " << *job
	      << (job->side_effect_free_get() ? " (side-effect free)" : ""));
	switch (job->state_get())
	{
	case running:
	  deadline = SCHED_IMMEDIATE;
	  break;
	case sleeping:
	  deadline = std::min(deadline, job->deadline_get());
	  break;
	default:
	  break;
	}
      }
      else
	jobs_.push_back(job);   // Job not started, keep it in queue
    }

    /// If during this cycle a new job has been created by an existing job,
    /// start it. Also start if a possible side effect happened, it may have
    /// occurred later then the waiting jobs in the cycle.
    if (jobs_to_start_ || possible_side_effect_)
      deadline = SCHED_IMMEDIATE;

    /// If we are ready to die and there are no jobs left, then die.
    if (ready_to_die_ && jobs_.empty())
      deadline = SCHED_EXIT;

    // Compute statistics
    if (at_least_one_started)
      stats_.add_sample(get_time_() - start_time);

    return deadline;
  }

  void
  Scheduler::resume_scheduler(rJob job)
  {
    // If the job has not terminated and is side-effect free, then we
    // assume it will not take a long time as we are probably evaluating
    // a condition. In order to reduce the number of cycles spent to evaluate
    // the condition, continue until it asks to be suspended in another
    // way or until it is no longer side-effect free.

    bool side_effect_free_save = job->side_effect_free_get();

    if (job->state_get() == running && side_effect_free_save)
      return;

    // We may have to suspend the job several time in case it makes no sense
    // to start it back. Let's do it in a loop and we'll break when we want
    // to resume the job.

    while (true)
    {
      // Add the job at the end of the scheduler queue unless the job has
      // already terminated.
      if (!job->terminated())
	jobs_.push_back(job);

      // Switch back to the scheduler. But in the case this job has been
      // destroyed, erase the local variable first so that it doesn't keep
      // a reference on it which will never be destroyed.
      assert(current_job_ == job);
      ECHO(*job << " has " << (job->terminated() ? "" : "not ") << "terminated\n\t"
	   << "state: " << state_name(job->state_get()) << std::endl);
      Coro* current_coro = job->coro_get();
      if (job->terminated())
	job = 0;
      coroutine_switch_to(current_coro, coro_);

      // If we regain control, we are not dead.
      assert(job);

      // We regained control, we are again in the context of the job.
      assert(!current_job_);
      current_job_ = job;
      ECHO("job " << *job << " resumed");

      // Execute a deferred exception if any; this may break out of this loop
      job->check_for_pending_exception();

      // If we are not frozen, it is time to resume regular execution
      if (!job->frozen())
	break;

      // Ok, we are frozen. Let's requeue ourselves after setting
      // the side_effect_free flag, and we will be in waiting mode.
      job->side_effect_free_set(true);
      job->state_set(waiting);
    }

    // Check that we are not near exhausting the stack space.
    job->check_stack_space();

    // Restore the side_effect_free flag
    job->side_effect_free_set(side_effect_free_save);

    // Resume job execution
  }

  void
  Scheduler::killall_jobs()
  {
    ECHO("killing all jobs!");

    // Mark the scheduler as ready to die when all the jobs are
    // really dead.
    ready_to_die_ = true;

    // Since killing the current job will result in its immediate
    // termination, kill all other jobs before.
    foreach (rJob job, jobs_get())
      if (job != current_job_)
	job->terminate_now();
    if (current_job_)
      current_job_->terminate_now();
  }

  void
  Scheduler::signal_stop(const rTag& tag, boost::any payload)
  {
    // Tell the jobs that a tag has been stopped, ending with
    // the current job to avoid interrupting this method early.
    foreach (rJob job, jobs_get())
    {
      // Job started at this cycle, reset to avoid stack references.
      if (!job)
	continue;
      // Job to be started during this cycle.
      if (job->state_get() == to_start)
      {
	// Check if this job deserves to be removed.
	foreach (const rTag& t, job->tags_get())
	  if (t->derives_from(*tag))
	  {
	    pending_.remove(job);
	    continue;
	  }
      }
      // Any other non-current job.
      else if (job != current_job_)
	job->register_stopped_tag(tag, payload);
    }
    if (current_job_)
      current_job_->register_stopped_tag(tag, payload);
  }

  jobs_type
  Scheduler::jobs_get() const
  {
    // If this method is called from within a job, return the currently
    // executing jobs (pending_), otherwise return the jobs_ content which
    // is complete.
    return current_job_ ? pending_ : jobs_;
  }

  const scheduler_stats_type&
  Scheduler::stats_get() const
  {
    return stats_;
  }

} // namespace scheduler
<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

using ::testing::Sequence;
using ::testing::Return;

namespace sauce {
namespace test {

class Store {};
class DBStore: public Store {};

class Session {};
class CookieSession: public Session {};

class Request {};
class HttpRequest: public Request {};

class Response {};
class HttpResponse: public Response {};

class Controller {};
class WelcomeController: public Controller {
public:

  SAUCE_SHARED_PTR<Store> store;
  SAUCE_SHARED_PTR<Session> session;
  SAUCE_SHARED_PTR<Request> request;
  SAUCE_SHARED_PTR<Response> response;

  WelcomeController(SAUCE_SHARED_PTR<Store> store,
                    SAUCE_SHARED_PTR<Session> session,
                    SAUCE_SHARED_PTR<Request> request,
                    SAUCE_SHARED_PTR<Response> response):
    store(store),
    session(session),
    request(request),
    response(response) {}

};

struct WebAppModule: ::sauce::AbstractModule {
  void configure() {
    bind<Store>().to<DBStore()>();
    bind<Session>().to<CookieSession()>();
    bind<Request>().to<HttpRequest()>();
    bind<Response>().to<HttpResponse()>();
    bind<Controller>().to<WelcomeController(Store, Session, Request, Response)>();
  }
};

struct BindingTest:
  public ::testing::Test {

  Injector injector;

  BindingTest():
    injector(Bindings().add(WebAppModule()).createInjector()) {}

  virtual void SetUp() {}

  virtual void TearDown() {}
};

TEST_F(BindingTest, shouldThrowExceptionWhenGettingAnUnboundIface) {
  Injector injector(Bindings().createInjector());
  ASSERT_THROW(injector.get<Request>(), ::sauce::UnboundException);
}

struct B;

struct A {
  A(SAUCE_SHARED_PTR<B> ) {}
};

struct B {
  B(SAUCE_SHARED_PTR<A> ) {}
};

void CircularModule(sauce::Binder & binder) {
  binder.bind<A>().to<A(B)>();
  binder.bind<B>().to<B(A)>();
}

TEST_F(BindingTest, shouldThrowExceptionWhenResolvingCircularDependency) {
  Injector injector(Bindings().add(&CircularModule).createInjector());
  ASSERT_THROW(injector.get<A>(), ::sauce::CircularDependencyException);
}

}
}<commit_msg>Let them eat public.<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <sauce/sauce.h>

using ::testing::Sequence;
using ::testing::Return;

namespace sauce {
namespace test {

struct Store {};
struct DBStore: public Store {};

struct Session {};
struct CookieSession: public Session {};

struct Request {};
struct HttpRequest: public Request {};

struct Response {};
struct HttpResponse: public Response {};

struct Controller {};
struct WelcomeController: public Controller {

  SAUCE_SHARED_PTR<Store> store;
  SAUCE_SHARED_PTR<Session> session;
  SAUCE_SHARED_PTR<Request> request;
  SAUCE_SHARED_PTR<Response> response;

  WelcomeController(SAUCE_SHARED_PTR<Store> store,
                    SAUCE_SHARED_PTR<Session> session,
                    SAUCE_SHARED_PTR<Request> request,
                    SAUCE_SHARED_PTR<Response> response):
    store(store),
    session(session),
    request(request),
    response(response) {}

};

struct WebAppModule: ::sauce::AbstractModule {
  void configure() {
    bind<Store>().to<DBStore()>();
    bind<Session>().to<CookieSession()>();
    bind<Request>().to<HttpRequest()>();
    bind<Response>().to<HttpResponse()>();
    bind<Controller>().to<WelcomeController(Store, Session, Request, Response)>();
  }
};

struct BindingTest:
  public ::testing::Test {

  Injector injector;

  BindingTest():
    injector(Bindings().add(WebAppModule()).createInjector()) {}

  virtual void SetUp() {}

  virtual void TearDown() {}
};

TEST_F(BindingTest, shouldThrowExceptionWhenGettingAnUnboundIface) {
  Injector injector(Bindings().createInjector());
  ASSERT_THROW(injector.get<Request>(), ::sauce::UnboundException);
}

struct B;

struct A {
  A(SAUCE_SHARED_PTR<B> ) {}
};

struct B {
  B(SAUCE_SHARED_PTR<A> ) {}
};

void CircularModule(sauce::Binder & binder) {
  binder.bind<A>().to<A(B)>();
  binder.bind<B>().to<B(A)>();
}

TEST_F(BindingTest, shouldThrowExceptionWhenResolvingCircularDependency) {
  Injector injector(Bindings().add(&CircularModule).createInjector());
  ASSERT_THROW(injector.get<A>(), ::sauce::CircularDependencyException);
}

}
}<|endoftext|>


<commit_before>#include <cstdlib>
#include <cassert>

#include "zs.hh"
#include "test_util.hh"

static bool result = true;

void check(const char* input, const char* expect){
  result = read_eval_print_test(input, expect,
                                [expect](const char* s){
                                  printf("[failed] expected %s, but got %s\n", expect, s);
                                });
}

int main(){
  install_builtin();

  check("(list 1)", "(1)");
  check("(list 1 2)", "(1 2)");
  check("(list 1 2 3)", "(1 2 3)");

  check("(list* 1)", "1");
  check("(list* 1 2)", "(1 . 2)");
  check("(list* 1 2 3)", "(1 2 . 3)");

  check("(vector 1)", "#(1)");
  check("(vector 1 2)", "#(1 2)");
  check("(vector 1 2 3)", "#(1 2 3)");

  check("(and)", "#t");
  check("(and 1)", "1");
  check("(and 1 2)", "2");
  check("(and #f 2)", "#f");
  check("(and 1 #f 3)", "#f");
  check("(and #t #t 3)", "3");

  check("(or)", "#f");
  check("(or 1)", "1");
  check("(or #f 2)", "2");
  check("(or #f #f 3)", "3");
  check("(or 1 #f 3)", "1");
  check("(or #f 2 #f 4)", "2");

  //check("(let () 100)", "100");
  //check("(let (x) x)", "()");
  check("(let ((x 1) (y 2) (z 3)) x)", "1");
  check("(let ((x 1) (y 2) (z 3)) y)", "2");
  check("(let ((x 1) (y 2) (z 3)) z)", "3");
  check("(let ((x 1)) (let ((x 2)) x))", "2");
  check("(let ((x 1)) (let ((x 2)) x) x)", "1");

  check("(let* ((x 1)) x)", "1");
  check("(let* ((x 1) (y x)) y)", "1");
  check("(let* ((x 1) (y x) (z y)) z)", "1");
  check("(let* ((x 1)) (let ((x 2)) x))", "2");
  check("(let* ((x 1)) (let ((x 2)) x) x)", "1");

  check("(letrec ((x 1)) x)", "1");
  check("(letrec ((x 1) (y 2)) y)", "2");
  check("(letrec ((x 1) (y 2) (z 3)) z)", "3");
  check("(letrec ((x 1)) (let ((x 2)) x))", "2");
  check("(letrec ((x 1)) (let ((x 2)) x) x)", "1");

  check("(cond ((eqv? 1 1) 1))", "1");
  check("(cond ((eqv? 1 2) xxx) ((eqv? 2 3) yyy) ((eqv? 3 3) 3))", "3");
  check("(cond ((eqv? 1 2) xxx) ((eqv? 2 3) yyy) (else 3))", "3");
  check("(cond ((eqv? 1 2)) ((eqv? 2 3) fuga) ((+ 5 7)))", "12");

  //check("(case 1 ((1 3 5) 'odd) ((2 4 6) 'even))", "odd");

  check("(eval 1 ())", "1");

  return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}

<commit_msg>added eval test case<commit_after>#include <cstdlib>
#include <cassert>

#include "zs.hh"
#include "test_util.hh"

static bool result = true;

void check(const char* input, const char* expect){
  result = read_eval_print_test(input, expect,
                                [expect](const char* s){
                                  printf("[failed] expected %s, but got %s\n", expect, s);
                                });
}

int main(){
  install_builtin();

  check("(list 1)", "(1)");
  check("(list 1 2)", "(1 2)");
  check("(list 1 2 3)", "(1 2 3)");

  check("(list* 1)", "1");
  check("(list* 1 2)", "(1 . 2)");
  check("(list* 1 2 3)", "(1 2 . 3)");

  check("(vector 1)", "#(1)");
  check("(vector 1 2)", "#(1 2)");
  check("(vector 1 2 3)", "#(1 2 3)");

  check("(and)", "#t");
  check("(and 1)", "1");
  check("(and 1 2)", "2");
  check("(and #f 2)", "#f");
  check("(and 1 #f 3)", "#f");
  check("(and #t #t 3)", "3");

  check("(or)", "#f");
  check("(or 1)", "1");
  check("(or #f 2)", "2");
  check("(or #f #f 3)", "3");
  check("(or 1 #f 3)", "1");
  check("(or #f 2 #f 4)", "2");

  //check("(let () 100)", "100");
  //check("(let (x) x)", "()");
  check("(let ((x 1) (y 2) (z 3)) x)", "1");
  check("(let ((x 1) (y 2) (z 3)) y)", "2");
  check("(let ((x 1) (y 2) (z 3)) z)", "3");
  check("(let ((x 1)) (let ((x 2)) x))", "2");
  check("(let ((x 1)) (let ((x 2)) x) x)", "1");

  check("(let* ((x 1)) x)", "1");
  check("(let* ((x 1) (y x)) y)", "1");
  check("(let* ((x 1) (y x) (z y)) z)", "1");
  check("(let* ((x 1)) (let ((x 2)) x))", "2");
  check("(let* ((x 1)) (let ((x 2)) x) x)", "1");

  check("(letrec ((x 1)) x)", "1");
  check("(letrec ((x 1) (y 2)) y)", "2");
  check("(letrec ((x 1) (y 2) (z 3)) z)", "3");
  check("(letrec ((x 1)) (let ((x 2)) x))", "2");
  check("(letrec ((x 1)) (let ((x 2)) x) x)", "1");

  check("(cond ((eqv? 1 1) 1))", "1");
  check("(cond ((eqv? 1 2) xxx) ((eqv? 2 3) yyy) ((eqv? 3 3) 3))", "3");
  check("(cond ((eqv? 1 2) xxx) ((eqv? 2 3) yyy) (else 3))", "3");
  check("(cond ((eqv? 1 2)) ((eqv? 2 3) fuga) ((+ 5 7)))", "12");

  //check("(case 1 ((1 3 5) 'odd) ((2 4 6) 'even))", "odd");

  check("(eval 1 ())", "1");
  check("(eval (+ 1 3) ())", "4");
  check("(eval '(+ 1 3) ())", "4");
  check("(eval '(if (eqv? 1 2) \"same\" \"different\") ())", "\"different\"");

  return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}

<|endoftext|>


<commit_before>//===-- ValueSymbolTable.cpp - Implement the ValueSymbolTable class -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group.  It is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ValueSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "valuesymtab"
#include "llvm/GlobalValue.h"
#include "llvm/Type.h"
#include "llvm/ValueSymbolTable.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include <algorithm>
using namespace llvm;

// Class destructor
ValueSymbolTable::~ValueSymbolTable() {
#ifndef NDEBUG   // Only do this in -g mode...
  bool LeftoverValues = true;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ++VI)
    if (!isa<Constant>(VI->second) ) {
      DEBUG(DOUT << "Value still in symbol table! Type = '"
           << VI->second->getType()->getDescription() << "' Name = '"
           << VI->first << "'\n");
      LeftoverValues = false;
    }
  assert(LeftoverValues && "Values remain in symbol table!");
#endif
}

// getUniqueName - Given a base name, return a string that is either equal to
// it (or derived from it) that does not already occur in the symbol table for
// the specified type.
//
std::string ValueSymbolTable::getUniqueName(const std::string &BaseName) const {
  std::string TryName = BaseName;
  const_iterator End = vmap.end();

  // See if the name exists
  while (vmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a value - Returns null on failure...
//
Value *ValueSymbolTable::lookup(const std::string &Name) const {
  const_iterator VI = vmap.find(Name);
  if (VI != vmap.end())                   // We found the symbol
    return const_cast<Value*>(VI->second);
  return 0;
}

// Strip the symbol table of its names.
//
bool ValueSymbolTable::strip() {
  bool RemovedSymbol = false;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ) {
    Value *V = VI->second;
    ++VI;
    if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasInternalLinkage()) {
      // Set name to "", removing from symbol table!
      V->setName("");
      RemovedSymbol = true;
    }
  }
  return RemovedSymbol;
}

// Insert a value into the symbol table with the specified name...
//
void ValueSymbolTable::insert(Value* V) {
  assert(V && "Can't insert null Value into symbol table!");
  assert(V->hasName() && "Can't insert nameless Value into symbol table");

  // Check to see if there is a naming conflict.  If so, rename this value
  std::string UniqueName = getUniqueName(V->getName());

  DEBUG(DOUT << " Inserting value: " << UniqueName << ": " << *V << "\n");

  // Insert the vmap entry
  V->Name = UniqueName;
  vmap.insert(make_pair(V->Name, V));
}

// Remove a value
bool ValueSymbolTable::remove(Value *V) {
  assert(V->hasName() && "Value doesn't have name!");
  iterator Entry = vmap.find(V->getName());
  if (Entry == vmap.end())
    return false;

  DEBUG(DOUT << " Removing Value: " << Entry->second->getName() << "\n");

  // Remove the value from the plane...
  vmap.erase(Entry);
  return true;
}

// rename - Given a value with a non-empty name, remove its existing entry
// from the symbol table and insert a new one for Name.  This is equivalent to
// doing "remove(V), V->Name = Name, insert(V)",
//
bool ValueSymbolTable::rename(Value *V, const std::string &name) {
  assert(V && "Can't rename a null Value");
  assert(V->hasName() && "Can't rename a nameless Value");
  assert(!V->getName().empty() && "Can't rename an Value with null name");
  assert(V->getName() != name && "Can't rename a Value with same name");
  assert(!name.empty() && "Can't rename a named Value with a null name");

  // Find the name
  iterator VI = vmap.find(V->getName());

  // If we didn't find it, we're done
  if (VI == vmap.end())
    return false;

  // Remove the old entry.
  vmap.erase(VI);

  // See if we can insert the new name.
  VI = vmap.lower_bound(name);

  // Is there a naming conflict?
  if (VI != vmap.end() && VI->first == name) {
    V->Name = getUniqueName( name);
    vmap.insert(make_pair(V->Name, V));
  } else {
    V->Name = name;
    vmap.insert(VI, make_pair(V->Name, V));
  }

  return true;
}

// DumpVal - a std::for_each function for dumping a value
//
static void DumpVal(const std::pair<const std::string, Value *> &V) {
  DOUT << "  '" << V.first << "' = ";
  V.second->dump();
  DOUT << "\n";
}

// dump - print out the symbol table
//
void ValueSymbolTable::dump() const {
  DOUT << "ValueSymbolTable:\n";
  for_each(vmap.begin(), vmap.end(), DumpVal);
}
<commit_msg>Eliminate a bunch of work from ValueSymbolTable::insert for the common case where a symbol name doesn't conflict.  This speeds up bc reading 16% on 176.gcc!<commit_after>//===-- ValueSymbolTable.cpp - Implement the ValueSymbolTable class -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group.  It is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the ValueSymbolTable class for the VMCore library.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "valuesymtab"
#include "llvm/GlobalValue.h"
#include "llvm/Type.h"
#include "llvm/ValueSymbolTable.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include <algorithm>
using namespace llvm;

// Class destructor
ValueSymbolTable::~ValueSymbolTable() {
#ifndef NDEBUG   // Only do this in -g mode...
  bool LeftoverValues = true;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ++VI)
    if (!isa<Constant>(VI->second) ) {
      DEBUG(DOUT << "Value still in symbol table! Type = '"
           << VI->second->getType()->getDescription() << "' Name = '"
           << VI->first << "'\n");
      LeftoverValues = false;
    }
  assert(LeftoverValues && "Values remain in symbol table!");
#endif
}

// getUniqueName - Given a base name, return a string that is either equal to
// it (or derived from it) that does not already occur in the symbol table for
// the specified type.
//
std::string ValueSymbolTable::getUniqueName(const std::string &BaseName) const {
  std::string TryName = BaseName;
  const_iterator End = vmap.end();

  // See if the name exists
  while (vmap.find(TryName) != End)            // Loop until we find a free
    TryName = BaseName + utostr(++LastUnique); // name in the symbol table
  return TryName;
}

// lookup a value - Returns null on failure...
//
Value *ValueSymbolTable::lookup(const std::string &Name) const {
  const_iterator VI = vmap.find(Name);
  if (VI != vmap.end())                   // We found the symbol
    return const_cast<Value*>(VI->second);
  return 0;
}

// Strip the symbol table of its names.
//
bool ValueSymbolTable::strip() {
  bool RemovedSymbol = false;
  for (iterator VI = vmap.begin(), VE = vmap.end(); VI != VE; ) {
    Value *V = VI->second;
    ++VI;
    if (!isa<GlobalValue>(V) || cast<GlobalValue>(V)->hasInternalLinkage()) {
      // Set name to "", removing from symbol table!
      V->setName("");
      RemovedSymbol = true;
    }
  }
  return RemovedSymbol;
}

// Insert a value into the symbol table with the specified name...
//
void ValueSymbolTable::insert(Value* V) {
  assert(V && "Can't insert null Value into symbol table!");
  assert(V->hasName() && "Can't insert nameless Value into symbol table");

  // Try inserting the name, assuming it won't conflict.
  if (vmap.insert(make_pair(V->Name, V)).second) {
    DOUT << " Inserted value: " << V->Name << ": " << *V << "\n";
    return;
  }

  // Otherwise, there is a naming conflict.  Rename this value.
  std::string UniqueName = getUniqueName(V->getName());

  DEBUG(DOUT << " Inserting value: " << UniqueName << ": " << *V << "\n");

  // Insert the vmap entry
  V->Name = UniqueName;
  vmap.insert(make_pair(V->Name, V));
}

// Remove a value
bool ValueSymbolTable::remove(Value *V) {
  assert(V->hasName() && "Value doesn't have name!");
  iterator Entry = vmap.find(V->getName());
  if (Entry == vmap.end())
    return false;

  DEBUG(DOUT << " Removing Value: " << Entry->second->getName() << "\n");

  // Remove the value from the plane...
  vmap.erase(Entry);
  return true;
}

// rename - Given a value with a non-empty name, remove its existing entry
// from the symbol table and insert a new one for Name.  This is equivalent to
// doing "remove(V), V->Name = Name, insert(V)",
//
bool ValueSymbolTable::rename(Value *V, const std::string &name) {
  assert(V && "Can't rename a null Value");
  assert(V->hasName() && "Can't rename a nameless Value");
  assert(!V->getName().empty() && "Can't rename an Value with null name");
  assert(V->getName() != name && "Can't rename a Value with same name");
  assert(!name.empty() && "Can't rename a named Value with a null name");

  // Find the name
  iterator VI = vmap.find(V->getName());

  // If we didn't find it, we're done
  if (VI == vmap.end())
    return false;

  // Remove the old entry.
  vmap.erase(VI);

  // See if we can insert the new name.
  VI = vmap.lower_bound(name);

  // Is there a naming conflict?
  if (VI != vmap.end() && VI->first == name) {
    V->Name = getUniqueName( name);
    vmap.insert(make_pair(V->Name, V));
  } else {
    V->Name = name;
    vmap.insert(VI, make_pair(V->Name, V));
  }

  return true;
}

// DumpVal - a std::for_each function for dumping a value
//
static void DumpVal(const std::pair<const std::string, Value *> &V) {
  DOUT << "  '" << V.first << "' = ";
  V.second->dump();
  DOUT << "\n";
}

// dump - print out the symbol table
//
void ValueSymbolTable::dump() const {
  DOUT << "ValueSymbolTable:\n";
  for_each(vmap.begin(), vmap.end(), DumpVal);
}
<|endoftext|>