<commit_before>#include "Convolution.hpp"
#include "mlo_internal.hpp"

mlopenConvolutionDescriptor::mlopenConvolutionDescriptor() : _pad_h(0), _pad_w(0), _u(1), _v(1), _upscalex(0), _upscaley(0) {
	printf("In convolution Ctor\n");
	_mode = mlopenConvolution;
}

mlopenStatus_t mlopenConvolutionDescriptor::GetForwardOutputDim(const mlopenTensorDescriptor_t inputTensorDesc,
			const mlopenTensorDescriptor_t filterDesc,
			int *n,
			int *c,
			int *h,
			int *w) {

	printf("To be implemented (GetForwardOutputDim)\n");

	return mlopenStatusSuccess;
}

mlopenStatus_t mlopenConvolutionDescriptor::FindConvFwdAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t	xDesc,
		const void						*x,
		const mlopenTensorDescriptor_t	wDesc,
		const void						*w,
		const mlopenTensorDescriptor_t	yDesc,
		const void						*y,
		const int						requestAlgoCount,
		int								*returnedAlgoCount,
		mlopenConvAlgoPerf_t			*perfResults,
		mlopenConvPreference_t			preference,
		void							*workSpace,
		size_t							workSpaceSize) {

	printf("To be implemented (FindConvFwdAlgo) \n");

#if 0
	if(handle == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc == nullptr || wDesc == nullptr || yDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(x == nullptr || w == nullptr || y == nullptr) {
		return mlopenStatusBadParm;
	}
	if(returnedAlgoCount == nullptr || perfResults == nullptr) {
		return mlopenStatusBadParm;
	}
	if(requestAlgoCount < 1) {
		return mlopenStatusBadParm;
	}
#endif

	// Generate kernels if OpenCL
	// Compile, cache kernels, etc.
	// Launch all kernels and store the perf, workspace limits, etc.

	mlo_construct_direct2D construct_params(1); // forward, no bias
	{

		construct_params.setTimerIter(100);
// HOW TO DEFINE???
		construct_params.doSearch(false);
//
		construct_params.saveSearchRequest(true);

// TO DO WHERE IS THE PATH ?
		std::string kernel_path = "../src";

		construct_params.setKernelPath(kernel_path);

		std::string generic_comp_otions = std::string(" -I ") + kernel_path + " ";
//		if (debug)
		{
			generic_comp_otions += std::string(" -cl-std=CL2.0 ");

		}

		construct_params.setGeneralCompOptions(generic_comp_otions);

		mlopenStream_t queue;
		handle->GetStream(&queue);

		construct_params.setStream(queue);

		int nOut;
		int cOut;
		int hOut;
		int wOut;
		int nOutStride;
		int cOutStride;
		int hOutStride;
		int wOutStride;

		yDesc->Get4Dims(&nOut, &cOut, &hOut, &wOut);

		yDesc->Get4Strides(&nOutStride,
			&cOutStride,
			&hOutStride,
			&wOutStride);

		construct_params.setOutputDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);

		int nIn;
		int cIn;
		int hIn;
		int wIn;
		int nInStride;
		int cInStride;
		int hInStride;
		int wInStride;

		xDesc->Get4Dims(&nIn, &cIn, &hIn, &wIn);

		yDesc->Get4Strides(&nInStride,
			&cInStride,
			&hInStride,
			&wInStride);

		construct_params.setInputDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

		int nWei;
		int cWei;
		int hWei;
		int wWei;
		int nWeiStride;
		int cWeiStride;
		int hWeiStride;
		int wWeiStride;

		wDesc->Get4Dims(&nWei, &cWei, &hWei, &wWei);

		wDesc->Get4Strides(&nWeiStride,
			&cWeiStride,
			&hWeiStride,
			&wWeiStride);

		construct_params.setWeightsDescr(
			"NCHW",
			"FP32",
			nWei,
			cWei,
			hWei,
			wWei,
			nWeiStride,
			cWeiStride,
			hWeiStride,
			wWeiStride
			);

		construct_params.setConvDescr(_pad_h, _pad_w, _u, _v, _upscalex, _upscaley);

		construct_params.mloConstructDirect2D();

	}

	std::string program_name = std::string("../src") +  construct_params.getKernelFile();  "../src/Hello.cl"; // CL kernel filename
	std::string kernel_name = construct_params.getKernelFile(); // "hello_world_kernel"; // kernel name
	std::string parms = construct_params.getCompilerOptions(); // kernel parameters

	// Get the queue associated with this handle
	mlopenStream_t queue;
	handle->GetStream(&queue);

	// Compile the kernel if not aleady compiled
	OCLKernel obj = KernelCache::get(queue, program_name, kernel_name);
	cl_int status;

	std::string kernName;
	obj.GetKernelName(kernName);

	printf("kname: %s\n", kernName.c_str());

#if 0 // Test to see if we can launch the kernel and get the results back
	float *a = new float[1024];
	float *b = new float[1024];
	float *c = new float[1024];

	for(int i = 0; i < 1024; i++) {
		a[i] = 1.0;
		b[i] = 7.0;
		c[i] = 0.0;
	}
	int sz = 1024;

	cl_context ctx;
	clGetCommandQueueInfo(queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

	cl_mem adev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, &status);
	if(status != CL_SUCCESS) {
		printf("error %d\n", status);
	}
	cl_mem bdev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, NULL);
	cl_mem cdev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz,NULL, NULL);

	status = clEnqueueWriteBuffer(queue, adev, CL_TRUE, 0, 4*sz, a, 0, NULL, NULL);
	status |= clEnqueueWriteBuffer(queue, bdev, CL_TRUE, 0, 4*sz, b, 0, NULL, NULL);
	status |= clEnqueueWriteBuffer(queue, cdev, CL_TRUE, 0, 4*sz, c, 0, NULL, NULL);
#endif // Test

	// Set kernel arguments
	// Use proper arguments

	//obj.SetArgs(0, adev, bdev, cdev, sz);

	size_t gd = 1024;
	size_t ld = 256;

	// Run the kernel
	obj.run(queue, 1, 0, gd, ld);

	clFinish(queue);

#if 0 // Read results back
	clEnqueueReadBuffer(queue, cdev, CL_TRUE, 0, 4*sz, c, 0, NULL, NULL);

	float sum = 0.0;
	for(int i = 0; i < 1024; i++) {
		b[i] = 6;
		sum += c[i];
	}

	printf("\nsum %f\n, ", sum);
	sum = 0.0;
	status |= clEnqueueWriteBuffer(queue, bdev, CL_TRUE, 0, 4*sz, b, 0, NULL, NULL);

	getchar();
#endif //Results

	return mlopenStatusSuccess;

}

mlopenStatus_t mlopenConvolutionDescriptor::ConvolutionForward(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		mlopenConvFwdAlgorithm_t			algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		 yDesc,
		void								*y) {

	printf("To be implemented (ConvolutionForward) \n");

	if(handle == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc == nullptr || wDesc == nullptr || yDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(x == nullptr || w == nullptr || y == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_CheckTensorDims(yDesc) != mlopenStatusSuccess || xDesc->_CheckTensorDims(wDesc) != mlopenStatusSuccess) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_CheckTensorDataTypes(yDesc) != mlopenStatusSuccess || xDesc->_CheckTensorDataTypes(wDesc) != mlopenStatusSuccess) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_dimA[0] != wDesc->_dimA[0]) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_dims < 3) {
		return mlopenStatusBadParm;
	}

	std::string program_name; // CL kernel filename
	std::string kernel_name; // kernel name
	std::string parms; // kernel parameters

	mlopenStream_t queue;
	handle->GetStream(&queue);

#if MLOpen_BACKEND_OPENCL
//	OCLKernel kernel = KernelCache::get(queue, program_name, kernel_name);
#endif

	return mlopenStatusSuccess;

}

<commit_msg>inor Conv.cpp fix<commit_after>#include "Convolution.hpp"
#include "mlo_internal.hpp"

mlopenConvolutionDescriptor::mlopenConvolutionDescriptor() : _pad_h(0), _pad_w(0), _u(1), _v(1), _upscalex(0), _upscaley(0) {
	printf("In convolution Ctor\n");
	_mode = mlopenConvolution;
}

mlopenStatus_t mlopenConvolutionDescriptor::GetForwardOutputDim(const mlopenTensorDescriptor_t inputTensorDesc,
			const mlopenTensorDescriptor_t filterDesc,
			int *n,
			int *c,
			int *h,
			int *w) {

	printf("To be implemented (GetForwardOutputDim)\n");

	return mlopenStatusSuccess;
}

