<commit_before>
#include <gainput/gainput.h>
#include <gainput/GainputDebugRenderer.h>

#include "GainputInputDeviceTouchImpl.h"
#include "GainputTouchInfo.h"
#include "../GainputInputDeltaState.h"
#include "../GainputHelpers.h"
#include "../GainputLog.h"

#include "GainputInputDeviceTouchNull.h"

#if defined(GAINPUT_PLATFORM_ANDROID)
	#include "GainputInputDeviceTouchAndroid.h"
#elif defined(GAINPUT_PLATFORM_IOS)
	#include "GainputInputDeviceTouchIos.h"
#endif

namespace gainput
{

InputDeviceTouch::InputDeviceTouch(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
	InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_TOUCH) : 0),
	impl_(0)
{
	state_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), TouchPointCount*TouchDataElems);
	GAINPUT_ASSERT(state_);
	previousState_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), TouchPointCount*TouchDataElems);
	GAINPUT_ASSERT(previousState_);

#if defined(GAINPUT_PLATFORM_ANDROID)
	if (variant != DV_NULL)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplAndroid>(manager, *this, *state_, *previousState_);
	}
#elif defined(GAINPUT_PLATFORM_IOS)
	if (variant != DV_NULL)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplIos>(manager, *this, *state_, *previousState_);
	}
#endif

	if (!impl_)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplNull>(manager, *this);
	}
	GAINPUT_ASSERT(impl_);
}

InputDeviceTouch::~InputDeviceTouch()
{
	manager_.GetAllocator().Delete(state_);
	manager_.GetAllocator().Delete(previousState_);
	manager_.GetAllocator().Delete(impl_);
}

void
InputDeviceTouch::InternalUpdate(InputDeltaState* delta)
{
	impl_->Update(delta);

	if ((manager_.IsDebugRenderingEnabled() || IsDebugRenderingEnabled())
		&& manager_.GetDebugRenderer())
	{
		DebugRenderer* debugRenderer = manager_.GetDebugRenderer();
		InputState* state = GetInputState();

		for (unsigned i = 0; i < TouchPointCount; ++i)
		{
			if (state->GetBool(Touch0Down + i*4))
			{
				const float x = state->GetFloat(Touch0X + i*4);
				const float y = state->GetFloat(Touch0Y + i*4);
				debugRenderer->DrawCircle(x, y, 0.03f);
			}
		}
	}
}

InputDevice::DeviceState
InputDeviceTouch::InternalGetState() const
{
	return impl_->GetState();
}

InputDevice::DeviceVariant
InputDeviceTouch::GetVariant() const
{
	return impl_->GetVariant();
}

size_t
InputDeviceTouch::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
{
	GAINPUT_ASSERT(outButtons);
	GAINPUT_ASSERT(maxButtonCount > 0);
	return CheckAllButtonsDown(outButtons, maxButtonCount, Touch0Down, TouchCount_);
}

size_t
InputDeviceTouch::GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const
{
	GAINPUT_ASSERT(IsValidButtonId(deviceButton));
	GAINPUT_ASSERT(buffer);
	GAINPUT_ASSERT(bufferLength > 0);
	strncpy(buffer, deviceButtonInfos[deviceButton].name, bufferLength);
	buffer[bufferLength-1] = 0;
	const size_t nameLen = strlen(deviceButtonInfos[deviceButton].name);
	return nameLen >= bufferLength ? bufferLength : nameLen+1;
}

ButtonType
InputDeviceTouch::GetButtonType(DeviceButtonId deviceButton) const
{
	GAINPUT_ASSERT(IsValidButtonId(deviceButton));
	return deviceButtonInfos[deviceButton].type;
}

DeviceButtonId
InputDeviceTouch::GetButtonByName(const char* name) const
{
	GAINPUT_ASSERT(name);
	for (unsigned i = 0; i < TouchPointCount*TouchDataElems; ++i)
	{
		if (strcmp(name, deviceButtonInfos[i].name) == 0)
		{
			return DeviceButtonId(i);
		}
	}
	return InvalidDeviceButtonId;
}

}

<commit_msg>Uncommented variant to fix compilation on Android and iOS.<commit_after>
#include <gainput/gainput.h>
#include <gainput/GainputDebugRenderer.h>

#include "GainputInputDeviceTouchImpl.h"
#include "GainputTouchInfo.h"
#include "../GainputInputDeltaState.h"
#include "../GainputHelpers.h"
#include "../GainputLog.h"

#include "GainputInputDeviceTouchNull.h"

#if defined(GAINPUT_PLATFORM_ANDROID)
	#include "GainputInputDeviceTouchAndroid.h"
#elif defined(GAINPUT_PLATFORM_IOS)
	#include "GainputInputDeviceTouchIos.h"
#endif

namespace gainput
{

InputDeviceTouch::InputDeviceTouch(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant) :
	InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_TOUCH) : 0),
	impl_(0)
{
	state_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), TouchPointCount*TouchDataElems);
	GAINPUT_ASSERT(state_);
	previousState_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), TouchPointCount*TouchDataElems);
	GAINPUT_ASSERT(previousState_);

#if defined(GAINPUT_PLATFORM_ANDROID)
	if (variant != DV_NULL)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplAndroid>(manager, *this, *state_, *previousState_);
	}
#elif defined(GAINPUT_PLATFORM_IOS)
	if (variant != DV_NULL)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplIos>(manager, *this, *state_, *previousState_);
	}
#endif

	if (!impl_)
	{
		impl_ = manager.GetAllocator().New<InputDeviceTouchImplNull>(manager, *this);
	}
	GAINPUT_ASSERT(impl_);
}

InputDeviceTouch::~InputDeviceTouch()
{
	manager_.GetAllocator().Delete(state_);
	manager_.GetAllocator().Delete(previousState_);
	manager_.GetAllocator().Delete(impl_);
}

void
InputDeviceTouch::InternalUpdate(InputDeltaState* delta)
{
	impl_->Update(delta);

	if ((manager_.IsDebugRenderingEnabled() || IsDebugRenderingEnabled())
		&& manager_.GetDebugRenderer())
	{
		DebugRenderer* debugRenderer = manager_.GetDebugRenderer();
		InputState* state = GetInputState();

		for (unsigned i = 0; i < TouchPointCount; ++i)
		{
			if (state->GetBool(Touch0Down + i*4))
			{
				const float x = state->GetFloat(Touch0X + i*4);
				const float y = state->GetFloat(Touch0Y + i*4);
				debugRenderer->DrawCircle(x, y, 0.03f);
			}
		}
	}
}

InputDevice::DeviceState
InputDeviceTouch::InternalGetState() const
{
	return impl_->GetState();
}

InputDevice::DeviceVariant
InputDeviceTouch::GetVariant() const
{
	return impl_->GetVariant();
}

size_t
InputDeviceTouch::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
{
	GAINPUT_ASSERT(outButtons);
	GAINPUT_ASSERT(maxButtonCount > 0);
	return CheckAllButtonsDown(outButtons, maxButtonCount, Touch0Down, TouchCount_);
}

size_t
InputDeviceTouch::GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const
{
	GAINPUT_ASSERT(IsValidButtonId(deviceButton));
	GAINPUT_ASSERT(buffer);
	GAINPUT_ASSERT(bufferLength > 0);
	strncpy(buffer, deviceButtonInfos[deviceButton].name, bufferLength);
	buffer[bufferLength-1] = 0;
	const size_t nameLen = strlen(deviceButtonInfos[deviceButton].name);
	return nameLen >= bufferLength ? bufferLength : nameLen+1;
}

ButtonType
InputDeviceTouch::GetButtonType(DeviceButtonId deviceButton) const
{
	GAINPUT_ASSERT(IsValidButtonId(deviceButton));
	return deviceButtonInfos[deviceButton].type;
}

DeviceButtonId
InputDeviceTouch::GetButtonByName(const char* name) const
{
	GAINPUT_ASSERT(name);
	for (unsigned i = 0; i < TouchPointCount*TouchDataElems; ++i)
	{
		if (strcmp(name, deviceButtonInfos[i].name) == 0)
		{
			return DeviceButtonId(i);
		}
	}
	return InvalidDeviceButtonId;
}

}

<|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/gpu/compositor_util.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info.h"
#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/public/common/content_switches.h"
#include "gpu/config/gpu_feature_type.h"

namespace content {

namespace {

static bool IsGpuRasterizationBlacklisted() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  return manager->IsFeatureBlacklisted(
        gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION);
}

const char* kGpuCompositingFeatureName = "gpu_compositing";
const char* kWebGLFeatureName = "webgl";
const char* kRasterizationFeatureName = "rasterization";
const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";

const int kMinRasterThreads = 1;
const int kMaxRasterThreads = 4;

const int kMinMSAASampleCount = 0;

struct GpuFeatureInfo {
  std::string name;
  bool blocked;
  bool disabled;
  std::string disabled_description;
  bool fallback_to_software;
};

const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();