mlopenStatus_t mlopenConvolutionDescriptor::FindConvFwdAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t	xDesc,
		const void						*x,
		const mlopenTensorDescriptor_t	wDesc,
		const void						*w,
		const mlopenTensorDescriptor_t	yDesc,
		const void						*y,
		const int						requestAlgoCount,
		int								*returnedAlgoCount,
		mlopenConvAlgoPerf_t			*perfResults,
		mlopenConvPreference_t			preference,
		void							*workSpace,
		size_t							workSpaceSize) {

	printf("To be implemented (FindConvFwdAlgo) \n");

#if 0
	if(handle == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc == nullptr || wDesc == nullptr || yDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(x == nullptr || w == nullptr || y == nullptr) {
		return mlopenStatusBadParm;
	}
	if(returnedAlgoCount == nullptr || perfResults == nullptr) {
		return mlopenStatusBadParm;
	}
	if(requestAlgoCount < 1) {
		return mlopenStatusBadParm;
	}
#endif

	// Generate kernels if OpenCL
	// Compile, cache kernels, etc.
	// Launch all kernels and store the perf, workspace limits, etc.

	mlo_construct_direct2D construct_params(1); // forward, no bias
	{

		construct_params.setTimerIter(100);
// HOW TO DEFINE???
		construct_params.doSearch(false);
//
		construct_params.saveSearchRequest(true);

// TO DO WHERE IS THE PATH ?
		std::string kernel_path = "../src";

		construct_params.setKernelPath(kernel_path);

		std::string generic_comp_otions = std::string(" -I ") + kernel_path + " ";
//		if (debug)
		{
			generic_comp_otions += std::string(" -cl-std=CL2.0 ");

		}

		construct_params.setGeneralCompOptions(generic_comp_otions);

		mlopenStream_t queue;
		handle->GetStream(&queue);

		construct_params.setStream(queue);

		int nOut;
		int cOut;
		int hOut;
		int wOut;
		int nOutStride;
		int cOutStride;
		int hOutStride;
		int wOutStride;

		yDesc->Get4Dims(&nOut, &cOut, &hOut, &wOut);

		yDesc->Get4Strides(&nOutStride,
			&cOutStride,
			&hOutStride,
			&wOutStride);

		construct_params.setOutputDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);

		int nIn;
		int cIn;
		int hIn;
		int wIn;
		int nInStride;
		int cInStride;
		int hInStride;
		int wInStride;

		xDesc->Get4Dims(&nIn, &cIn, &hIn, &wIn);

		yDesc->Get4Strides(&nInStride,
			&cInStride,
			&hInStride,
			&wInStride);

		construct_params.setInputDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

		int nWei;
		int cWei;
		int hWei;
		int wWei;
		int nWeiStride;
		int cWeiStride;
		int hWeiStride;
		int wWeiStride;

		wDesc->Get4Dims(&nWei, &cWei, &hWei, &wWei);

		wDesc->Get4Strides(&nWeiStride,
			&cWeiStride,
			&hWeiStride,
			&wWeiStride);

		construct_params.setWeightsDescr(
			"NCHW",
			"FP32",
			nWei,
			cWei,
			hWei,
			wWei,
			nWeiStride,
			cWeiStride,
			hWeiStride,
			wWeiStride
			);

		construct_params.setConvDescr(_pad_h, _pad_w, _u, _v, _upscalex, _upscaley);

		construct_params.mloConstructDirect2D();

	}

	std::string program_name = std::string("../src/") +  construct_params.getKernelFile();  //"../src/Hello.cl"; // CL kernel filename
	std::string kernel_name = construct_params.getKernelFile(); // "hello_world_kernel"; // kernel name
	std::string parms = construct_params.getCompilerOptions(); // kernel parameters

	// Get the queue associated with this handle
	mlopenStream_t queue;
	handle->GetStream(&queue);

	// Compile the kernel if not aleady compiled
	OCLKernel obj = KernelCache::get(queue, program_name, kernel_name);
	cl_int status;

	std::string kernName;
	obj.GetKernelName(kernName);

	printf("kname: %s\n", kernName.c_str());

#if 0 // Test to see if we can launch the kernel and get the results back
	float *a = new float[1024];
	float *b = new float[1024];
	float *c = new float[1024];

	for(int i = 0; i < 1024; i++) {
		a[i] = 1.0;
		b[i] = 7.0;
		c[i] = 0.0;
	}
	int sz = 1024;

	cl_context ctx;
	clGetCommandQueueInfo(queue, CL_QUEUE_CONTEXT, sizeof(cl_context), &ctx, NULL);

	cl_mem adev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, &status);
	if(status != CL_SUCCESS) {
		printf("error %d\n", status);
	}
	cl_mem bdev = clCreateBuffer(ctx, CL_MEM_READ_ONLY, 4*sz,NULL, NULL);
	cl_mem cdev = clCreateBuffer(ctx, CL_MEM_READ_WRITE, 4*sz,NULL, NULL);

	status = clEnqueueWriteBuffer(queue, adev, CL_TRUE, 0, 4*sz, a, 0, NULL, NULL);
	status |= clEnqueueWriteBuffer(queue, bdev, CL_TRUE, 0, 4*sz, b, 0, NULL, NULL);
	status |= clEnqueueWriteBuffer(queue, cdev, CL_TRUE, 0, 4*sz, c, 0, NULL, NULL);
#endif // Test

	// Set kernel arguments
	// Use proper arguments

	//obj.SetArgs(0, adev, bdev, cdev, sz);

	size_t gd = 1024;
	size_t ld = 256;

	// Run the kernel
	obj.run(queue, 1, 0, gd, ld);

	clFinish(queue);

#if 0 // Read results back
	clEnqueueReadBuffer(queue, cdev, CL_TRUE, 0, 4*sz, c, 0, NULL, NULL);

	float sum = 0.0;
	for(int i = 0; i < 1024; i++) {
		b[i] = 6;
		sum += c[i];
	}

	printf("\nsum %f\n, ", sum);
	sum = 0.0;
	status |= clEnqueueWriteBuffer(queue, bdev, CL_TRUE, 0, 4*sz, b, 0, NULL, NULL);

	getchar();
#endif //Results

	return mlopenStatusSuccess;

}

mlopenStatus_t mlopenConvolutionDescriptor::ConvolutionForward(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		mlopenConvFwdAlgorithm_t			algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		 yDesc,
		void								*y) {

	printf("To be implemented (ConvolutionForward) \n");

	if(handle == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc == nullptr || wDesc == nullptr || yDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(x == nullptr || w == nullptr || y == nullptr) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_CheckTensorDims(yDesc) != mlopenStatusSuccess || xDesc->_CheckTensorDims(wDesc) != mlopenStatusSuccess) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_CheckTensorDataTypes(yDesc) != mlopenStatusSuccess || xDesc->_CheckTensorDataTypes(wDesc) != mlopenStatusSuccess) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_dimA[0] != wDesc->_dimA[0]) {
		return mlopenStatusBadParm;
	}
	if(xDesc->_dims < 3) {
		return mlopenStatusBadParm;
	}

	std::string program_name; // CL kernel filename
	std::string kernel_name; // kernel name
	std::string parms; // kernel parameters

	mlopenStream_t queue;
	handle->GetStream(&queue);

#if MLOpen_BACKEND_OPENCL
//	OCLKernel kernel = KernelCache::get(queue, program_name, kernel_name);
#endif

	return mlopenStatusSuccess;

}

<|endoftext|>


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

#include <queue>

#include <nan.h>
#include <node.h>
#include <v8.h>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/alloc.h"
#include "grpc/support/log.h"
#include "grpc/support/time.h"

// TODO(murgatroid99): Remove this when the endpoint API becomes public
extern "C" {
#include "src/core/lib/iomgr/pollset_uv.h"
}

#include "call.h"
#include "call_credentials.h"
#include "channel.h"
#include "channel_credentials.h"
#include "completion_queue.h"
#include "server.h"
#include "server_credentials.h"
#include "slice.h"
#include "timeval.h"

using grpc::node::CreateSliceFromString;

using v8::FunctionTemplate;
using v8::Local;
using v8::Value;
using v8::Number;
using v8::Object;
using v8::Uint32;
using v8::String;

typedef struct log_args {
  gpr_log_func_args core_args;
  gpr_timespec timestamp;
} log_args;

typedef struct logger_state {
  Nan::Callback *callback;
  std::queue<log_args *> *pending_args;
  uv_mutex_t mutex;
  uv_async_t async;
  // Indicates that a logger has been set
  bool logger_set;
} logger_state;

logger_state grpc_logger_state;

static char *pem_root_certs = NULL;

void InitOpTypeConstants(Local<Object> exports) {
  Nan::HandleScope scope;
  Local<Object> op_type = Nan::New<Object>();
  Nan::Set(exports, Nan::New("opType").ToLocalChecked(), op_type);
  Local<Value> SEND_INITIAL_METADATA(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_INITIAL_METADATA));
  Nan::Set(op_type, Nan::New("SEND_INITIAL_METADATA").ToLocalChecked(),
           SEND_INITIAL_METADATA);
  Local<Value> SEND_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_MESSAGE));
  Nan::Set(op_type, Nan::New("SEND_MESSAGE").ToLocalChecked(), SEND_MESSAGE);
  Local<Value> SEND_CLOSE_FROM_CLIENT(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
  Nan::Set(op_type, Nan::New("SEND_CLOSE_FROM_CLIENT").ToLocalChecked(),
           SEND_CLOSE_FROM_CLIENT);
  Local<Value> SEND_STATUS_FROM_SERVER(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_STATUS_FROM_SERVER));
  Nan::Set(op_type, Nan::New("SEND_STATUS_FROM_SERVER").ToLocalChecked(),
           SEND_STATUS_FROM_SERVER);
  Local<Value> RECV_INITIAL_METADATA(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_INITIAL_METADATA));
  Nan::Set(op_type, Nan::New("RECV_INITIAL_METADATA").ToLocalChecked(),
           RECV_INITIAL_METADATA);
  Local<Value> RECV_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_MESSAGE));
  Nan::Set(op_type, Nan::New("RECV_MESSAGE").ToLocalChecked(), RECV_MESSAGE);
  Local<Value> RECV_STATUS_ON_CLIENT(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_STATUS_ON_CLIENT));
  Nan::Set(op_type, Nan::New("RECV_STATUS_ON_CLIENT").ToLocalChecked(),
           RECV_STATUS_ON_CLIENT);
  Local<Value> RECV_CLOSE_ON_SERVER(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_CLOSE_ON_SERVER));
  Nan::Set(op_type, Nan::New("RECV_CLOSE_ON_SERVER").ToLocalChecked(),
           RECV_CLOSE_ON_SERVER);
}