  const GpuFeatureInfo kGpuFeatureInfo[] = {
      {
          "2d_canvas",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
          command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) ||
          !GpuDataManagerImpl::GetInstance()->
              GetGPUInfo().SupportsAccelerated2dCanvas(),
          "Accelerated 2D canvas is unavailable: either disabled at the command"
          " line or not supported by the current system.",
          true
      },
      {
          kGpuCompositingFeatureName,
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING),
          command_line.HasSwitch(switches::kDisableGpuCompositing),
          "Gpu compositing has been disabled, either via about:flags or"
          " command line. The browser will fall back to software compositing"
          " and hardware acceleration will be unavailable.",
          true
      },
      {
          kWebGLFeatureName,
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL),
          command_line.HasSwitch(switches::kDisableExperimentalWebGL),
          "WebGL has been disabled, either via about:flags or command line.",
          false
      },
      {
          "flash_3d",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D),
          command_line.HasSwitch(switches::kDisableFlash3d),
          "Using 3d in flash has been disabled, either via about:flags or"
          " command line.",
          true
      },
      {
          "flash_stage3d",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
          command_line.HasSwitch(switches::kDisableFlashStage3d),
          "Using Stage3d in Flash has been disabled, either via about:flags or"
          " command line.",
          true
      },
      {
          "flash_stage3d_baseline",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE) ||
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
          command_line.HasSwitch(switches::kDisableFlashStage3d),
          "Using Stage3d Baseline profile in Flash has been disabled, either"
          " via about:flags or command line.",
          true
      },
      {
          "video_decode",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
          command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
          "Accelerated video decode has been disabled, either via about:flags"
          " or command line.",
          true
      },
#if defined(ENABLE_WEBRTC)
      {
          "video_encode",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE),
          command_line.HasSwitch(switches::kDisableWebRtcHWEncoding),
          "Accelerated video encode has been disabled, either via about:flags"
          " or command line.",
          true
      },
#endif
#if defined(OS_CHROMEOS)
      {
          "panel_fitting",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_PANEL_FITTING),
          command_line.HasSwitch(switches::kDisablePanelFitting),
          "Panel fitting has been disabled, either via about:flags or command"
          " line.",
          false
      },
#endif
      {
          kRasterizationFeatureName,
          IsGpuRasterizationBlacklisted() &&
          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled(),
          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled() &&
          !IsGpuRasterizationBlacklisted(),
          "Accelerated rasterization has been disabled, either via about:flags"
          " or command line.",
          true
      },
      {
          kMultipleRasterThreadsFeatureName,
          false,
          NumberOfRendererRasterThreads() == 1,
          "Raster is using a single thread.",
          false
      },
  };
  DCHECK(index < arraysize(kGpuFeatureInfo));
  *eof = (index == arraysize(kGpuFeatureInfo) - 1);
  return kGpuFeatureInfo[index];
}

}  // namespace

bool IsPropertyTreeVerificationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  return command_line.HasSwitch(cc::switches::kEnablePropertyTreeVerification);
}

bool IsDelegatedRendererEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  bool enabled = false;

#if defined(USE_AURA) || defined(OS_MACOSX)
  // Enable on Aura and Mac.
  enabled = true;
#endif

  // Flags override.
  enabled |= command_line.HasSwitch(switches::kEnableDelegatedRenderer);
  enabled &= !command_line.HasSwitch(switches::kDisableDelegatedRenderer);
  return enabled;
}

int NumberOfRendererRasterThreads() {
  int num_processors = base::SysInfo::NumberOfProcessors();

#if defined(OS_ANDROID)
  // Android may report 6 to 8 CPUs for big.LITTLE configurations.
  // Limit the number of raster threads based on maximum of 4 big cores.
  num_processors = std::min(num_processors, 4);
#endif

  int num_raster_threads = num_processors / 2;

  // Async uploads is used when neither zero-copy nor one-copy is enabled and
  // it uses its own thread, so reduce the number of raster threads when async
  // uploads is in use.
  bool async_uploads_is_used =
      !IsZeroCopyUploadEnabled() && !IsOneCopyUploadEnabled();
  if (async_uploads_is_used)
    --num_raster_threads;

#if defined(OS_ANDROID)
  // Limit the number of raster threads to 1 on Android.
  // TODO(reveman): Remove this when we have a better mechanims to prevent
  // pre-paint raster work from slowing down non-raster work. crbug.com/504515
  num_raster_threads = 1;
#endif

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (command_line.HasSwitch(switches::kNumRasterThreads)) {
    std::string string_value = command_line.GetSwitchValueASCII(
        switches::kNumRasterThreads);
    if (!base::StringToInt(string_value, &num_raster_threads)) {
      DLOG(WARNING) << "Failed to parse switch " <<
          switches::kNumRasterThreads  << ": " << string_value;
    }
  }

  return cc::MathUtil::ClampToRange(num_raster_threads, kMinRasterThreads,
                                    kMaxRasterThreads);
}

bool IsOneCopyUploadEnabled() {
  if (IsZeroCopyUploadEnabled())
    return false;

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kEnableOneCopy))
    return true;
  if (command_line.HasSwitch(switches::kDisableOneCopy))
    return false;

#if defined(OS_ANDROID)
  return false;
#endif
  return true;
}

bool IsZeroCopyUploadEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  // Single-threaded mode in the renderer process (for layout tests) is
  // synchronous, which depends on tiles being ready to draw when raster is
  // complete.  Therefore, it must use one of zero copy, software raster, or
  // GPU raster. So we force zero-copy on for the case where software/GPU raster
  // is not used.
  // TODO(reveman): One-copy can work with sync compositing: crbug.com/490295.
  if (command_line.HasSwitch(switches::kDisableThreadedCompositing))
    return true;
  return command_line.HasSwitch(switches::kEnableZeroCopy);
}

bool IsGpuRasterizationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (command_line.HasSwitch(switches::kDisableGpuRasterization))
    return false;
  else if (command_line.HasSwitch(switches::kEnableGpuRasterization))
    return true;

  if (IsGpuRasterizationBlacklisted()) {
    return false;
  }

#if defined(OS_ANDROID)
  return true;
#endif

  // explicitly disable GPU rasterization on all non-android devices until we
  // have full test coverage.
  return false;
}

bool IsForceGpuRasterizationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  return command_line.HasSwitch(switches::kForceGpuRasterization);
}

bool UseSurfacesEnabled() {
#if defined(OS_ANDROID)
  return false;
#endif
  bool enabled = false;
#if defined(USE_AURA) || defined(OS_MACOSX)
  enabled = true;
#endif

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  // Flags override.
  enabled |= command_line.HasSwitch(switches::kUseSurfaces);
  enabled &= !command_line.HasSwitch(switches::kDisableSurfaces);
  return enabled;
}

int GpuRasterizationMSAASampleCount() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (!command_line.HasSwitch(switches::kGpuRasterizationMSAASampleCount))
#if defined(OS_ANDROID)
    return 4;
#else
    return 8;
#endif
  std::string string_value = command_line.GetSwitchValueASCII(
      switches::kGpuRasterizationMSAASampleCount);
  int msaa_sample_count = 0;
  if (base::StringToInt(string_value, &msaa_sample_count) &&
      msaa_sample_count >= kMinMSAASampleCount) {
    return msaa_sample_count;
  } else {
    DLOG(WARNING) << "Failed to parse switch "
                  << switches::kGpuRasterizationMSAASampleCount << ": "
                  << string_value;
    return 0;
  }
}

base::DictionaryValue* GetFeatureStatus() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  std::string gpu_access_blocked_reason;
  bool gpu_access_blocked =
      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);

  base::DictionaryValue* feature_status_dict = new base::DictionaryValue();

  bool eof = false;
  for (size_t i = 0; !eof; ++i) {
    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
    std::string status;
    if (gpu_feature_info.disabled) {
      status = "disabled";
      if (gpu_feature_info.fallback_to_software)
        status += "_software";
      else
        status += "_off";
    } else if (gpu_feature_info.blocked ||
               gpu_access_blocked) {
      status = "unavailable";
      if (gpu_feature_info.fallback_to_software)
        status += "_software";
      else
        status += "_off";
    } else {
      status = "enabled";
      if (gpu_feature_info.name == kWebGLFeatureName &&
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
        status += "_readback";
      if (gpu_feature_info.name == kRasterizationFeatureName) {
        if (IsForceGpuRasterizationEnabled())
          status += "_force";
      }
      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName) {
        const base::CommandLine& command_line =
            *base::CommandLine::ForCurrentProcess();
        if (command_line.HasSwitch(switches::kNumRasterThreads))
          status += "_force";
      }
      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
        status += "_on";
    }
    if (gpu_feature_info.name == kWebGLFeatureName &&
        (gpu_feature_info.blocked || gpu_access_blocked) &&
        manager->ShouldUseSwiftShader()) {
      status = "unavailable_software";
    }

    feature_status_dict->SetString(
        gpu_feature_info.name.c_str(), status.c_str());
  }
  return feature_status_dict;
}

base::Value* GetProblems() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  std::string gpu_access_blocked_reason;
  bool gpu_access_blocked =
      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);

  base::ListValue* problem_list = new base::ListValue();
  manager->GetBlacklistReasons(problem_list);

  if (gpu_access_blocked) {
    base::DictionaryValue* problem = new base::DictionaryValue();
    problem->SetString("description",
        "GPU process was unable to boot: " + gpu_access_blocked_reason);
    problem->Set("crBugs", new base::ListValue());
    problem->Set("webkitBugs", new base::ListValue());
    base::ListValue* disabled_features = new base::ListValue();
    disabled_features->AppendString("all");
    problem->Set("affectedGpuSettings", disabled_features);
    problem->SetString("tag", "disabledFeatures");
    problem_list->Insert(0, problem);
  }

  bool eof = false;
  for (size_t i = 0; !eof; ++i) {
    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
    if (gpu_feature_info.disabled) {
      base::DictionaryValue* problem = new base::DictionaryValue();
      problem->SetString(
          "description", gpu_feature_info.disabled_description);
      problem->Set("crBugs", new base::ListValue());
      problem->Set("webkitBugs", new base::ListValue());
      base::ListValue* disabled_features = new base::ListValue();
      disabled_features->AppendString(gpu_feature_info.name);
      problem->Set("affectedGpuSettings", disabled_features);
      problem->SetString("tag", "disabledFeatures");
      problem_list->Append(problem);
    }
  }
  return problem_list;
}

std::vector<std::string> GetDriverBugWorkarounds() {
  return GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds();
}

}  // namespace content
<commit_msg>Enable surfaces on Android (try #6).<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/gpu/compositor_util.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info.h"
#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/public/common/content_switches.h"
#include "gpu/config/gpu_feature_type.h"

namespace content {

namespace {

static bool IsGpuRasterizationBlacklisted() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  return manager->IsFeatureBlacklisted(
        gpu::GPU_FEATURE_TYPE_GPU_RASTERIZATION);
}

const char* kGpuCompositingFeatureName = "gpu_compositing";
const char* kWebGLFeatureName = "webgl";
const char* kRasterizationFeatureName = "rasterization";
const char* kMultipleRasterThreadsFeatureName = "multiple_raster_threads";

const int kMinRasterThreads = 1;
const int kMaxRasterThreads = 4;

const int kMinMSAASampleCount = 0;

struct GpuFeatureInfo {
  std::string name;
  bool blocked;
  bool disabled;
  std::string disabled_description;
  bool fallback_to_software;
};

const GpuFeatureInfo GetGpuFeatureInfo(size_t index, bool* eof) {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();

  const GpuFeatureInfo kGpuFeatureInfo[] = {
      {
          "2d_canvas",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS),
          command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) ||
          !GpuDataManagerImpl::GetInstance()->
              GetGPUInfo().SupportsAccelerated2dCanvas(),
          "Accelerated 2D canvas is unavailable: either disabled at the command"
          " line or not supported by the current system.",
          true
      },
      {
          kGpuCompositingFeatureName,
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING),
          command_line.HasSwitch(switches::kDisableGpuCompositing),
          "Gpu compositing has been disabled, either via about:flags or"
          " command line. The browser will fall back to software compositing"
          " and hardware acceleration will be unavailable.",
          true
      },
      {
          kWebGLFeatureName,
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL),
          command_line.HasSwitch(switches::kDisableExperimentalWebGL),
          "WebGL has been disabled, either via about:flags or command line.",
          false
      },
      {
          "flash_3d",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH3D),
          command_line.HasSwitch(switches::kDisableFlash3d),
          "Using 3d in flash has been disabled, either via about:flags or"
          " command line.",
          true
      },
      {
          "flash_stage3d",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
          command_line.HasSwitch(switches::kDisableFlashStage3d),
          "Using Stage3d in Flash has been disabled, either via about:flags or"
          " command line.",
          true
      },
      {
          "flash_stage3d_baseline",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE) ||
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_FLASH_STAGE3D),
          command_line.HasSwitch(switches::kDisableFlashStage3d),
          "Using Stage3d Baseline profile in Flash has been disabled, either"
          " via about:flags or command line.",
          true
      },
      {
          "video_decode",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE),
          command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode),
          "Accelerated video decode has been disabled, either via about:flags"
          " or command line.",
          true
      },
#if defined(ENABLE_WEBRTC)
      {
          "video_encode",
          manager->IsFeatureBlacklisted(
              gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_ENCODE),
          command_line.HasSwitch(switches::kDisableWebRtcHWEncoding),
          "Accelerated video encode has been disabled, either via about:flags"
          " or command line.",
          true
      },
#endif
#if defined(OS_CHROMEOS)
      {
          "panel_fitting",
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_PANEL_FITTING),
          command_line.HasSwitch(switches::kDisablePanelFitting),
          "Panel fitting has been disabled, either via about:flags or command"
          " line.",
          false
      },
#endif
      {
          kRasterizationFeatureName,
          IsGpuRasterizationBlacklisted() &&
          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled(),
          !IsGpuRasterizationEnabled() && !IsForceGpuRasterizationEnabled() &&
          !IsGpuRasterizationBlacklisted(),
          "Accelerated rasterization has been disabled, either via about:flags"
          " or command line.",
          true
      },
      {
          kMultipleRasterThreadsFeatureName,
          false,
          NumberOfRendererRasterThreads() == 1,
          "Raster is using a single thread.",
          false
      },
  };
  DCHECK(index < arraysize(kGpuFeatureInfo));
  *eof = (index == arraysize(kGpuFeatureInfo) - 1);
  return kGpuFeatureInfo[index];
}

}  // namespace

bool IsPropertyTreeVerificationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  return command_line.HasSwitch(cc::switches::kEnablePropertyTreeVerification);
}

bool IsDelegatedRendererEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  bool enabled = false;

#if defined(USE_AURA) || defined(OS_MACOSX)
  // Enable on Aura and Mac.
  enabled = true;
#endif

  // Flags override.
  enabled |= command_line.HasSwitch(switches::kEnableDelegatedRenderer);
  enabled &= !command_line.HasSwitch(switches::kDisableDelegatedRenderer);
  return enabled;
}

int NumberOfRendererRasterThreads() {
  int num_processors = base::SysInfo::NumberOfProcessors();

#if defined(OS_ANDROID)
  // Android may report 6 to 8 CPUs for big.LITTLE configurations.
  // Limit the number of raster threads based on maximum of 4 big cores.
  num_processors = std::min(num_processors, 4);
#endif

  int num_raster_threads = num_processors / 2;

  // Async uploads is used when neither zero-copy nor one-copy is enabled and
  // it uses its own thread, so reduce the number of raster threads when async
  // uploads is in use.
  bool async_uploads_is_used =
      !IsZeroCopyUploadEnabled() && !IsOneCopyUploadEnabled();
  if (async_uploads_is_used)
    --num_raster_threads;

#if defined(OS_ANDROID)
  // Limit the number of raster threads to 1 on Android.
  // TODO(reveman): Remove this when we have a better mechanims to prevent
  // pre-paint raster work from slowing down non-raster work. crbug.com/504515
  num_raster_threads = 1;
#endif

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (command_line.HasSwitch(switches::kNumRasterThreads)) {
    std::string string_value = command_line.GetSwitchValueASCII(
        switches::kNumRasterThreads);
    if (!base::StringToInt(string_value, &num_raster_threads)) {
      DLOG(WARNING) << "Failed to parse switch " <<
          switches::kNumRasterThreads  << ": " << string_value;
    }
  }

  return cc::MathUtil::ClampToRange(num_raster_threads, kMinRasterThreads,
                                    kMaxRasterThreads);
}

bool IsOneCopyUploadEnabled() {
  if (IsZeroCopyUploadEnabled())
    return false;

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  if (command_line.HasSwitch(switches::kEnableOneCopy))
    return true;
  if (command_line.HasSwitch(switches::kDisableOneCopy))
    return false;

#if defined(OS_ANDROID)
  return false;
#endif
  return true;
}

bool IsZeroCopyUploadEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  // Single-threaded mode in the renderer process (for layout tests) is
  // synchronous, which depends on tiles being ready to draw when raster is
  // complete.  Therefore, it must use one of zero copy, software raster, or
  // GPU raster. So we force zero-copy on for the case where software/GPU raster
  // is not used.
  // TODO(reveman): One-copy can work with sync compositing: crbug.com/490295.
  if (command_line.HasSwitch(switches::kDisableThreadedCompositing))
    return true;
  return command_line.HasSwitch(switches::kEnableZeroCopy);
}