void InitConnectivityStateConstants(Local<Object> exports) {
  Nan::HandleScope scope;
  Local<Object> channel_state = Nan::New<Object>();
  Nan::Set(exports, Nan::New("connectivityState").ToLocalChecked(),
           channel_state);
  Local<Value> IDLE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_IDLE));
  Nan::Set(channel_state, Nan::New("IDLE").ToLocalChecked(), IDLE);
  Local<Value> CONNECTING(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_CONNECTING));
  Nan::Set(channel_state, Nan::New("CONNECTING").ToLocalChecked(), CONNECTING);
  Local<Value> READY(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_READY));
  Nan::Set(channel_state, Nan::New("READY").ToLocalChecked(), READY);
  Local<Value> TRANSIENT_FAILURE(
      Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_TRANSIENT_FAILURE));
  Nan::Set(channel_state, Nan::New("TRANSIENT_FAILURE").ToLocalChecked(),
           TRANSIENT_FAILURE);
  Local<Value> FATAL_FAILURE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_SHUTDOWN));
  Nan::Set(channel_state, Nan::New("FATAL_FAILURE").ToLocalChecked(),
           FATAL_FAILURE);
}

NAN_METHOD(MetadataKeyIsLegal) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError("headerKeyIsLegal's argument must be a string");
  }
  Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(key);
  info.GetReturnValue().Set(static_cast<bool>(grpc_header_key_is_legal(slice)));
  grpc_slice_unref(slice);
}

NAN_METHOD(MetadataNonbinValueIsLegal) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "metadataNonbinValueIsLegal's argument must be a string");
  }
  Local<String> value = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(value);
  info.GetReturnValue().Set(
      static_cast<bool>(grpc_header_nonbin_value_is_legal(slice)));
  grpc_slice_unref(slice);
}

NAN_METHOD(MetadataKeyIsBinary) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "metadataKeyIsLegal's argument must be a string");
  }
  Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(key);
  info.GetReturnValue().Set(static_cast<bool>(grpc_is_binary_header(slice)));
  grpc_slice_unref(slice);
}

static grpc_ssl_roots_override_result get_ssl_roots_override(
    char **pem_root_certs_ptr) {
  *pem_root_certs_ptr = pem_root_certs;
  if (pem_root_certs == NULL) {
    return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
  } else {
    return GRPC_SSL_ROOTS_OVERRIDE_OK;
  }
}

/* This should only be called once, and only before creating any
 *ServerCredentials */
NAN_METHOD(SetDefaultRootsPem) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "setDefaultRootsPem's argument must be a string");
  }
  Nan::Utf8String utf8_roots(info[0]);
  size_t length = static_cast<size_t>(utf8_roots.length());
  if (length > 0) {
    const char *data = *utf8_roots;
    pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
    memcpy(pem_root_certs, data, length + 1);
  }
}

NAUV_WORK_CB(LogMessagesCallback) {
  Nan::HandleScope scope;
  std::queue<log_args *> args;
  uv_mutex_lock(&grpc_logger_state.mutex);
  grpc_logger_state.pending_args->swap(args);
  uv_mutex_unlock(&grpc_logger_state.mutex);
  /* Call the callback with each log message */
  while (!args.empty()) {
    log_args *arg = args.front();
    args.pop();
    Local<Value> file = Nan::New(arg->core_args.file).ToLocalChecked();
    Local<Value> line = Nan::New<Uint32, uint32_t>(arg->core_args.line);
    Local<Value> severity =
        Nan::New(gpr_log_severity_string(arg->core_args.severity))
            .ToLocalChecked();
    Local<Value> message = Nan::New(arg->core_args.message).ToLocalChecked();
    Local<Value> timestamp =
        Nan::New<v8::Date>(grpc::node::TimespecToMilliseconds(arg->timestamp))
            .ToLocalChecked();
    const int argc = 5;
    Local<Value> argv[argc] = {file, line, severity, message, timestamp};
    grpc_logger_state.callback->Call(argc, argv);
    delete[] arg->core_args.message;
    delete arg;
  }
}

void node_log_func(gpr_log_func_args *args) {
  // TODO(mlumish): Use the core's log formatter when it becomes available
  log_args *args_copy = new log_args;
  size_t message_len = strlen(args->message) + 1;
  char *message = new char[message_len];
  memcpy(message, args->message, message_len);
  memcpy(&args_copy->core_args, args, sizeof(gpr_log_func_args));
  args_copy->core_args.message = message;
  args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME);

  uv_mutex_lock(&grpc_logger_state.mutex);
  grpc_logger_state.pending_args->push(args_copy);
  uv_mutex_unlock(&grpc_logger_state.mutex);

  uv_async_send(&grpc_logger_state.async);
}

void init_logger() {
  memset(&grpc_logger_state, 0, sizeof(logger_state));
  grpc_logger_state.pending_args = new std::queue<log_args *>();
  uv_mutex_init(&grpc_logger_state.mutex);
  uv_async_init(uv_default_loop(), &grpc_logger_state.async,
                LogMessagesCallback);
  uv_unref((uv_handle_t *)&grpc_logger_state.async);
  grpc_logger_state.logger_set = false;

  gpr_log_verbosity_init();
}

/* This registers a JavaScript logger for messages from the gRPC core. Because
   that handler has to be run in the context of the JavaScript event loop, it
   will be run asynchronously. To minimize the problems that could cause for
   debugging, we leave core to do its default synchronous logging until a
   JavaScript logger is set */
NAN_METHOD(SetDefaultLoggerCallback) {
  if (!info[0]->IsFunction()) {
    return Nan::ThrowTypeError(
        "setDefaultLoggerCallback's argument must be a function");
  }
  if (!grpc_logger_state.logger_set) {
    gpr_set_log_function(node_log_func);
    grpc_logger_state.logger_set = true;
  }
  grpc_logger_state.callback = new Nan::Callback(info[0].As<v8::Function>());
}

NAN_METHOD(SetLogVerbosity) {
  if (!info[0]->IsUint32()) {
    return Nan::ThrowTypeError("setLogVerbosity's argument must be a number");
  }
  gpr_log_severity severity =
      static_cast<gpr_log_severity>(Nan::To<uint32_t>(info[0]).FromJust());
  gpr_set_log_verbosity(severity);
}

NAN_METHOD(ForcePoll) {
  grpc::node::CompletionQueueForcePoll();
}

void init(Local<Object> exports) {
  Nan::HandleScope scope;
  grpc_init();
  grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
  init_logger();

  InitOpTypeConstants(exports);
  InitConnectivityStateConstants(exports);

  grpc_pollset_work_run_loop = 0;

  grpc::node::Call::Init(exports);
  grpc::node::CallCredentials::Init(exports);
  grpc::node::Channel::Init(exports);
  grpc::node::ChannelCredentials::Init(exports);
  grpc::node::Server::Init(exports);
  grpc::node::ServerCredentials::Init(exports);

  grpc::node::CompletionQueueInit(exports);

  // Attach a few utility functions directly to the module
  Nan::Set(exports, Nan::New("metadataKeyIsLegal").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsLegal))
               .ToLocalChecked());
  Nan::Set(
      exports, Nan::New("metadataNonbinValueIsLegal").ToLocalChecked(),
      Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataNonbinValueIsLegal))
          .ToLocalChecked());
  Nan::Set(exports, Nan::New("metadataKeyIsBinary").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsBinary))
               .ToLocalChecked());
  Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultRootsPem))
               .ToLocalChecked());
  Nan::Set(
      exports, Nan::New("setDefaultLoggerCallback").ToLocalChecked(),
      Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultLoggerCallback))
          .ToLocalChecked());
  Nan::Set(exports, Nan::New("setLogVerbosity").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(SetLogVerbosity))
               .ToLocalChecked());
  Nan::Set(exports, Nan::New("forcePoll").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(ForcePoll))
               .ToLocalChecked());
}

NODE_MODULE(grpc_node, init)
<commit_msg>Update a core header inclusion to stop using extern C<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <queue>

#include <nan.h>
#include <node.h>
#include <v8.h>
#include "grpc/grpc.h"
#include "grpc/grpc_security.h"
#include "grpc/support/alloc.h"
#include "grpc/support/log.h"
#include "grpc/support/time.h"

// TODO(murgatroid99): Remove this when the endpoint API becomes public
#include "src/core/lib/iomgr/pollset_uv.h"

#include "call.h"
#include "call_credentials.h"
#include "channel.h"
#include "channel_credentials.h"
#include "completion_queue.h"
#include "server.h"
#include "server_credentials.h"
#include "slice.h"
#include "timeval.h"

using grpc::node::CreateSliceFromString;

using v8::FunctionTemplate;
using v8::Local;
using v8::Value;
using v8::Number;
using v8::Object;
using v8::Uint32;
using v8::String;

typedef struct log_args {
  gpr_log_func_args core_args;
  gpr_timespec timestamp;
} log_args;

typedef struct logger_state {
  Nan::Callback *callback;
  std::queue<log_args *> *pending_args;
  uv_mutex_t mutex;
  uv_async_t async;
  // Indicates that a logger has been set
  bool logger_set;
} logger_state;

logger_state grpc_logger_state;

static char *pem_root_certs = NULL;

void InitOpTypeConstants(Local<Object> exports) {
  Nan::HandleScope scope;
  Local<Object> op_type = Nan::New<Object>();
  Nan::Set(exports, Nan::New("opType").ToLocalChecked(), op_type);
  Local<Value> SEND_INITIAL_METADATA(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_INITIAL_METADATA));
  Nan::Set(op_type, Nan::New("SEND_INITIAL_METADATA").ToLocalChecked(),
           SEND_INITIAL_METADATA);
  Local<Value> SEND_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_MESSAGE));
  Nan::Set(op_type, Nan::New("SEND_MESSAGE").ToLocalChecked(), SEND_MESSAGE);
  Local<Value> SEND_CLOSE_FROM_CLIENT(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_CLOSE_FROM_CLIENT));
  Nan::Set(op_type, Nan::New("SEND_CLOSE_FROM_CLIENT").ToLocalChecked(),
           SEND_CLOSE_FROM_CLIENT);
  Local<Value> SEND_STATUS_FROM_SERVER(
      Nan::New<Uint32, uint32_t>(GRPC_OP_SEND_STATUS_FROM_SERVER));
  Nan::Set(op_type, Nan::New("SEND_STATUS_FROM_SERVER").ToLocalChecked(),
           SEND_STATUS_FROM_SERVER);
  Local<Value> RECV_INITIAL_METADATA(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_INITIAL_METADATA));
  Nan::Set(op_type, Nan::New("RECV_INITIAL_METADATA").ToLocalChecked(),
           RECV_INITIAL_METADATA);
  Local<Value> RECV_MESSAGE(Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_MESSAGE));
  Nan::Set(op_type, Nan::New("RECV_MESSAGE").ToLocalChecked(), RECV_MESSAGE);
  Local<Value> RECV_STATUS_ON_CLIENT(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_STATUS_ON_CLIENT));
  Nan::Set(op_type, Nan::New("RECV_STATUS_ON_CLIENT").ToLocalChecked(),
           RECV_STATUS_ON_CLIENT);
  Local<Value> RECV_CLOSE_ON_SERVER(
      Nan::New<Uint32, uint32_t>(GRPC_OP_RECV_CLOSE_ON_SERVER));
  Nan::Set(op_type, Nan::New("RECV_CLOSE_ON_SERVER").ToLocalChecked(),
           RECV_CLOSE_ON_SERVER);
}