bool IsGpuRasterizationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (command_line.HasSwitch(switches::kDisableGpuRasterization))
    return false;
  else if (command_line.HasSwitch(switches::kEnableGpuRasterization))
    return true;

  if (IsGpuRasterizationBlacklisted()) {
    return false;
  }

#if defined(OS_ANDROID)
  return true;
#endif

  // explicitly disable GPU rasterization on all non-android devices until we
  // have full test coverage.
  return false;
}

bool IsForceGpuRasterizationEnabled() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();
  return command_line.HasSwitch(switches::kForceGpuRasterization);
}

bool UseSurfacesEnabled() {
#if defined(OS_ANDROID)
  return true;
#endif
  bool enabled = false;
#if defined(USE_AURA) || defined(OS_MACOSX)
  enabled = true;
#endif

  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  // Flags override.
  enabled |= command_line.HasSwitch(switches::kUseSurfaces);
  enabled &= !command_line.HasSwitch(switches::kDisableSurfaces);
  return enabled;
}

int GpuRasterizationMSAASampleCount() {
  const base::CommandLine& command_line =
      *base::CommandLine::ForCurrentProcess();

  if (!command_line.HasSwitch(switches::kGpuRasterizationMSAASampleCount))
#if defined(OS_ANDROID)
    return 4;
#else
    return 8;
#endif
  std::string string_value = command_line.GetSwitchValueASCII(
      switches::kGpuRasterizationMSAASampleCount);
  int msaa_sample_count = 0;
  if (base::StringToInt(string_value, &msaa_sample_count) &&
      msaa_sample_count >= kMinMSAASampleCount) {
    return msaa_sample_count;
  } else {
    DLOG(WARNING) << "Failed to parse switch "
                  << switches::kGpuRasterizationMSAASampleCount << ": "
                  << string_value;
    return 0;
  }
}

base::DictionaryValue* GetFeatureStatus() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  std::string gpu_access_blocked_reason;
  bool gpu_access_blocked =
      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);

  base::DictionaryValue* feature_status_dict = new base::DictionaryValue();

  bool eof = false;
  for (size_t i = 0; !eof; ++i) {
    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
    std::string status;
    if (gpu_feature_info.disabled) {
      status = "disabled";
      if (gpu_feature_info.fallback_to_software)
        status += "_software";
      else
        status += "_off";
    } else if (gpu_feature_info.blocked ||
               gpu_access_blocked) {
      status = "unavailable";
      if (gpu_feature_info.fallback_to_software)
        status += "_software";
      else
        status += "_off";
    } else {
      status = "enabled";
      if (gpu_feature_info.name == kWebGLFeatureName &&
          manager->IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING))
        status += "_readback";
      if (gpu_feature_info.name == kRasterizationFeatureName) {
        if (IsForceGpuRasterizationEnabled())
          status += "_force";
      }
      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName) {
        const base::CommandLine& command_line =
            *base::CommandLine::ForCurrentProcess();
        if (command_line.HasSwitch(switches::kNumRasterThreads))
          status += "_force";
      }
      if (gpu_feature_info.name == kMultipleRasterThreadsFeatureName)
        status += "_on";
    }
    if (gpu_feature_info.name == kWebGLFeatureName &&
        (gpu_feature_info.blocked || gpu_access_blocked) &&
        manager->ShouldUseSwiftShader()) {
      status = "unavailable_software";
    }

    feature_status_dict->SetString(
        gpu_feature_info.name.c_str(), status.c_str());
  }
  return feature_status_dict;
}

base::Value* GetProblems() {
  GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
  std::string gpu_access_blocked_reason;
  bool gpu_access_blocked =
      !manager->GpuAccessAllowed(&gpu_access_blocked_reason);

  base::ListValue* problem_list = new base::ListValue();
  manager->GetBlacklistReasons(problem_list);

  if (gpu_access_blocked) {
    base::DictionaryValue* problem = new base::DictionaryValue();
    problem->SetString("description",
        "GPU process was unable to boot: " + gpu_access_blocked_reason);
    problem->Set("crBugs", new base::ListValue());
    problem->Set("webkitBugs", new base::ListValue());
    base::ListValue* disabled_features = new base::ListValue();
    disabled_features->AppendString("all");
    problem->Set("affectedGpuSettings", disabled_features);
    problem->SetString("tag", "disabledFeatures");
    problem_list->Insert(0, problem);
  }

  bool eof = false;
  for (size_t i = 0; !eof; ++i) {
    const GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfo(i, &eof);
    if (gpu_feature_info.disabled) {
      base::DictionaryValue* problem = new base::DictionaryValue();
      problem->SetString(
          "description", gpu_feature_info.disabled_description);
      problem->Set("crBugs", new base::ListValue());
      problem->Set("webkitBugs", new base::ListValue());
      base::ListValue* disabled_features = new base::ListValue();
      disabled_features->AppendString(gpu_feature_info.name);
      problem->Set("affectedGpuSettings", disabled_features);
      problem->SetString("tag", "disabledFeatures");
      problem_list->Append(problem);
    }
  }
  return problem_list;
}

std::vector<std::string> GetDriverBugWorkarounds() {
  return GpuDataManagerImpl::GetInstance()->GetDriverBugWorkarounds();
}

}  // namespace content
<|endoftext|>


<commit_before>/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and others contributors as indicated
 * by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
#include "TestAssert.h"
#include "TestSocketSession.h"
#include "btlogger.h"
#include "AtmiBrokerEnv.h"
#include "apr_strings.h"
#include "apr.h"
#include <stdlib.h>

void messagesAvailableCallbackSocket(int bar, bool remove) {

}

static void* APR_THREAD_FUNC run_server(apr_thread_t *thd, void *data) {
	SocketServer* server = (SocketServer*)data;
	btlogger("start server");
	server->run();
	apr_thread_exit(thd, APR_SUCCESS);
	return NULL;
}

static void* APR_THREAD_FUNC run_queue(apr_thread_t *thd, void *data) {
	HybridSocketEndpointQueue* queue = (HybridSocketEndpointQueue*)data;
	btlogger("start queue");
	queue->run();
	apr_thread_exit(thd, APR_SUCCESS);
	return NULL;
}

void TestSocketSession::setUp() {
	btlogger("TestSocketSession::setUp");
	apr_status_t rv;
	apr_pool_create(&mp, NULL);
	server = new SocketServer(port, mp, messagesAvailableCallbackSocket);
	apr_threadattr_create(&thd_attr, mp);
	rv = apr_thread_create(&thead, thd_attr, run_server, (void*)server, mp);
	BT_ASSERT(rv == APR_SUCCESS);

}

void TestSocketSession::tearDown() {
	btlogger("TestSocketSession::tearDown");
	apr_status_t rv;
	server->shutdown();
	btlogger("stop server");
	rv = apr_thread_join(&rv, thead);
	BT_ASSERT(rv == APR_SUCCESS);
	if(server) delete server;
}

void TestSocketSession::test_queue() {
	btlogger("TestSocketSession::test_queue");
	apr_status_t rv;
	client_ctx_t* ctx = server->register_client(1, NULL);
	HybridSocketSessionImpl* session = new HybridSocketSessionImpl(mp);
	HybridSocketEndpointQueue* client_queue = new HybridSocketEndpointQueue(session, mp, ctx, messagesAvailableCallbackSocket);
	HybridSocketEndpointQueue* svc_queue = new HybridSocketEndpointQueue(session, mp, 1, "localhost", port, messagesAvailableCallbackSocket);
	BT_ASSERT(svc_queue->connect());
	apr_thread_t     *queue_thead;
	rv = apr_thread_create(&queue_thead, thd_attr, run_queue, (void*)svc_queue, mp);
	BT_ASSERT(rv == APR_SUCCESS);

	for(int i = 0; i < 10; i++) {
		MESSAGE* msg = (MESSAGE*)apr_pcalloc(mp, sizeof(MESSAGE));
		msg->correlationId = 1;
		msg->replyto = NULL;
		msg->serviceName = NULL;
		msg->type = (char*) "X_OCTET";
		msg->subtype = NULL;
		msg->flags = 0;
		msg->rval = 0;
		msg->rcode = 1;
                msg->schedtime = -1;
		msg->data = new char[8];
		memcpy(msg->data, (char*)"test1234", 8);;
		msg->len = 8;
		BT_ASSERT(svc_queue->send(msg->replyto, msg->rval,
						msg->rcode, msg->data, msg->len,
						msg->correlationId, msg->flags, msg->type,
						msg->subtype));

		MESSAGE message = client_queue->receive(0);
		/*
		btlogger("message.data: %s  message.len: %ld message.rcode: %ld",
				message.data,  message.len, message.rcode);
		*/
		BT_ASSERT(memcmp(message.data, "test1234", message.len) == 0);
		BT_ASSERT(message.correlationId == 1);
		BT_ASSERT(message.len == 8);
		BT_ASSERT(message.rcode == 1);
		BT_ASSERT(message.flags == 0);
		BT_ASSERT(message.rval == 0);
		free(message.data);
		free((char*)message.replyto);
		free(message.type);
		free(message.subtype);

		msg->correlationId = 2;
		msg->rcode = 2;
		msg->data = new char[8];
		memcpy(msg->data, (char*)"test1235", 8);;
		BT_ASSERT(client_queue->send(msg->replyto, msg->rval,
						msg->rcode, msg->data, msg->len,
						msg->correlationId, msg->flags, msg->type,
						msg->subtype));

		message = svc_queue->receive(0);
		/*
		btlogger("message.data: %s message.len: %ld message.rcode: %ld",
				message.data, message.len, message.rcode);
		*/
		BT_ASSERT(memcmp(message.data, "test1235", message.len) == 0);
		BT_ASSERT(message.correlationId == 2);
		BT_ASSERT(message.rcode == 2);
		free(message.data);
		free((char*)message.replyto);
		free(message.type);
		free(message.subtype);
	}

	svc_queue->disconnect();
	server->unregister_client(1);

	rv = apr_thread_join(&rv, queue_thead);
	BT_ASSERT(rv == APR_SUCCESS);
	delete svc_queue;
	delete client_queue;
	delete session;
}