void InitConnectivityStateConstants(Local<Object> exports) {
  Nan::HandleScope scope;
  Local<Object> channel_state = Nan::New<Object>();
  Nan::Set(exports, Nan::New("connectivityState").ToLocalChecked(),
           channel_state);
  Local<Value> IDLE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_IDLE));
  Nan::Set(channel_state, Nan::New("IDLE").ToLocalChecked(), IDLE);
  Local<Value> CONNECTING(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_CONNECTING));
  Nan::Set(channel_state, Nan::New("CONNECTING").ToLocalChecked(), CONNECTING);
  Local<Value> READY(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_READY));
  Nan::Set(channel_state, Nan::New("READY").ToLocalChecked(), READY);
  Local<Value> TRANSIENT_FAILURE(
      Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_TRANSIENT_FAILURE));
  Nan::Set(channel_state, Nan::New("TRANSIENT_FAILURE").ToLocalChecked(),
           TRANSIENT_FAILURE);
  Local<Value> FATAL_FAILURE(Nan::New<Uint32, uint32_t>(GRPC_CHANNEL_SHUTDOWN));
  Nan::Set(channel_state, Nan::New("FATAL_FAILURE").ToLocalChecked(),
           FATAL_FAILURE);
}

NAN_METHOD(MetadataKeyIsLegal) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError("headerKeyIsLegal's argument must be a string");
  }
  Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(key);
  info.GetReturnValue().Set(static_cast<bool>(grpc_header_key_is_legal(slice)));
  grpc_slice_unref(slice);
}

NAN_METHOD(MetadataNonbinValueIsLegal) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "metadataNonbinValueIsLegal's argument must be a string");
  }
  Local<String> value = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(value);
  info.GetReturnValue().Set(
      static_cast<bool>(grpc_header_nonbin_value_is_legal(slice)));
  grpc_slice_unref(slice);
}

NAN_METHOD(MetadataKeyIsBinary) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "metadataKeyIsLegal's argument must be a string");
  }
  Local<String> key = Nan::To<String>(info[0]).ToLocalChecked();
  grpc_slice slice = CreateSliceFromString(key);
  info.GetReturnValue().Set(static_cast<bool>(grpc_is_binary_header(slice)));
  grpc_slice_unref(slice);
}

static grpc_ssl_roots_override_result get_ssl_roots_override(
    char **pem_root_certs_ptr) {
  *pem_root_certs_ptr = pem_root_certs;
  if (pem_root_certs == NULL) {
    return GRPC_SSL_ROOTS_OVERRIDE_FAIL;
  } else {
    return GRPC_SSL_ROOTS_OVERRIDE_OK;
  }
}

/* This should only be called once, and only before creating any
 *ServerCredentials */
NAN_METHOD(SetDefaultRootsPem) {
  if (!info[0]->IsString()) {
    return Nan::ThrowTypeError(
        "setDefaultRootsPem's argument must be a string");
  }
  Nan::Utf8String utf8_roots(info[0]);
  size_t length = static_cast<size_t>(utf8_roots.length());
  if (length > 0) {
    const char *data = *utf8_roots;
    pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char));
    memcpy(pem_root_certs, data, length + 1);
  }
}

NAUV_WORK_CB(LogMessagesCallback) {
  Nan::HandleScope scope;
  std::queue<log_args *> args;
  uv_mutex_lock(&grpc_logger_state.mutex);
  grpc_logger_state.pending_args->swap(args);
  uv_mutex_unlock(&grpc_logger_state.mutex);
  /* Call the callback with each log message */
  while (!args.empty()) {
    log_args *arg = args.front();
    args.pop();
    Local<Value> file = Nan::New(arg->core_args.file).ToLocalChecked();
    Local<Value> line = Nan::New<Uint32, uint32_t>(arg->core_args.line);
    Local<Value> severity =
        Nan::New(gpr_log_severity_string(arg->core_args.severity))
            .ToLocalChecked();
    Local<Value> message = Nan::New(arg->core_args.message).ToLocalChecked();
    Local<Value> timestamp =
        Nan::New<v8::Date>(grpc::node::TimespecToMilliseconds(arg->timestamp))
            .ToLocalChecked();
    const int argc = 5;
    Local<Value> argv[argc] = {file, line, severity, message, timestamp};
    grpc_logger_state.callback->Call(argc, argv);
    delete[] arg->core_args.message;
    delete arg;
  }
}

void node_log_func(gpr_log_func_args *args) {
  // TODO(mlumish): Use the core's log formatter when it becomes available
  log_args *args_copy = new log_args;
  size_t message_len = strlen(args->message) + 1;
  char *message = new char[message_len];
  memcpy(message, args->message, message_len);
  memcpy(&args_copy->core_args, args, sizeof(gpr_log_func_args));
  args_copy->core_args.message = message;
  args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME);

  uv_mutex_lock(&grpc_logger_state.mutex);
  grpc_logger_state.pending_args->push(args_copy);
  uv_mutex_unlock(&grpc_logger_state.mutex);

  uv_async_send(&grpc_logger_state.async);
}

void init_logger() {
  memset(&grpc_logger_state, 0, sizeof(logger_state));
  grpc_logger_state.pending_args = new std::queue<log_args *>();
  uv_mutex_init(&grpc_logger_state.mutex);
  uv_async_init(uv_default_loop(), &grpc_logger_state.async,
                LogMessagesCallback);
  uv_unref((uv_handle_t *)&grpc_logger_state.async);
  grpc_logger_state.logger_set = false;

  gpr_log_verbosity_init();
}

/* This registers a JavaScript logger for messages from the gRPC core. Because
   that handler has to be run in the context of the JavaScript event loop, it
   will be run asynchronously. To minimize the problems that could cause for
   debugging, we leave core to do its default synchronous logging until a
   JavaScript logger is set */
NAN_METHOD(SetDefaultLoggerCallback) {
  if (!info[0]->IsFunction()) {
    return Nan::ThrowTypeError(
        "setDefaultLoggerCallback's argument must be a function");
  }
  if (!grpc_logger_state.logger_set) {
    gpr_set_log_function(node_log_func);
    grpc_logger_state.logger_set = true;
  }
  grpc_logger_state.callback = new Nan::Callback(info[0].As<v8::Function>());
}

NAN_METHOD(SetLogVerbosity) {
  if (!info[0]->IsUint32()) {
    return Nan::ThrowTypeError("setLogVerbosity's argument must be a number");
  }
  gpr_log_severity severity =
      static_cast<gpr_log_severity>(Nan::To<uint32_t>(info[0]).FromJust());
  gpr_set_log_verbosity(severity);
}

NAN_METHOD(ForcePoll) {
  grpc::node::CompletionQueueForcePoll();
}

void init(Local<Object> exports) {
  Nan::HandleScope scope;
  grpc_init();
  grpc_set_ssl_roots_override_callback(get_ssl_roots_override);
  init_logger();

  InitOpTypeConstants(exports);
  InitConnectivityStateConstants(exports);

  grpc_pollset_work_run_loop = 0;

  grpc::node::Call::Init(exports);
  grpc::node::CallCredentials::Init(exports);
  grpc::node::Channel::Init(exports);
  grpc::node::ChannelCredentials::Init(exports);
  grpc::node::Server::Init(exports);
  grpc::node::ServerCredentials::Init(exports);

  grpc::node::CompletionQueueInit(exports);

  // Attach a few utility functions directly to the module
  Nan::Set(exports, Nan::New("metadataKeyIsLegal").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsLegal))
               .ToLocalChecked());
  Nan::Set(
      exports, Nan::New("metadataNonbinValueIsLegal").ToLocalChecked(),
      Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataNonbinValueIsLegal))
          .ToLocalChecked());
  Nan::Set(exports, Nan::New("metadataKeyIsBinary").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(MetadataKeyIsBinary))
               .ToLocalChecked());
  Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultRootsPem))
               .ToLocalChecked());
  Nan::Set(
      exports, Nan::New("setDefaultLoggerCallback").ToLocalChecked(),
      Nan::GetFunction(Nan::New<FunctionTemplate>(SetDefaultLoggerCallback))
          .ToLocalChecked());
  Nan::Set(exports, Nan::New("setLogVerbosity").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(SetLogVerbosity))
               .ToLocalChecked());
  Nan::Set(exports, Nan::New("forcePoll").ToLocalChecked(),
           Nan::GetFunction(Nan::New<FunctionTemplate>(ForcePoll))
               .ToLocalChecked());
}

NODE_MODULE(grpc_node, init)
<|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit 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 <gmock/gmock.h>
#include <gtest/gtest.h>

#include <thread>

#include "ProducerSideServiceImpl.h"
#include "absl/strings/str_format.h"
#include "grpcpp/grpcpp.h"