CPPUNIT_TEST_SUITE_REGISTRATION( TestSocketSession);
<commit_msg>TEST CHANGE ONLY: Make sure to null terminate the string<commit_after>/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and others contributors as indicated
 * by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
#include "TestAssert.h"
#include "TestSocketSession.h"
#include "btlogger.h"
#include "AtmiBrokerEnv.h"
#include "apr_strings.h"
#include "apr.h"
#include <stdlib.h>

void messagesAvailableCallbackSocket(int bar, bool remove) {

}

static void* APR_THREAD_FUNC run_server(apr_thread_t *thd, void *data) {
	SocketServer* server = (SocketServer*)data;
	btlogger("start server");
	server->run();
	apr_thread_exit(thd, APR_SUCCESS);
	return NULL;
}

static void* APR_THREAD_FUNC run_queue(apr_thread_t *thd, void *data) {
	HybridSocketEndpointQueue* queue = (HybridSocketEndpointQueue*)data;
	btlogger("start queue");
	queue->run();
	apr_thread_exit(thd, APR_SUCCESS);
	return NULL;
}

void TestSocketSession::setUp() {
	btlogger("TestSocketSession::setUp");
	apr_status_t rv;
	apr_pool_create(&mp, NULL);
	server = new SocketServer(port, mp, messagesAvailableCallbackSocket);
	apr_threadattr_create(&thd_attr, mp);
	rv = apr_thread_create(&thead, thd_attr, run_server, (void*)server, mp);
	BT_ASSERT(rv == APR_SUCCESS);

}

void TestSocketSession::tearDown() {
	btlogger("TestSocketSession::tearDown");
	apr_status_t rv;
	server->shutdown();
	btlogger("stop server");
	rv = apr_thread_join(&rv, thead);
	BT_ASSERT(rv == APR_SUCCESS);
	if(server) delete server;
}

void TestSocketSession::test_queue() {
	btlogger("TestSocketSession::test_queue");
	apr_status_t rv;
	client_ctx_t* ctx = server->register_client(1, NULL);
	HybridSocketSessionImpl* session = new HybridSocketSessionImpl(mp);
	HybridSocketEndpointQueue* client_queue = new HybridSocketEndpointQueue(session, mp, ctx, messagesAvailableCallbackSocket);
	HybridSocketEndpointQueue* svc_queue = new HybridSocketEndpointQueue(session, mp, 1, "localhost", port, messagesAvailableCallbackSocket);
	BT_ASSERT(svc_queue->connect());
	apr_thread_t     *queue_thead;
	rv = apr_thread_create(&queue_thead, thd_attr, run_queue, (void*)svc_queue, mp);
	BT_ASSERT(rv == APR_SUCCESS);

	for(int i = 0; i < 10; i++) {
		MESSAGE* msg = (MESSAGE*)apr_pcalloc(mp, sizeof(MESSAGE));
		msg->correlationId = 1;
		msg->replyto = NULL;
		msg->serviceName = NULL;
		msg->type = (char*) "X_OCTET";
		msg->subtype = NULL;
		msg->flags = 0;
		msg->rval = 0;
		msg->rcode = 1;
                msg->schedtime = -1;
		msg->data = new char[9];
		memset(msg->data, '\0', 9);
		memcpy(msg->data, (char*)"test1234", 8);;
		msg->len = 8;
		BT_ASSERT(svc_queue->send(msg->replyto, msg->rval,
						msg->rcode, msg->data, msg->len,
						msg->correlationId, msg->flags, msg->type,
						msg->subtype));

		MESSAGE message = client_queue->receive(0);
		/*
		btlogger("message.data: %s  message.len: %ld message.rcode: %ld",
				message.data,  message.len, message.rcode);
		*/
		BT_ASSERT(memcmp(message.data, "test1234", message.len) == 0);
		BT_ASSERT(message.correlationId == 1);
		BT_ASSERT(message.len == 8);
		BT_ASSERT(message.rcode == 1);
		BT_ASSERT(message.flags == 0);
		BT_ASSERT(message.rval == 0);
		free(message.data);
		free((char*)message.replyto);
		free(message.type);
		free(message.subtype);

		msg->correlationId = 2;
		msg->rcode = 2;
		msg->data = new char[9];
		memset(msg->data, '\0', 9);
		memcpy(msg->data, (char*)"test1235", 8);;
		BT_ASSERT(client_queue->send(msg->replyto, msg->rval,
						msg->rcode, msg->data, msg->len,
						msg->correlationId, msg->flags, msg->type,
						msg->subtype));

		message = svc_queue->receive(0);
		/*
		btlogger("message.data: %s message.len: %ld message.rcode: %ld",
				message.data, message.len, message.rcode);
		*/
		BT_ASSERT(memcmp(message.data, "test1235", message.len) == 0);
		BT_ASSERT(message.correlationId == 2);
		BT_ASSERT(message.rcode == 2);
		free(message.data);
		free((char*)message.replyto);
		free(message.type);
		free(message.subtype);
	}

	svc_queue->disconnect();
	server->unregister_client(1);

	rv = apr_thread_join(&rv, queue_thead);
	BT_ASSERT(rv == APR_SUCCESS);
	delete svc_queue;
	delete client_queue;
	delete session;
}

CPPUNIT_TEST_SUITE_REGISTRATION( TestSocketSession);
<|endoftext|>


<commit_before>/** \brief Utility for displaying all non-standar tags in a MARC collection.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include "MARC.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] marc_data\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecords(MARC::Reader * const marc_reader) {
    unsigned record_count(0);
    std::unordered_set<std::string> non_standard_tags;
    while (const MARC::Record record = marc_reader->read()) {
        ++record_count;

        for (const auto &field: record) {
            const auto &tag(field.getTag());
            if (not MARC::IsStandardTag(tag))
                non_standard_tags.emplace(tag.toString());
        }
    }

    std::cout << "Data set contains " << record_count << " MARC record(s) w/ the following " << non_standard_tags.size()
              << "non-standard tags:\n";

    for (const auto &non_standard_tag : non_standard_tags)
        std::cout << non_standard_tag << '\n';
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 2)
        Usage();

    auto marc_reader(MARC::Reader::Factory(argv[1]));
    ProcessRecords(marc_reader.get());

    return EXIT_SUCCESS;
}
<commit_msg>Added missing space.<commit_after>/** \brief Utility for displaying all non-standar tags in a MARC collection.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include "MARC.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] marc_data\n";
    std::exit(EXIT_FAILURE);
}

void ProcessRecords(MARC::Reader * const marc_reader) {
    unsigned record_count(0);
    std::unordered_set<std::string> non_standard_tags;
    while (const MARC::Record record = marc_reader->read()) {
        ++record_count;

        for (const auto &field: record) {
            const auto &tag(field.getTag());
            if (not MARC::IsStandardTag(tag))
                non_standard_tags.emplace(tag.toString());
        }
    }

    std::cout << "Data set contains " << record_count << " MARC record(s) w/ the following " << non_standard_tags.size()
              << " non-standard tags:\n";

    for (const auto &non_standard_tag : non_standard_tags)
        std::cout << non_standard_tag << '\n';
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc != 2)
        Usage();

    auto marc_reader(MARC::Reader::Factory(argv[1]));
    ProcessRecords(marc_reader.get());

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2017, CNRS-LAAS
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#ifndef PLANNING_CPP_VNS_INTERFACE_H
#define PLANNING_CPP_VNS_INTERFACE_H

#include <ctime>
#include "plan.hpp"

#include "../ext/json.hpp"
using json = nlohmann::json;

class LocalMove {

public:
    /** Reference to the plan this move is created for. */
    PlanPtr base_plan;
    explicit LocalMove(PlanPtr base) : base_plan(base) {};

    /** Cost that would result in applying the move. */
    virtual double utility() = 0;

    /** Total duration that would result in applying the move */
    virtual double duration() = 0;

    /** True if applying this move on the base plan results in a valid plan. */
    virtual bool is_valid() = 0;

    /** Applies the move on the inner plan */
    void apply() {
        apply_on(base_plan);
    }

    /** Creates a new Plan on which the move is applied */
    PlanPtr apply_on_new() {
        PlanPtr ret = make_shared<Plan>(*base_plan);
        apply_on(ret);
        return ret;
    }