namespace orbit_service {

namespace {

// This class fakes a client of ProducerSideService for use in tests.
class FakeProducer {
 public:
  void RunRpc(const std::shared_ptr<grpc::Channel>& channel) {
    ASSERT_NE(channel, nullptr);

    std::unique_ptr<orbit_grpc_protos::ProducerSideService::Stub> stub =
        orbit_grpc_protos::ProducerSideService::NewStub(channel);
    ASSERT_NE(stub, nullptr);

    EXPECT_EQ(context_, nullptr);
    EXPECT_EQ(stream_, nullptr);
    context_ = std::make_unique<grpc::ClientContext>();
    stream_ = stub->ReceiveCommandsAndSendEvents(context_.get());
    ASSERT_NE(stream_, nullptr);

    read_thread_ = std::thread([this] {
      orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse response;
      while (stream_->Read(&response)) {
        EXPECT_NE(response.command_case(),
                  orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::COMMAND_NOT_SET);
        switch (response.command_case()) {
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::kStartCaptureCommand:
            OnStartCaptureCommandReceived();
            break;
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::kStopCaptureCommand:
            OnStopCaptureCommandReceived();
            break;
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::COMMAND_NOT_SET:
            break;
        }
      }
    });
  }

  void SendBufferedCaptureEvents(int32_t num_to_send) {
    ASSERT_NE(stream_, nullptr);
    orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest request;
    request.mutable_buffered_capture_events();
    for (int32_t i = 0; i < num_to_send; ++i) {
      request.mutable_buffered_capture_events()->mutable_capture_events()->Add();
    }
    bool written = stream_->Write(request);
    EXPECT_TRUE(written);
  }

  void SendAllEventsSent() {
    ASSERT_NE(stream_, nullptr);
    orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest request;
    request.mutable_all_events_sent();
    bool written = stream_->Write(request);
    EXPECT_TRUE(written);
  }

  void FinishRpc() {
    if (context_ != nullptr) {
      context_->TryCancel();
      context_ = nullptr;
      EXPECT_NE(stream_, nullptr);
      EXPECT_TRUE(read_thread_.joinable());
    }
    stream_ = nullptr;
    if (read_thread_.joinable()) {
      read_thread_.join();
    }
  }

  MOCK_METHOD(void, OnStartCaptureCommandReceived, (), ());
  MOCK_METHOD(void, OnStopCaptureCommandReceived, (), ());

 private:
  std::unique_ptr<grpc::ClientContext> context_;
  std::unique_ptr<grpc::ClientReaderWriter<orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest,
                                           orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse>>
      stream_;
  std::thread read_thread_;
};

class MockCaptureEventBuffer : public CaptureEventBuffer {
 public:
  MOCK_METHOD(void, AddEvent, (orbit_grpc_protos::CaptureEvent && event), (override));
};

class ProducerSideServiceImplTest : public ::testing::Test {
 protected:
  void SetUp() override {
    service.emplace();

    grpc::ServerBuilder builder;
    builder.RegisterService(&*service);
    fake_server = builder.BuildAndStart();

    std::shared_ptr<grpc::Channel> channel =
        fake_server->InProcessChannel(grpc::ChannelArguments{});

    fake_producer.emplace();
    ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
      fake_producer->SendAllEventsSent();
    });
    fake_producer->RunRpc(channel);

    // Leave some time for the ReceiveCommandsAndSendEvents RPC to actually happen.
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
  }

  void TearDown() override {
    // Leave some time for all pending communication to finish.
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    fake_producer->FinishRpc();
    fake_producer.reset();

    service->OnExitRequest();
    fake_server->Shutdown();
    fake_server->Wait();

    service.reset();
    fake_server.reset();
  }

  std::optional<ProducerSideServiceImpl> service;
  std::unique_ptr<grpc::Server> fake_server;
  std::optional<FakeProducer> fake_producer;
};

constexpr std::chrono::duration kWaitMessagesSentDuration = std::chrono::milliseconds(10);

}  // namespace

TEST_F(ProducerSideServiceImplTest, OneCapture) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  service->OnCaptureStopRequested();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);
}

TEST_F(ProducerSideServiceImplTest, TwoCaptures) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  service->OnCaptureStopRequested();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(1);
  fake_producer->SendBufferedCaptureEvents(2);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  service->OnCaptureStopRequested();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);
}

TEST_F(ProducerSideServiceImplTest, MultipleOnCaptureStartStop) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(0);
  // This should *not* cause StartCaptureCommand to be sent again.
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  service->OnCaptureStopRequested();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(0);
  // This should *not* cause StopCaptureCommand to be sent again.
  service->OnCaptureStopRequested();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);
}

}  // namespace orbit_service
<commit_msg>Add more test to ProducerSideServiceImplTest<commit_after>// Copyright (c) 2020 The Orbit 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 <gmock/gmock.h>
#include <gtest/gtest.h>

#include <thread>

#include "ProducerSideServiceImpl.h"
#include "absl/strings/str_format.h"
#include "grpcpp/grpcpp.h"

namespace orbit_service {

namespace {

// This class fakes a client of ProducerSideService for use in tests.
class FakeProducer {
 public:
  void RunRpc(const std::shared_ptr<grpc::Channel>& channel) {
    ASSERT_NE(channel, nullptr);

    std::unique_ptr<orbit_grpc_protos::ProducerSideService::Stub> stub =
        orbit_grpc_protos::ProducerSideService::NewStub(channel);
    ASSERT_NE(stub, nullptr);

    EXPECT_EQ(context_, nullptr);
    EXPECT_EQ(stream_, nullptr);
    context_ = std::make_unique<grpc::ClientContext>();
    stream_ = stub->ReceiveCommandsAndSendEvents(context_.get());
    ASSERT_NE(stream_, nullptr);

    read_thread_ = std::thread([this] {
      orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse response;
      while (stream_->Read(&response)) {
        EXPECT_NE(response.command_case(),
                  orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::COMMAND_NOT_SET);
        switch (response.command_case()) {
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::kStartCaptureCommand:
            OnStartCaptureCommandReceived();
            break;
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::kStopCaptureCommand:
            OnStopCaptureCommandReceived();
            break;
          case orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse::COMMAND_NOT_SET:
            break;
        }
      }
    });
  }

  void SendBufferedCaptureEvents(int32_t num_to_send) {
    ASSERT_NE(stream_, nullptr);
    orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest request;
    request.mutable_buffered_capture_events();
    for (int32_t i = 0; i < num_to_send; ++i) {
      request.mutable_buffered_capture_events()->mutable_capture_events()->Add();
    }
    bool written = stream_->Write(request);
    EXPECT_TRUE(written);
  }

  void SendAllEventsSent() {
    ASSERT_NE(stream_, nullptr);
    orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest request;
    request.mutable_all_events_sent();
    bool written = stream_->Write(request);
    EXPECT_TRUE(written);
  }

  void FinishRpc() {
    if (context_ != nullptr) {
      context_->TryCancel();
      context_ = nullptr;
      EXPECT_NE(stream_, nullptr);
      EXPECT_TRUE(read_thread_.joinable());
    }
    stream_ = nullptr;
    if (read_thread_.joinable()) {
      read_thread_.join();
    }
  }

  MOCK_METHOD(void, OnStartCaptureCommandReceived, (), ());
  MOCK_METHOD(void, OnStopCaptureCommandReceived, (), ());

 private:
  std::unique_ptr<grpc::ClientContext> context_;
  std::unique_ptr<grpc::ClientReaderWriter<orbit_grpc_protos::ReceiveCommandsAndSendEventsRequest,
                                           orbit_grpc_protos::ReceiveCommandsAndSendEventsResponse>>
      stream_;
  std::thread read_thread_;
};

class MockCaptureEventBuffer : public CaptureEventBuffer {
 public:
  MOCK_METHOD(void, AddEvent, (orbit_grpc_protos::CaptureEvent && event), (override));
};

class ProducerSideServiceImplTest : public ::testing::Test {
 protected:
  void SetUp() override {
    service.emplace();

    grpc::ServerBuilder builder;
    builder.RegisterService(&*service);
    fake_server = builder.BuildAndStart();

    std::shared_ptr<grpc::Channel> channel =
        fake_server->InProcessChannel(grpc::ChannelArguments{});

    fake_producer.emplace();
    fake_producer->RunRpc(channel);

    // Leave some time for the ReceiveCommandsAndSendEvents RPC to actually happen.
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
  }

  void TearDown() override {
    // Leave some time for all pending communication to finish.
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    fake_producer->FinishRpc();
    fake_producer.reset();

    service->OnExitRequest();
    fake_server->Shutdown();
    fake_server->Wait();

    service.reset();
    fake_server.reset();
  }

  std::optional<ProducerSideServiceImpl> service;
  std::unique_ptr<grpc::Server> fake_server;
  std::optional<FakeProducer> fake_producer;
};

constexpr std::chrono::duration kWaitMessagesSentDuration = std::chrono::milliseconds(25);

void ExpectDurationBetweenMs(const std::function<void(void)>& action, uint64_t min_ms,
                             uint64_t max_ms) {
  auto begin = std::chrono::steady_clock::now();
  action();
  auto end = std::chrono::steady_clock::now();
  EXPECT_GE(end - begin, std::chrono::milliseconds{min_ms});
  EXPECT_LE(end - begin, std::chrono::milliseconds{max_ms});
}

}  // namespace

TEST_F(ProducerSideServiceImplTest, OneCapture) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  static constexpr uint64_t kSendAllEventsDelayMs = 25;
  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    std::this_thread::sleep_for(std::chrono::milliseconds{kSendAllEventsDelayMs});
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, kSendAllEventsDelayMs,
                          2 * kSendAllEventsDelayMs);
}

TEST_F(ProducerSideServiceImplTest, TwoCaptures) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, 0,
                          kWaitMessagesSentDuration.count());

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(1);
  fake_producer->SendBufferedCaptureEvents(2);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  static constexpr uint64_t kSendAllEventsDelayMs = 25;
  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    std::this_thread::sleep_for(std::chrono::milliseconds{kSendAllEventsDelayMs});
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, kSendAllEventsDelayMs,
                          2 * kSendAllEventsDelayMs);
}

TEST_F(ProducerSideServiceImplTest, NoCaptureEvents) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(0);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  static constexpr uint64_t kSendAllEventsDelayMs = 25;
  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    std::this_thread::sleep_for(std::chrono::milliseconds{kSendAllEventsDelayMs});
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, kSendAllEventsDelayMs,
                          2 * kSendAllEventsDelayMs);
}

TEST_F(ProducerSideServiceImplTest, NoAllEventsSent) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  static constexpr uint64_t kMaxWaitForAllCaptureEventsMs = 50;
  service->SetMaxWaitForAllCaptureEvents(absl::Milliseconds(kMaxWaitForAllCaptureEventsMs));
  // As the AllEventsSent is not sent by the producer, OnCaptureStopRequested
  // this should take the time specified with SetMaxWaitForAllCaptureEvents.
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); },
                          kMaxWaitForAllCaptureEventsMs, 2 * kMaxWaitForAllCaptureEventsMs);
}

TEST_F(ProducerSideServiceImplTest, RedundantAllEventsSent) {
  MockCaptureEventBuffer mock_buffer;

  fake_producer->SendAllEventsSent();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  static constexpr uint64_t kSendAllEventsDelayMs = 25;
  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    std::this_thread::sleep_for(std::chrono::milliseconds{kSendAllEventsDelayMs});
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, kSendAllEventsDelayMs,
                          2 * kSendAllEventsDelayMs);

  fake_producer->SendAllEventsSent();
}

TEST_F(ProducerSideServiceImplTest, AllEventsSentBeforeStopCaptureCommand) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  fake_producer->SendAllEventsSent();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  // As the producer has already sent AllEventsSent, this should be immediate.
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, 0, 5);
}

TEST_F(ProducerSideServiceImplTest, MultipleOnCaptureStartStop) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(0);
  // This should *not* cause StartCaptureCommand to be sent again.
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  static constexpr uint64_t kSendAllEventsDelayMs = 25;
  ON_CALL(*fake_producer, OnStopCaptureCommandReceived).WillByDefault([this] {
    std::this_thread::sleep_for(std::chrono::milliseconds{kSendAllEventsDelayMs});
    fake_producer->SendAllEventsSent();
  });
  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(1);
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, kSendAllEventsDelayMs,
                          2 * kSendAllEventsDelayMs);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(0);
  // This should *not* cause StopCaptureCommand to be sent again and should be immediate.
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, 0,
                          kSendAllEventsDelayMs / 2);
}

TEST_F(ProducerSideServiceImplTest, NoOnCaptureStartRequested) {
  // As we are not waiting for any producer, this should be immediate.
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, 0, 5);
}

TEST_F(ProducerSideServiceImplTest, NoOnCaptureStopRequested) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(6);
  fake_producer->SendBufferedCaptureEvents(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  EXPECT_CALL(*fake_producer, OnStopCaptureCommandReceived).Times(0);
}

TEST_F(ProducerSideServiceImplTest, ProducerDisconnectsMidCapture) {
  MockCaptureEventBuffer mock_buffer;

  EXPECT_CALL(*fake_producer, OnStartCaptureCommandReceived).Times(1);
  service->OnCaptureStartRequested(&mock_buffer);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&*fake_producer);

  EXPECT_CALL(mock_buffer, AddEvent).Times(3);
  fake_producer->SendBufferedCaptureEvents(3);
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  fake_producer->FinishRpc();
  std::this_thread::sleep_for(kWaitMessagesSentDuration);

  ::testing::Mock::VerifyAndClearExpectations(&mock_buffer);

  // As the producer has disconnected, this should be immediate.
  ExpectDurationBetweenMs([this] { service->OnCaptureStopRequested(); }, 0, 5);
}

}  // namespace orbit_service
<|endoftext|>


<commit_before>#include "../preproc.hh"

#include <sys/types.h>

#ifdef MIMOSA_WIN
# include <winsock2.h>
# include <Ws2tcpip.h>

// Link with ws2_32.lib
# pragma comment(lib, "Ws2_32.lib")
#endif

#ifdef MIMOSA_UNIX
# include <poll.h>
# include <netdb.h>
# include <sys/socket.h>
#endif

#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <cstring>
#include <cerrno>
#include <memory>

#include "io.hh"
#include "connect.hh"

namespace mimosa
{
  namespace net
  {
    int connect(int socket, const struct sockaddr *address,
                socklen_t address_len, Time timeout)
    {
      if (!waitForFdReady(socket, POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI, timeout))
        return -1;
      return ::connect(socket, address, address_len);
    }

    int connectToHost(const std::string &host, uint16_t port, Time timeout)
    {
      ::hostent * host_entry = gethostbyname(host.c_str());
      if (!host_entry)
        return -1;

      int fd = ::socket(host_entry->h_addrtype, SOCK_STREAM, 0);
      if (fd < 0)
        return -1;

      if (host_entry->h_addrtype == AF_INET)
      {
        sockaddr_in addr;
        ::memset(&addr, 0, sizeof (addr));
        addr.sin_family = AF_INET;
        addr.sin_port   = htons(port);
        ::memcpy(&addr.sin_addr, host_entry->h_addr_list[0], host_entry->h_length);
        if (connect(fd, (const sockaddr*)&addr, sizeof (addr), timeout))
        {
          ::close(fd);
          return -1;
        }
        return fd;
      }
      if (host_entry->h_addrtype == AF_INET6)
      {
        sockaddr_in6 addr;
        ::memset(&addr, 0, sizeof (addr));
        addr.sin6_family = AF_INET6;
        addr.sin6_port   = htons(port);
        ::memcpy(&addr.sin6_addr, host_entry->h_addr_list[0], host_entry->h_length);
        if (connect(fd, (const sockaddr*)&addr, sizeof (addr), timeout))
        {
          ::close(fd);
          return -1;
        }
        return fd;
      }
      ::close(fd);
      return -1;
    }

    int connectToUnixSocket(const std::string & path,
                            Time timeout)
    {
      size_t addr_len = ((size_t) (((::sockaddr_un *) 0)->sun_path)) + path.size() + 1;
      std::unique_ptr<char[]> data(new char[addr_len]);
      ::sockaddr_un & addr = *(::sockaddr_un*)data.get();
      addr.sun_family = AF_UNIX;
      ::memcpy(addr.sun_path, path.c_str(), path.size() + 1);

      int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
      if (fd < 0)
        return -1;

      if (connect(fd, (const sockaddr*)&addr, addr_len, timeout))
      {
        ::close(fd);
        return -1;
      }
      return fd;
    }
  }
}
<commit_msg>More checks<commit_after>#include "../preproc.hh"

#include <sys/types.h>

#ifdef MIMOSA_WIN
# include <winsock2.h>
# include <Ws2tcpip.h>

// Link with ws2_32.lib
# pragma comment(lib, "Ws2_32.lib")
#endif

#ifdef MIMOSA_UNIX
# include <poll.h>
# include <netdb.h>
# include <sys/socket.h>
#endif

#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <cstring>
#include <cerrno>
#include <memory>

#include "io.hh"
#include "connect.hh"

namespace mimosa
{
  namespace net
  {
    int connect(int socket, const struct sockaddr *address,
                socklen_t address_len, Time timeout)
    {
      if (!waitForFdReady(socket, POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI, timeout))
        return -1;
      return ::connect(socket, address, address_len);
    }

    int connectToHost(const std::string &host, uint16_t port, Time timeout)
    {
      ::hostent * host_entry = gethostbyname(host.c_str());
      if (!host_entry || !host_entry->h_addr_list[0])
        return -1;

      int fd = ::socket(host_entry->h_addrtype, SOCK_STREAM, 0);
      if (fd < 0)
        return -1;

      if (host_entry->h_addrtype == AF_INET)
      {
        sockaddr_in addr;
        ::memset(&addr, 0, sizeof (addr));
        addr.sin_family = AF_INET;
        addr.sin_port   = htons(port);
        ::memcpy(&addr.sin_addr, host_entry->h_addr_list[0], host_entry->h_length);
        if (connect(fd, (const sockaddr*)&addr, sizeof (addr), timeout))
        {
          ::close(fd);
          return -1;
        }
        return fd;
      }
      if (host_entry->h_addrtype == AF_INET6)
      {
        sockaddr_in6 addr;
        ::memset(&addr, 0, sizeof (addr));
        addr.sin6_family = AF_INET6;
        addr.sin6_port   = htons(port);
        ::memcpy(&addr.sin6_addr, host_entry->h_addr_list[0], host_entry->h_length);
        if (connect(fd, (const sockaddr*)&addr, sizeof (addr), timeout))
        {
          ::close(fd);
          return -1;
        }
        return fd;
      }
      ::close(fd);
      return -1;
    }

    int connectToUnixSocket(const std::string & path,
                            Time timeout)
    {
      size_t addr_len = ((size_t) (((::sockaddr_un *) 0)->sun_path)) + path.size() + 1;
      std::unique_ptr<char[]> data(new char[addr_len]);
      ::sockaddr_un & addr = *(::sockaddr_un*)data.get();
      addr.sun_family = AF_UNIX;
      ::memcpy(addr.sun_path, path.c_str(), path.size() + 1);

      int fd = ::socket(AF_UNIX, SOCK_STREAM, 0);
      if (fd < 0)
        return -1;

      if (connect(fd, (const sockaddr*)&addr, addr_len, timeout))
      {
        ::close(fd);
        return -1;
      }
      return fd;
    }
  }
}
<|endoftext|>


<commit_before>// $Id$
//
// Task to propagate AOD tracks to EMCAL surface.
//
// Author: C.Loizides

#include <TClonesArray.h>
#include "AliAnalysisManager.h"
#include "AliEMCALRecoUtils.h"
#include "AliAODEvent.h"
#include "AliAODTrack.h"
#include "AliExternalTrackParam.h"
#include "AliEmcalTrackPropagatorTaskAOD.h"