protected:
    /** Internal method that applies the move on a given plan.
     * This should not be used directly. Instead you should the apply/apply_on_new public methods. */
    virtual void apply_on(PlanPtr target) = 0;

private:
    /** NEVER ACCESS. This is only to make the plan visible in gdb which has problems with shared points. */
    Plan* plan_raw = base_plan.get();
};
typedef shared_ptr<LocalMove> PLocalMove;

/** Interface for generating local move in local search.
 *
 * A neighborhood provides a single method get_move() that optionally generates a new move.
 * It also contains several parameters, with defaults, that can be overriden by subclasses.*/
struct Neighborhood {

    /** Generates a new move for the given plan.
     * The optional might be empty if this neighborhood failed to generate a valid move.
     *
     * If the optional return is non-empty, local search will apply this move regardless of its cost.
     * Hence subclasses should make sure the returned values contribute to the overall quality of the plan.
     * */
    virtual opt<PLocalMove> get_move(PlanPtr plan) = 0;

    virtual std::string name() const = 0;
};

struct Shuffler {
public:
    virtual void suffle(shared_ptr<Plan> plan) = 0;
};

struct SearchResult {
    shared_ptr<Plan> init_plan;
    shared_ptr<Plan> final_plan;

public:
    vector<Plan> intermediate_plans;

    SearchResult(Plan& init_plan)
            : init_plan(shared_ptr<Plan>(new Plan(init_plan))),
              final_plan(shared_ptr<Plan>())
    {}

    void set_final_plan(Plan& p) {
        ASSERT(!final_plan)
        final_plan.reset(new Plan(p));
        metadata["plan"] = p.metadata();
    }

    Plan initial() const { return *init_plan; }
    Plan final() const { return *final_plan; }

    json metadata;
};

struct VariableNeighborhoodSearch {
    /** Sequence of neighborhoods to be considered by VNS. */
    vector<shared_ptr<Neighborhood>> neighborhoods;

    shared_ptr<Shuffler> shuffler;

    explicit VariableNeighborhoodSearch(vector<shared_ptr<Neighborhood>>& neighborhoods, shared_ptr<Shuffler> shuffler) :
            neighborhoods(neighborhoods), shuffler(shuffler) {
        ASSERT(neighborhoods.size() > 0);
    }

    /** Refines an initial plan with Variable Neighborhood Search.
     *
     * @param p: Initial plan.
     * @param max_restarts: Number of allowed restarts (currently only 0 is supported).
     * @param save_every: If >0, the Search result will contain snapshots of the search every N iterations.
     *                    Warning: this is very heavy on memory usage.
     * @param save_improvements: If set, the Search result will contain snapshots of every improvement in the plan.
     *                    Warning: this is very heavy on memory usage.
     * @return
     */
    SearchResult search(Plan p, size_t max_restarts, size_t save_every=0, bool save_improvements=false) {
        SearchResult result(p);

        PlanPtr best_plan = make_shared<Plan>(p);
        PlanPtr best_plan_for_restart = make_shared<Plan>(p);

        size_t current_iter = 0;
        size_t num_restarts = 0;

        vector<double> runtime_per_neighborhood(neighborhoods.size(), 0.0);

        bool saved = false; /*True if an improvement was saved so save_every do not take an snapshot again*/

        while(num_restarts <= max_restarts) {
            // choose first neighborhood
            size_t current_neighborhood = 0;
            if(num_restarts > 0) {
                std::cout << "Shuffling\n";
                best_plan_for_restart = std::make_shared<Plan>(*best_plan);
                shuffler->suffle(best_plan_for_restart);
                if(save_improvements) {
                    // save plan even though its is probably not an improvement
                    result.intermediate_plans.push_back(*best_plan_for_restart);
                }
            }

            while(current_neighborhood < neighborhoods.size()) {
                // current neighborhood
                shared_ptr<Neighborhood> neighborhood = neighborhoods[current_neighborhood];

                // get move for current neighborhood
                clock_t start = clock();
                const opt<PLocalMove> move = neighborhood->get_move(best_plan_for_restart);
                clock_t end = clock();
                runtime_per_neighborhood[current_neighborhood] += double(end - start) / CLOCKS_PER_SEC;

                if(move) {
                    // neighborhood generate a move, apply it
                    LocalMove& m = **move;
                    ASSERT(m.is_valid());
                    m.apply();

                    printf("Improvement (lvl: %d): utility: %f -- duration: %f\n", (int)current_neighborhood,
                           best_plan_for_restart->utility(), best_plan_for_restart->duration());

                    if(save_improvements) {
                        result.intermediate_plans.push_back(*best_plan_for_restart);
                        saved = true;
                    }

                    // plan changed, go back to first neighborhood
                    current_neighborhood = 0;
                } else {
                    // no move
                    current_neighborhood += 1;
                }
                if(!saved && save_every != 0 && (current_iter % save_every) == 0) {
                    result.intermediate_plans.push_back(*best_plan_for_restart);
                }
                saved = false;
                current_iter += 1;
            }

            if(best_plan_for_restart->utility() < best_plan->utility()) {
                best_plan = best_plan_for_restart;
            }

            // no neighborhood provides improvements, restart or exit.
            num_restarts += 1;
        }
        result.set_final_plan(*best_plan);

        // save neighborhoods metadata
        result.metadata["neighborhoods"] = json::array();
        for(size_t i=0; i<neighborhoods.size(); i++) {
            json j;
            auto& n = *neighborhoods[i];
            j["name"] = std::to_string(i) + "-" + n.name();
            j["runtime"] = runtime_per_neighborhood[i];
            result.metadata["neighborhoods"].push_back(j);
        }
        return result;
    }
};

#endif //PLANNING_CPP_VNS_INTERFACE_H
<commit_msg>Record a history of the improvements of the plan made while searching.<commit_after>/* Copyright (c) 2017, CNRS-LAAS
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#ifndef PLANNING_CPP_VNS_INTERFACE_H
#define PLANNING_CPP_VNS_INTERFACE_H

#include <ctime>
#include "plan.hpp"

#include "../ext/json.hpp"
using json = nlohmann::json;

class LocalMove {

public:
    /** Reference to the plan this move is created for. */
    PlanPtr base_plan;
    explicit LocalMove(PlanPtr base) : base_plan(base) {};

    /** Cost that would result in applying the move. */
    virtual double utility() = 0;

    /** Total duration that would result in applying the move */
    virtual double duration() = 0;

    /** True if applying this move on the base plan results in a valid plan. */
    virtual bool is_valid() = 0;

    /** Applies the move on the inner plan */
    void apply() {
        apply_on(base_plan);
    }

    /** Creates a new Plan on which the move is applied */
    PlanPtr apply_on_new() {
        PlanPtr ret = make_shared<Plan>(*base_plan);
        apply_on(ret);
        return ret;
    }

protected:
    /** Internal method that applies the move on a given plan.
     * This should not be used directly. Instead you should the apply/apply_on_new public methods. */
    virtual void apply_on(PlanPtr target) = 0;

private:
    /** NEVER ACCESS. This is only to make the plan visible in gdb which has problems with shared points. */
    Plan* plan_raw = base_plan.get();
};
typedef shared_ptr<LocalMove> PLocalMove;

/** Interface for generating local move in local search.
 *
 * A neighborhood provides a single method get_move() that optionally generates a new move.
 * It also contains several parameters, with defaults, that can be overriden by subclasses.*/
struct Neighborhood {

    /** Generates a new move for the given plan.
     * The optional might be empty if this neighborhood failed to generate a valid move.
     *
     * If the optional return is non-empty, local search will apply this move regardless of its cost.
     * Hence subclasses should make sure the returned values contribute to the overall quality of the plan.
     * */
    virtual opt<PLocalMove> get_move(PlanPtr plan) = 0;

    virtual std::string name() const = 0;
};

struct Shuffler {
public:
    virtual void suffle(shared_ptr<Plan> plan) = 0;
};