ClassImp(AliEmcalTrackPropagatorTaskAOD)

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::AliEmcalTrackPropagatorTaskAOD() :
  AliAnalysisTaskSE("AliEmcalTrackPropagatorTaskAOD"),
  fRecoUtils(0),
  fTracksName(),
  fDist(430),
  fMinPtCut(0.35),
  fAodEv(0),
  fTracks(0)
{
  // Constructor.
}

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::AliEmcalTrackPropagatorTaskAOD(const char *name) :
  AliAnalysisTaskSE("AliEmcalTrackPropagatorTaskAOD"),
  fRecoUtils(0),
  fTracksName("TpcSpdVertexConstrainedTracks"),
  fDist(430),
  fMinPtCut(0.35),
  fAodEv(0),
  fTracks(0)
{
  // Constructor.

  if (!name)
    return;

  SetName(name);

  //  fBranchNames = "ESD:AliESDHeader.,Tracks";
}

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::~AliEmcalTrackPropagatorTaskAOD()
{
  // Destructor.

  delete fRecoUtils;
}

//________________________________________________________________________
void AliEmcalTrackPropagatorTaskAOD::UserCreateOutputObjects()
{
  // Create histograms.

  if (!fRecoUtils) {
    fRecoUtils = new AliEMCALRecoUtils;
    fRecoUtils->SetStep(20);
    AliInfo("No reco utils given, creating default utils");
  }
}

//________________________________________________________________________
void AliEmcalTrackPropagatorTaskAOD::UserExec(Option_t *)
{
  // Main loop, called for each event.

  fAodEv = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!fAodEv) {
    AliError("Task works only on AOD events, returning");
    return;
  }

  AliAnalysisManager *am = AliAnalysisManager::GetAnalysisManager();
  if (!am) {
    AliError("Manager zero, returning");
    return;
  }

  // get tracks from event if not yet there
  if (fTracksName == "tracks")
    am->LoadBranch("tracks");
  fTracks = dynamic_cast<TClonesArray*>((InputEvent()->FindListObject(fTracksName)));
  if (!fTracks) {
    AliError(Form("Could not get tracks %s, returning", fTracksName.Data()));
    return;
  }

  // Loop over all tracks
  const Int_t ntr = fTracks->GetEntries();
  for (Int_t i=0; i<ntr; ++i) {
    AliAODTrack *aodTrack = static_cast<AliAODTrack*>(fTracks->At(i));
    if (!aodTrack)
      continue;
    aodTrack->ResetStatus(AliVTrack::kEMCALmatch); //MV: necessary?
    if(aodTrack->Pt()<fMinPtCut)
      continue;
    if(aodTrack->GetTrackPtOnEMCal()>0)
      continue;

    Double_t phi = aodTrack->Phi()*TMath::RadToDeg();
    if (TMath::Abs(aodTrack->Eta())>0.9 || phi <= 10 || phi >= 250)
      continue;

    Double_t xyz[3], pxpypz[3], cv[21];
    aodTrack->PxPyPz(pxpypz);
    aodTrack->XvYvZv(xyz);
    aodTrack->GetCovarianceXYZPxPyPz(cv);
    AliExternalTrackParam *trackParam = new AliExternalTrackParam(xyz,pxpypz,cv,aodTrack->Charge());
    //    AliExternalTrackParam *trackParam =  const_cast<AliExternalTrackParam*>(eTrack->GetInnerParam()); MV: note, not taking InnerParam in AOD, not available
    if(!trackParam)
      continue;

    // Extrapolate the track to EMCal surface
    AliExternalTrackParam emcalParam(*trackParam);
    Float_t etaout=-999, phiout=-999, ptout=-999;
    Bool_t ret = fRecoUtils->ExtrapolateTrackToEMCalSurface(&emcalParam,
                                                            fDist,
                                                            aodTrack->M(),
                                                            fRecoUtils->GetStepSurface(),
                                                            etaout,
                                                            phiout,
							    ptout);
    if (!ret)
      continue;
    if (TMath::Abs(etaout)>0.75 || (phiout<70*TMath::DegToRad()) || (phiout>190*TMath::DegToRad()))
      continue;
    aodTrack->SetTrackPhiEtaPtOnEMCal(phiout, etaout, ptout);
    aodTrack->SetStatus(AliVTrack::kEMCALmatch);

    delete trackParam;
  }
}
<commit_msg>Use AliEMCALRecoUtils for propagation including use of pion mass for all tracks<commit_after>// $Id$
//
// Task to propagate AOD tracks to EMCAL surface.
//
// Author: C.Loizides

#include <TClonesArray.h>
#include "AliAnalysisManager.h"
#include "AliEMCALRecoUtils.h"
#include "AliAODEvent.h"
#include "AliAODTrack.h"
#include "AliExternalTrackParam.h"
#include <AliMagF.h>
#include <AliTrackerBase.h>
#include <AliEMCALRecoUtils.h>

#include "AliEmcalTrackPropagatorTaskAOD.h"

ClassImp(AliEmcalTrackPropagatorTaskAOD)

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::AliEmcalTrackPropagatorTaskAOD() :
  AliAnalysisTaskSE("AliEmcalTrackPropagatorTaskAOD"),
  fRecoUtils(0),
  fTracksName(),
  fDist(430),
  fMinPtCut(0.35),
  fAodEv(0),
  fTracks(0)
{
  // Constructor.
}

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::AliEmcalTrackPropagatorTaskAOD(const char *name) :
  AliAnalysisTaskSE("AliEmcalTrackPropagatorTaskAOD"),
  fRecoUtils(0),
  fTracksName("TpcSpdVertexConstrainedTracks"),
  fDist(430),
  fMinPtCut(0.35),
  fAodEv(0),
  fTracks(0)
{
  // Constructor.

  if (!name)
    return;

  SetName(name);

  //  fBranchNames = "ESD:AliESDHeader.,Tracks";
}

//________________________________________________________________________
AliEmcalTrackPropagatorTaskAOD::~AliEmcalTrackPropagatorTaskAOD()
{
  // Destructor.

  delete fRecoUtils;
}

//________________________________________________________________________
void AliEmcalTrackPropagatorTaskAOD::UserCreateOutputObjects()
{
  // Create histograms.

  if (!fRecoUtils) {
    fRecoUtils = new AliEMCALRecoUtils;
    fRecoUtils->SetStep(20);
    AliInfo("No reco utils given, creating default utils");
  }
}

//________________________________________________________________________
void AliEmcalTrackPropagatorTaskAOD::UserExec(Option_t *)
{
  // Main loop, called for each event.

  fAodEv = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!fAodEv) {
    AliError("Task works only on AOD events, returning");
    return;
  }

  AliAnalysisManager *am = AliAnalysisManager::GetAnalysisManager();
  if (!am) {
    AliError("Manager zero, returning");
    return;
  }

  // get tracks from event if not yet there
  if (fTracksName == "tracks")
    am->LoadBranch("tracks");

  fTracks = dynamic_cast<TClonesArray*>((InputEvent()->FindListObject(fTracksName)));
  if (!fTracks) {
    AliError(Form("Could not get tracks %s, returning", fTracksName.Data()));
    return;
  }

  // Loop over all tracks
  const Int_t ntr = fTracks->GetEntries();
  for (Int_t i=0; i<ntr; ++i) {
    AliAODTrack *aodTrack = static_cast<AliAODTrack*>(fTracks->At(i));
    if (!aodTrack)
      continue;
    if(aodTrack->Pt()<fMinPtCut || aodTrack->GetTrackPtOnEMCal()>0)
      continue;

    AliEMCALRecoUtils::ExtrapolateTrackToEMCalSurface(aodTrack,fDist);
  }
}
<|endoftext|>


<commit_before>// CuttingTool.cpp
/*
 * Copyright (c) 2009, Dan Heeks, Perttu Ahola
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include "CuttingTool.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "tinyxml/tinyxml.h"

#include <sstream>

extern CHeeksCADInterface* heeksCAD;

void CCuttingToolParams::set_initial_values()
{
	CNCConfig config;
	config.Read(_T("m_diameter"), &m_diameter, 12.7);
	config.Read(_T("m_x_offset"), &m_x_offset, 0);
	config.Read(_T("m_tool_length_offset"), &m_tool_length_offset, 0);
	config.Read(_T("m_orientation"), &m_orientation, 9);
}

void CCuttingToolParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_diameter"), m_diameter);
	config.Write(_T("m_x_offset"), m_x_offset);
	config.Write(_T("m_tool_length_offset"), m_tool_length_offset);
	config.Write(_T("m_orientation"), m_orientation);
}

static void on_set_diameter(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_diameter = value;}
static void on_set_x_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_x_offset = value;}
static void on_set_tool_length_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_tool_length_offset = value;}
static void on_set_orientation(int value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_orientation = value;}

void CCuttingToolParams::GetProperties(CCuttingTool* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("diameter"), m_diameter, parent, on_set_diameter));
	list->push_back(new PropertyLength(_("x_offset"), m_x_offset, parent, on_set_x_offset));
	list->push_back(new PropertyLength(_("tool_length_offset"), m_x_offset, parent, on_set_tool_length_offset));
	list->push_back(new PropertyInt(_("orientation"), m_orientation, parent, on_set_orientation));
}

void CCuttingToolParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );

	element->SetDoubleAttribute("diameter", m_diameter);
	element->SetDoubleAttribute("x_offset", m_x_offset);
	element->SetDoubleAttribute("tool_length_offset", m_tool_length_offset);

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_orientation;
	element->SetAttribute("orientation", l_ossValue.str().c_str() );
}

void CCuttingToolParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	if (pElem->Attribute("diameter")) m_diameter = atof(pElem->Attribute("diameter"));
	if (pElem->Attribute("x_offset")) m_x_offset = atof(pElem->Attribute("x_offset"));
	if (pElem->Attribute("tool_length_offset")) m_tool_length_offset = atof(pElem->Attribute("tool_length_offset"));
	if (pElem->Attribute("orientation")) m_orientation = atoi(pElem->Attribute("orientation"));
}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.
 */
void CCuttingTool::AppendTextToProgram()
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	// The G10 command can be used (within EMC2) to add a tool to the tool
        // table from within a program.
        // G10 L1 P[tool number] R[radius] X[offset] Z[offset] Q[orientation]

	if (m_title.size() > 0)
	{
		ss << "#(" << m_title.c_str() << ")\n";
	} // End if - then

	ss << "tool_defn( id=" << m_tool_number << ", "
		<< "name=None, ";
	if (m_params.m_diameter > 0)
	{
		ss << "radius=" << m_params.m_diameter / 2 << ", ";
	} // End if - then
	else
	{
		ss << "radius=None, ";
	} // End if - else

	if (m_params.m_tool_length_offset > 0)
	{
		ss << "length=" << m_params.m_tool_length_offset;
	} // End if - then
	else
	{
		ss << "length=None";
	} // End if - else

	ss << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}

static void on_set_tool_number(const int value, HeeksObj* object){((CCuttingTool*)object)->m_tool_number = value;}

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortDesc()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CCuttingTool::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyInt(_("tool_number"), m_tool_number, this, on_set_tool_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}

HeeksObj *CCuttingTool::MakeACopy(void)const
{
	return new CCuttingTool(*this);
}

void CCuttingTool::CopyFrom(const HeeksObj* object)
{
	operator=(*((CCuttingTool*)object));
}

bool CCuttingTool::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CCuttingTool::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "CuttingTool" );
	root->LinkEndChild( element );
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_tool_number;
	element->SetAttribute("tool_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CCuttingTool::ReadFromXMLElement(TiXmlElement* element)
{

	int tool_number = 0;
	if (element->Attribute("tool_number")) tool_number = atoi(element->Attribute("tool_number"));

	wxString title(Ctt(element->Attribute("title")));
	CCuttingTool* new_object = new CCuttingTool( title.c_str(), tool_number);

	// read point and circle ids
	for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
	{
		std::string name(pElem->Value());
		if(name == "params"){
			new_object->m_params.ReadParametersFromXMLElement(pElem);
		}
	}

	new_object->ReadBaseXML(element);

	return new_object;
}

void CCuttingTool::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

/**
 * Find the CuttingTool object whose tool number matches that passed in.
 */
int CCuttingTool::FindCuttingTool( const int tool_number )
{
        /* Can't make this work.  Need to figure out why */
        for (HeeksObj *ob = heeksCAD->GetFirstObject(); ob != NULL; ob = heeksCAD->GetNextObject())
        {
                if (ob->GetType() != CuttingToolType) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        // This is a hack but it works.  As long as we don't get more than 100 tools in the holder.
        for (int id=1; id<100; id++)
        {
                HeeksObj *ob = heeksCAD->GetIDObject( CuttingToolType, id );
                if (! ob) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        return(-1);

} // End FindCuttingTool() method

<commit_msg>added units<commit_after>// CuttingTool.cpp
/*
 * Copyright (c) 2009, Dan Heeks, Perttu Ahola
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include "CuttingTool.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "tinyxml/tinyxml.h"

#include <sstream>

extern CHeeksCADInterface* heeksCAD;

void CCuttingToolParams::set_initial_values()
{
	CNCConfig config;
	config.Read(_T("m_diameter"), &m_diameter, 12.7);
	config.Read(_T("m_x_offset"), &m_x_offset, 0);
	config.Read(_T("m_tool_length_offset"), &m_tool_length_offset, 0);
	config.Read(_T("m_orientation"), &m_orientation, 9);
}

void CCuttingToolParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_diameter"), m_diameter);
	config.Write(_T("m_x_offset"), m_x_offset);
	config.Write(_T("m_tool_length_offset"), m_tool_length_offset);
	config.Write(_T("m_orientation"), m_orientation);
}

static void on_set_diameter(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_diameter = value;}
static void on_set_x_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_x_offset = value;}
static void on_set_tool_length_offset(double value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_tool_length_offset = value;}
static void on_set_orientation(int value, HeeksObj* object){((CCuttingTool*)object)->m_params.m_orientation = value;}

void CCuttingToolParams::GetProperties(CCuttingTool* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyLength(_("diameter"), m_diameter, parent, on_set_diameter));
	list->push_back(new PropertyLength(_("x_offset"), m_x_offset, parent, on_set_x_offset));
	list->push_back(new PropertyLength(_("tool_length_offset"), m_x_offset, parent, on_set_tool_length_offset));
	list->push_back(new PropertyInt(_("orientation"), m_orientation, parent, on_set_orientation));
}

void CCuttingToolParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );

	element->SetDoubleAttribute("diameter", m_diameter);
	element->SetDoubleAttribute("x_offset", m_x_offset);
	element->SetDoubleAttribute("tool_length_offset", m_tool_length_offset);

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_orientation;
	element->SetAttribute("orientation", l_ossValue.str().c_str() );
}

void CCuttingToolParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	if (pElem->Attribute("diameter")) m_diameter = atof(pElem->Attribute("diameter"));
	if (pElem->Attribute("x_offset")) m_x_offset = atof(pElem->Attribute("x_offset"));
	if (pElem->Attribute("tool_length_offset")) m_tool_length_offset = atof(pElem->Attribute("tool_length_offset"));
	if (pElem->Attribute("orientation")) m_orientation = atoi(pElem->Attribute("orientation"));
}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.
 */
void CCuttingTool::AppendTextToProgram()
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	// The G10 command can be used (within EMC2) to add a tool to the tool
        // table from within a program.
        // G10 L1 P[tool number] R[radius] X[offset] Z[offset] Q[orientation]

	if (m_title.size() > 0)
	{
		ss << "#(" << m_title.c_str() << ")\n";
	} // End if - then

	ss << "tool_defn( id=" << m_tool_number << ", "
		<< "name=None, ";
	if (m_params.m_diameter > 0)
	{
		ss << "radius=" << m_params.m_diameter / 2 /theApp.m_program->m_units << ", ";
	} // End if - then
	else
	{
		ss << "radius=None, ";
	} // End if - else

	if (m_params.m_tool_length_offset > 0)
	{
		ss << "length=" << m_params.m_tool_length_offset /theApp.m_program->m_units;
	} // End if - then
	else
	{
		ss << "length=None";
	} // End if - else

	ss << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}

static void on_set_tool_number(const int value, HeeksObj* object){((CCuttingTool*)object)->m_tool_number = value;}

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortDesc()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CCuttingTool::GetProperties(std::list<Property *> *list)
{
	list->push_back(new PropertyInt(_("tool_number"), m_tool_number, this, on_set_tool_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}

HeeksObj *CCuttingTool::MakeACopy(void)const
{
	return new CCuttingTool(*this);
}

void CCuttingTool::CopyFrom(const HeeksObj* object)
{
	operator=(*((CCuttingTool*)object));
}

bool CCuttingTool::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CCuttingTool::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "CuttingTool" );
	root->LinkEndChild( element );
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_tool_number;
	element->SetAttribute("tool_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CCuttingTool::ReadFromXMLElement(TiXmlElement* element)
{

	int tool_number = 0;
	if (element->Attribute("tool_number")) tool_number = atoi(element->Attribute("tool_number"));

	wxString title(Ctt(element->Attribute("title")));
	CCuttingTool* new_object = new CCuttingTool( title.c_str(), tool_number);

	// read point and circle ids
	for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
	{
		std::string name(pElem->Value());
		if(name == "params"){
			new_object->m_params.ReadParametersFromXMLElement(pElem);
		}
	}

	new_object->ReadBaseXML(element);

	return new_object;
}

void CCuttingTool::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

/**
 * Find the CuttingTool object whose tool number matches that passed in.
 */
int CCuttingTool::FindCuttingTool( const int tool_number )
{
        /* Can't make this work.  Need to figure out why */
        for (HeeksObj *ob = heeksCAD->GetFirstObject(); ob != NULL; ob = heeksCAD->GetNextObject())
        {
                if (ob->GetType() != CuttingToolType) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        // This is a hack but it works.  As long as we don't get more than 100 tools in the holder.
        for (int id=1; id<100; id++)
        {
                HeeksObj *ob = heeksCAD->GetIDObject( CuttingToolType, id );
                if (! ob) continue;

                if (((CCuttingTool *) ob)->m_tool_number == tool_number)
                {
                        return(ob->m_id);
                } // End if - then
        } // End for

        return(-1);

} // End FindCuttingTool() method

<|endoftext|>


<commit_before>// Make sure we report atexit stats.
// RUN: %clangxx_asan -O3 %s -o %t
// RUN: env ASAN_OPTIONS=atexit=1:print_stats=1 %run %t 2>&1 | FileCheck %s
//
// No atexit output on Android due to
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android

#include <stdlib.h>
#if !defined(__APPLE__)
#include <malloc.h>
#endif
int *p1 = (int*)malloc(900);
int *p2 = (int*)malloc(90000);
int *p3 = (int*)malloc(9000000);
int main() { }

// CHECK: AddressSanitizer exit stats:
<commit_msg>Add FreeBSD support to the address sanitizer's atexit_stats.cc test case Differential Revision: http://reviews.llvm.org/D4524<commit_after>// Make sure we report atexit stats.
// RUN: %clangxx_asan -O3 %s -o %t
// RUN: env ASAN_OPTIONS=atexit=1:print_stats=1 %run %t 2>&1 | FileCheck %s
//
// No atexit output on Android due to
// https://code.google.com/p/address-sanitizer/issues/detail?id=263
// XFAIL: android

#include <stdlib.h>
#if !defined(__APPLE__) && !defined(__FreeBSD__)
#include <malloc.h>
#endif
int *p1 = (int*)malloc(900);
int *p2 = (int*)malloc(90000);
int *p3 = (int*)malloc(9000000);
int main() { }

// CHECK: AddressSanitizer exit stats:
<|endoftext|>