struct SearchResult {
    shared_ptr<Plan> init_plan;
    shared_ptr<Plan> final_plan;

public:
    vector<Plan> intermediate_plans;

    SearchResult(Plan& init_plan)
            : init_plan(shared_ptr<Plan>(new Plan(init_plan))),
              final_plan(shared_ptr<Plan>())
    {}

    void set_final_plan(Plan& p) {
        ASSERT(!final_plan)
        final_plan.reset(new Plan(p));
        metadata["plan"] = p.metadata();
    }

    Plan initial() const { return *init_plan; }
    Plan final() const { return *final_plan; }

    json metadata;
};

struct VariableNeighborhoodSearch {
    /** Sequence of neighborhoods to be considered by VNS. */
    vector<shared_ptr<Neighborhood>> neighborhoods;

    shared_ptr<Shuffler> shuffler;

    explicit VariableNeighborhoodSearch(vector<shared_ptr<Neighborhood>>& neighborhoods, shared_ptr<Shuffler> shuffler) :
            neighborhoods(neighborhoods), shuffler(shuffler) {
        ASSERT(neighborhoods.size() > 0);
    }

    /** Refines an initial plan with Variable Neighborhood Search.
     *
     * @param p: Initial plan.
     * @param max_restarts: Number of allowed restarts (currently only 0 is supported).
     * @param save_every: If >0, the Search result will contain snapshots of the search every N iterations.
     *                    Warning: this is very heavy on memory usage.
     * @param save_improvements: If set, the Search result will contain snapshots of every improvement in the plan.
     *                    Warning: this is very heavy on memory usage.
     * @return
     */
    SearchResult search(Plan p, size_t max_restarts, size_t save_every=0, bool save_improvements=false) {
        const clock_t search_start = clock();
        auto seconds_since_start = [search_start]() { return (double (clock() - search_start)) / CLOCKS_PER_SEC; };

        SearchResult result(p);

        PlanPtr best_plan = make_shared<Plan>(p);
        PlanPtr best_plan_for_restart = make_shared<Plan>(p);

        // a list of tuples (t, u) where 't' is a time in seconds reliative to the start of search and 'u' is the value
        // of the best utility found a 't'
        std::vector<std::pair<double, double>> utility_history;
        utility_history.push_back(std::pair<double, double>(seconds_since_start(), best_plan->utility()));

        size_t current_iter = 0;
        size_t num_restarts = 0;

        vector<double> runtime_per_neighborhood(neighborhoods.size(), 0.0);

        bool saved = false; /*True if an improvement was saved so save_every do not take an snapshot again*/

        while(num_restarts <= max_restarts) {
            // choose first neighborhood
            size_t current_neighborhood = 0;
            if(num_restarts > 0) {
                std::cout << "Shuffling\n";
                best_plan_for_restart = std::make_shared<Plan>(*best_plan);
                shuffler->suffle(best_plan_for_restart);
                if(save_improvements) {
                    // save plan even though its is probably not an improvement
                    result.intermediate_plans.push_back(*best_plan_for_restart);
                }
            }

            while(current_neighborhood < neighborhoods.size()) {
                // current neighborhood
                shared_ptr<Neighborhood> neighborhood = neighborhoods[current_neighborhood];

                // get move for current neighborhood
                const clock_t start = clock();
                const opt<PLocalMove> move = neighborhood->get_move(best_plan_for_restart);
                const clock_t end = clock();
                runtime_per_neighborhood[current_neighborhood] += double(end - start) / CLOCKS_PER_SEC;

                if(move) {
                    // neighborhood generate a move, apply it
                    LocalMove& m = **move;
                    ASSERT(m.is_valid());

                    // apply the move on best_plan_for_restart
                    m.apply();

                    if(best_plan_for_restart->utility() < best_plan->utility()) {
                        // best utility improved, record the improvement for offline analysis
                        utility_history.emplace_back(std::pair<double, double>(seconds_since_start(), best_plan_for_restart->utility()));
                    }

                    printf("Improvement (lvl: %d): utility: %f -- duration: %f\n", (int)current_neighborhood,
                           best_plan_for_restart->utility(), best_plan_for_restart->duration());

                    if(save_improvements) {
                        result.intermediate_plans.push_back(*best_plan_for_restart);
                        saved = true;
                    }

                    // plan changed, go back to first neighborhood
                    current_neighborhood = 0;
                } else {
                    // no move
                    current_neighborhood += 1;
                }
                if(!saved && save_every != 0 && (current_iter % save_every) == 0) {
                    result.intermediate_plans.push_back(*best_plan_for_restart);
                }
                saved = false;
                current_iter += 1;
            }

            if(best_plan_for_restart->utility() < best_plan->utility()) {
                best_plan = best_plan_for_restart;
            }

            // no neighborhood provides improvements, restart or exit.
            num_restarts += 1;
        }
        result.set_final_plan(*best_plan);

        // save neighborhoods metadata
        result.metadata["neighborhoods"] = json::array();
        for(size_t i=0; i<neighborhoods.size(); i++) {
            json j;
            auto& n = *neighborhoods[i];
            j["name"] = std::to_string(i) + "-" + n.name();
            j["runtime"] = runtime_per_neighborhood[i];
            result.metadata["neighborhoods"].push_back(j);
        }
        result.metadata["utility_history"] = json::array();
        for(auto time_utility : utility_history)
            result.metadata["utility_history"].push_back(json::array({time_utility.first, time_utility.second}));
        return result;
    }
};

#endif //PLANNING_CPP_VNS_INTERFACE_H
<|endoftext|>


<commit_before>#include <stdio.h>

#include <iostream>
#include <sstream>

#include "classad/classad_distribution.h"
#include "classad/fnCall.h"

#include <rest/rest-proxy.h>
#include <rest/rest-xml-parser.h>

using namespace std;
#ifdef WANT_CLASSAD_NAMESPACE
using namespace classad;
#endif

#define print_value(fp, val) _print_value(fp, val, #val)
#define print_type(fp, val) _print_type(fp, val, #val)

static void _print_type(FILE *fp, Value val, const char *name)
{
  fprintf(fp, "%s type is: ", name);

  switch(val.GetType()) {
  case Value::NULL_VALUE:
    fprintf(fp, "NULL");
    break;
  case Value::ERROR_VALUE:
    fprintf(fp, "Error");
    break;
  case Value::UNDEFINED_VALUE:
    fprintf(fp, "Undefined");
    break;
  case Value::BOOLEAN_VALUE:
    fprintf(fp, "Boolean");
    break;
  case Value::INTEGER_VALUE:
    fprintf(fp, "Integer");
    break;
  case Value::REAL_VALUE:
    fprintf(fp, "Real");
    break;
  case Value::LIST_VALUE:
    fprintf(fp, "List");
    break;
  case Value::CLASSAD_VALUE:
    fprintf(fp, "Classad");
    break;
  case Value::RELATIVE_TIME_VALUE:
    fprintf(fp, "RelativeTime");
    break;
  case Value::ABSOLUTE_TIME_VALUE:
    fprintf(fp, "AbsoluteTime");
    break;
  case Value::STRING_VALUE:
    fprintf(fp, "String");
    break;
  }

  fprintf(fp, "\n");
}

static void _print_value(FILE *fp, Value val, const char *name)
{
    /* AFAICT the only way to get at the string in a 'Value' object is to use
     * the C++ stream operator <<,  so we set up a stringstream and write
     * stuff we want into that..
     */
    std::stringstream sstr;

    sstr << name << " is " << val;
    fprintf(fp, "%s\n", sstr.str().c_str());
}

static RestXmlNode *
get_xml (RestProxyCall *call)
{
  RestXmlParser *parser;
  RestXmlNode *root;
  GError *error = NULL;

  parser = rest_xml_parser_new ();

  root = rest_xml_parser_parse_from_data (parser,
                                          rest_proxy_call_get_payload (call),
                                          rest_proxy_call_get_payload_length (call));

  g_object_unref (call);
  g_object_unref (parser);

  return root;
}

/*
 * Perform our quota check against the Aeolus Conductor database.
 * This function expects:
 *
 * - Instance executable name as handed to condor so that we can map to the
 *   instance found in the database.
 * - The username
 * - The provider url so we can map back to the provider.
 * - The realm key so we know what realm this is in.
 *
 * ... at least for now.  Need to better analyze what is required to do all
 * the quota matching but that's the idea.
 */
bool
conductor_quota_check(const char *name, const ArgumentList &arglist,
		      EvalState &state, Value &result)
{
    Value instance_id;
    Value account_id;
    FILE *fp;
    bool val = false;
    RestProxy *proxy;
    RestProxyCall *call;
    RestXmlNode *root;
    std::stringstream rest_call;
    GError *err = NULL;

    g_thread_init (NULL);
    g_type_init ();

    result.SetBooleanValue(false);

    fp = fopen(LOGFILE, "a");

    if (arglist.size() != 2) {
      result.SetErrorValue();
      fprintf(fp, "Expected 2 arguments, saw %z\n", arglist.size());
      goto do_ret;
    }

    if (!arglist[0]->Evaluate(state, instance_id)) {
      result.SetErrorValue();
      fprintf(fp, "Could not evaluate argument 0 to instance id\n");
      goto do_ret;
    }
    if (!arglist[1]->Evaluate(state, account_id)) {
      result.SetErrorValue();
      fprintf(fp, "Could not evaluate argument 1 to account id\n");
      goto do_ret;
    }

    print_type(fp, instance_id);
    print_value(fp, instance_id);
    if (instance_id.GetType() != Value::INTEGER_VALUE) {
      result.SetErrorValue();
      fprintf(fp, "Instance id type was not an integer\n");
      goto do_ret;
    }

    print_type(fp, account_id);
    print_value(fp, account_id);
    if (account_id.GetType() != Value::STRING_VALUE) {
      result.SetErrorValue();
      fprintf(fp, "Account ID type was not a string\n");
      goto do_ret;
    }

    rest_call << "resources/instances/" << instance_id << "/can_start/" << account_id;

    // Call rest API to get answer on quota..
    proxy = rest_proxy_new ("http://localhost:3000/deltacloud", FALSE);
    call = rest_proxy_new_call (proxy);
    rest_proxy_call_set_function (call, rest_call.str().c_str());

    fprintf(fp, "Calling REST API with %s\n", rest_call.str().c_str());
    rest_proxy_call_sync (call, &err);

    if (err != NULL) {
        fprintf (fp, "Error calling REST API: %s\n", err->message);
    } else {
        root = get_xml (call);
        if (root) {
            RestXmlNode *node;
            gchar *value;

            node = rest_xml_node_find (root, "value");
            value = node->content;

            fprintf (fp, "return value is %s\n", value);
            if (strncmp(value, "true", 4) == 0) {
                result.SetBooleanValue(true);
                val = true;
            }
        }
    }

    g_object_unref (proxy);

 do_ret:
    fclose(fp);

    return val;
}

/*
 * Struct containing the names of the functions provided here and a pointer
 * to the function that implements them.  Third arg is an int flags that appears
 * to be unused.
 *
 * This is found in fnCall.h
 */
static ClassAdFunctionMapping classad_functions[] =
{
    { "conductor_quota_check", (void *) conductor_quota_check, 0 },
    { "", NULL, 0 }
};

/*
 * This is the 'Init' function that is called after the library is dlopen()'d.
 * This just returns the struct defined above.
 *
 */
extern "C"
{
    ClassAdFunctionMapping *
    Init(void) {
        return classad_functions;
    }
}

<commit_msg>Rename deltacloud->conductor in the classad plugin.<commit_after>#include <stdio.h>

#include <iostream>
#include <sstream>

#include "classad/classad_distribution.h"
#include "classad/fnCall.h"

#include <rest/rest-proxy.h>
#include <rest/rest-xml-parser.h>

using namespace std;
#ifdef WANT_CLASSAD_NAMESPACE
using namespace classad;
#endif

#define print_value(fp, val) _print_value(fp, val, #val)
#define print_type(fp, val) _print_type(fp, val, #val)

static void _print_type(FILE *fp, Value val, const char *name)
{
  fprintf(fp, "%s type is: ", name);

  switch(val.GetType()) {
  case Value::NULL_VALUE:
    fprintf(fp, "NULL");
    break;
  case Value::ERROR_VALUE:
    fprintf(fp, "Error");
    break;
  case Value::UNDEFINED_VALUE:
    fprintf(fp, "Undefined");
    break;
  case Value::BOOLEAN_VALUE:
    fprintf(fp, "Boolean");
    break;
  case Value::INTEGER_VALUE:
    fprintf(fp, "Integer");
    break;
  case Value::REAL_VALUE:
    fprintf(fp, "Real");
    break;
  case Value::LIST_VALUE:
    fprintf(fp, "List");
    break;
  case Value::CLASSAD_VALUE:
    fprintf(fp, "Classad");
    break;
  case Value::RELATIVE_TIME_VALUE:
    fprintf(fp, "RelativeTime");
    break;
  case Value::ABSOLUTE_TIME_VALUE:
    fprintf(fp, "AbsoluteTime");
    break;
  case Value::STRING_VALUE:
    fprintf(fp, "String");
    break;
  }

  fprintf(fp, "\n");
}

static void _print_value(FILE *fp, Value val, const char *name)
{
    /* AFAICT the only way to get at the string in a 'Value' object is to use
     * the C++ stream operator <<,  so we set up a stringstream and write
     * stuff we want into that..
     */
    std::stringstream sstr;

    sstr << name << " is " << val;
    fprintf(fp, "%s\n", sstr.str().c_str());
}

static RestXmlNode *
get_xml (RestProxyCall *call)
{
  RestXmlParser *parser;
  RestXmlNode *root;
  GError *error = NULL;

  parser = rest_xml_parser_new ();

  root = rest_xml_parser_parse_from_data (parser,
                                          rest_proxy_call_get_payload (call),
                                          rest_proxy_call_get_payload_length (call));

  g_object_unref (call);
  g_object_unref (parser);

  return root;
}

/*
 * Perform our quota check against the Aeolus Conductor database.
 * This function expects:
 *
 * - Instance executable name as handed to condor so that we can map to the
 *   instance found in the database.
 * - The username
 * - The provider url so we can map back to the provider.
 * - The realm key so we know what realm this is in.
 *
 * ... at least for now.  Need to better analyze what is required to do all
 * the quota matching but that's the idea.
 */
bool
conductor_quota_check(const char *name, const ArgumentList &arglist,
		      EvalState &state, Value &result)
{
    Value instance_id;
    Value account_id;
    FILE *fp;
    bool val = false;
    RestProxy *proxy;
    RestProxyCall *call;
    RestXmlNode *root;
    std::stringstream rest_call;
    GError *err = NULL;

    g_thread_init (NULL);
    g_type_init ();

    result.SetBooleanValue(false);

    fp = fopen(LOGFILE, "a");

    if (arglist.size() != 2) {
      result.SetErrorValue();
      fprintf(fp, "Expected 2 arguments, saw %z\n", arglist.size());
      goto do_ret;
    }

    if (!arglist[0]->Evaluate(state, instance_id)) {
      result.SetErrorValue();
      fprintf(fp, "Could not evaluate argument 0 to instance id\n");
      goto do_ret;
    }
    if (!arglist[1]->Evaluate(state, account_id)) {
      result.SetErrorValue();
      fprintf(fp, "Could not evaluate argument 1 to account id\n");
      goto do_ret;
    }

    print_type(fp, instance_id);
    print_value(fp, instance_id);
    if (instance_id.GetType() != Value::INTEGER_VALUE) {
      result.SetErrorValue();
      fprintf(fp, "Instance id type was not an integer\n");
      goto do_ret;
    }

    print_type(fp, account_id);
    print_value(fp, account_id);
    if (account_id.GetType() != Value::STRING_VALUE) {
      result.SetErrorValue();
      fprintf(fp, "Account ID type was not a string\n");
      goto do_ret;
    }

    rest_call << "resources/instances/" << instance_id << "/can_start/" << account_id;

    // Call rest API to get answer on quota..
    proxy = rest_proxy_new ("http://localhost:3000/conductor", FALSE);
    call = rest_proxy_new_call (proxy);
    rest_proxy_call_set_function (call, rest_call.str().c_str());

    fprintf(fp, "Calling REST API with %s\n", rest_call.str().c_str());
    rest_proxy_call_sync (call, &err);

    if (err != NULL) {
        fprintf (fp, "Error calling REST API: %s\n", err->message);
    } else {
        root = get_xml (call);
        if (root) {
            RestXmlNode *node;
            gchar *value;

            node = rest_xml_node_find (root, "value");
            value = node->content;

            fprintf (fp, "return value is %s\n", value);
            if (strncmp(value, "true", 4) == 0) {
                result.SetBooleanValue(true);
                val = true;
            }
        }
    }

    g_object_unref (proxy);

 do_ret:
    fclose(fp);

    return val;
}

/*
 * Struct containing the names of the functions provided here and a pointer
 * to the function that implements them.  Third arg is an int flags that appears
 * to be unused.
 *
 * This is found in fnCall.h
 */
static ClassAdFunctionMapping classad_functions[] =
{
    { "conductor_quota_check", (void *) conductor_quota_check, 0 },
    { "", NULL, 0 }
};

/*
 * This is the 'Init' function that is called after the library is dlopen()'d.
 * This just returns the struct defined above.
 *
 */
extern "C"
{
    ClassAdFunctionMapping *
    Init(void) {
        return classad_functions;
    }
}

<|endoftext|>