<commit_before>#include "mmap_reader.hpp"

#include "../std/target_os.hpp"
#include "../std/memcpy.hpp"

// @TODO we don't support windows at the moment
#ifndef OMIM_OS_WINDOWS
  #include <sys/mman.h>
  #include <sys/stat.h>
  #include <sys/fcntl.h>
  #include <unistd.h>
#endif

class MmapReader::MmapData
{
  int m_fd;

public:
  uint8_t * m_memory;
  uint64_t m_size;

  MmapData(string const & fileName)
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    m_fd = open(fileName.c_str(), O_RDONLY | O_NONBLOCK | O_SYMLINK);
    if (m_fd == -1)
      MYTHROW(OpenException, ("open failed for file", fileName));

    struct stat s;
    if (-1 == fstat(m_fd, &s))
      MYTHROW(OpenException, ("fstat failed for file", fileName));
    m_size = s.st_size;

    m_memory = (uint8_t *)mmap(0, m_size, PROT_READ, MAP_SHARED, m_fd, 0);
    if (m_memory == MAP_FAILED)
    {
      close(m_fd);
      MYTHROW(OpenException, ("mmap failed for file", fileName));
    }
#endif
  }

  ~MmapData()
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    munmap(m_memory, m_size);
    close(m_fd);
#endif
  }
};

MmapReader::MmapReader(string const & fileName)
  : base_type(fileName), m_offset(0)
{
  m_data = shared_ptr<MmapData>(new MmapData(fileName));
  m_size = m_data->m_size;
}

MmapReader::MmapReader(MmapReader const & reader, uint64_t offset, uint64_t size)
  : base_type(reader.GetName()), m_data(reader.m_data),
    m_offset(offset), m_size(size)
{
}

uint64_t MmapReader::Size() const
{
  return m_size;
}

void MmapReader::Read(uint64_t pos, void * p, size_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  memcpy(p, m_data->m_memory + m_offset + pos, size);
}

MmapReader * MmapReader::CreateSubReader(uint64_t pos, uint64_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  return new MmapReader(*this, m_offset + pos, size);
}
<commit_msg>[linux] Removed unsupported open() flag<commit_after>#include "mmap_reader.hpp"

#include "../std/target_os.hpp"
#include "../std/memcpy.hpp"

// @TODO we don't support windows at the moment
#ifndef OMIM_OS_WINDOWS
  #include <sys/mman.h>
  #include <sys/stat.h>
  #include <sys/fcntl.h>
  #include <unistd.h>
#endif

class MmapReader::MmapData
{
  int m_fd;

public:
  uint8_t * m_memory;
  uint64_t m_size;

  MmapData(string const & fileName)
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    m_fd = open(fileName.c_str(), O_RDONLY | O_NONBLOCK);
    if (m_fd == -1)
      MYTHROW(OpenException, ("open failed for file", fileName));

    struct stat s;
    if (-1 == fstat(m_fd, &s))
      MYTHROW(OpenException, ("fstat failed for file", fileName));
    m_size = s.st_size;

    m_memory = (uint8_t *)mmap(0, m_size, PROT_READ, MAP_SHARED, m_fd, 0);
    if (m_memory == MAP_FAILED)
    {
      close(m_fd);
      MYTHROW(OpenException, ("mmap failed for file", fileName));
    }
#endif
  }

  ~MmapData()
  {
    // @TODO add windows support
#ifndef OMIM_OS_WINDOWS
    munmap(m_memory, m_size);
    close(m_fd);
#endif
  }
};

MmapReader::MmapReader(string const & fileName)
  : base_type(fileName), m_offset(0)
{
  m_data = shared_ptr<MmapData>(new MmapData(fileName));
  m_size = m_data->m_size;
}

MmapReader::MmapReader(MmapReader const & reader, uint64_t offset, uint64_t size)
  : base_type(reader.GetName()), m_data(reader.m_data),
    m_offset(offset), m_size(size)
{
}

uint64_t MmapReader::Size() const
{
  return m_size;
}

void MmapReader::Read(uint64_t pos, void * p, size_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  memcpy(p, m_data->m_memory + m_offset + pos, size);
}

MmapReader * MmapReader::CreateSubReader(uint64_t pos, uint64_t size) const
{
  ASSERT_LESS_OR_EQUAL(pos + size, Size(), (pos, size));
  return new MmapReader(*this, m_offset + pos, size);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_agent.h"
#include "utils/digest.h"
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <algorithm>
#include "cereal/archives/xml.hpp"
#include "cereal/types/string.hpp"
extern "C"
{
#include "ext/standard/php_smart_str.h"
#include "ext/json/php_json.h"
#include "ext/date/php_date.h"
#include "php_streams.h"
#include "php_main.h"
}

namespace openrasp
{

volatile int PluginAgent::signal_received = 0;
volatile int LogAgent::signal_received = 0;

BaseAgent::BaseAgent(std::string name)
	: default_slash(1, DEFAULT_SLASH)
{
	this->name = name;
	this->is_alive = false;
}

void BaseAgent::install_signal_handler(sighandler_t signal_handler)
{
	struct sigaction sa_usr = {0};
	sa_usr.sa_flags = 0;
	sa_usr.sa_handler = signal_handler;
	sigaction(SIGTERM, &sa_usr, NULL);
}

PluginAgent::PluginAgent()
	: BaseAgent(PLUGIN_AGENT_PR_NAME)
{
}

void PluginAgent::run()
{
	AGENT_SET_PROC_NAME(this->name.c_str());
	install_signal_handler(
		[](int signal_no) {
			PluginAgent::signal_received = signal_no;
		});
	TSRMLS_FETCH();
	CURL *curl = nullptr;
	std::string root_dir = std::string(openrasp_ini.root_dir);
	while (true)
	{
		if (nullptr == curl)
		{
			curl = curl_easy_init();
		}
		for (int i = 0; i < openrasp_ini.plugin_update_interval; ++i)
		{
			sleep(1);
			if (PluginAgent::signal_received == SIGTERM)
			{
				curl_easy_cleanup(curl);
				curl = nullptr;
				exit(0);
			}
		}
		std::string url_string = std::string(openrasp_ini.backend) + "/v1/plugin?version=" + std::string(oam.agent_ctrl_block->get_plugin_version());
		ResponseInfo res_info;
		perform_curl(curl, url_string, nullptr, res_info);
		if (CURLE_OK != res_info.res)
		{
			continue;
		}
		zval *return_value = nullptr;
		MAKE_STD_ZVAL(return_value);
		php_json_decode(return_value, (char *)res_info.response_string.c_str(), res_info.response_string.size(), 1, 512 TSRMLS_CC);
		zval **origin_zv;
		if (Z_TYPE_P(return_value) != IS_ARRAY)
		{
			zval_ptr_dtor(&return_value);
			continue;
		}
		if (res_info.response_code >= 200 && res_info.response_code < 300)
		{
			long status;
			char *description = nullptr;
			if ((status = fetch_outmost_long_from_ht(Z_ARRVAL_P(return_value), "status")) &&
				(description = fetch_outmost_string_from_ht(Z_ARRVAL_P(return_value), "description")))
			{
				if (0 < status)
				{
					openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to update offcial plugin, status: %ld."), status);
				}
				else if (0 == status)
				{
					if (HashTable *data = fetch_outmost_hashtable_from_ht(Z_ARRVAL_P(return_value), "data"))
					{
						char *version = nullptr;
						char *plugin = nullptr;
						char *md5 = nullptr;
						if ((version = fetch_outmost_string_from_ht(data, "version")) &&
							(plugin = fetch_outmost_string_from_ht(data, "plugin")) &&
							(md5 = fetch_outmost_string_from_ht(data, "md5")))
						{
							std::string cal_md5 = md5sum(static_cast<const void *>(plugin), strlen(plugin));
							if (!strcmp(cal_md5.c_str(), md5))
							{
								update_local_offcial_plugin(root_dir + "/plugins/offcial.js", plugin, version);
							}
						}
					}
				}
			}
		}
		else
		{
			openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to update offcial plugin, response code: %ld."), res_info.response_code);
		}
		zval_ptr_dtor(&return_value);
	}
}

void PluginAgent::write_pid_to_shm(pid_t agent_pid)
{
	oam.agent_ctrl_block->set_plugin_agent_id(agent_pid);
}

std::string PluginAgent::clear_old_offcial_plugins()
{
	TSRMLS_FETCH();
	std::string root_dir = std::string(openrasp_ini.root_dir);
	std::string plugin_dir = root_dir + "/plugins";
	std::vector<std::string> offcial_plugins;
	openrasp_scandir(plugin_dir, offcial_plugins,
					 [](const char *filename) { return !strncmp(filename, "official-", strlen("official-")) &&
													   !strcmp(filename + strlen(filename) - 3, ".js"); });
	std::sort(offcial_plugins.rbegin(), offcial_plugins.rend());
	std::string newest_plugin;
	for (int i = 0; i < offcial_plugins.size(); ++i)
	{
		std::string plugin_abs_path = plugin_dir + default_slash + offcial_plugins[i];
		if (0 == i)
		{
			newest_plugin = offcial_plugins[i];
		}
		else
		{
			VCWD_UNLINK(plugin_abs_path.c_str());
		}
	}
	return newest_plugin;
}

void PluginAgent::update_local_offcial_plugin(std::string plugin_abs_path, const char *plugin, const char *version)
{
	TSRMLS_FETCH();
	std::ofstream out_file(plugin_abs_path, std::ofstream::in | std::ofstream::out | std::ofstream::trunc);
	if (out_file.is_open() && out_file.good())
	{
		out_file << plugin;
		out_file.close();
		oam.agent_ctrl_block->set_plugin_version(version);
	}
	else
	{
		openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to write offcial plugin to %s."), plugin_abs_path.c_str());
	}
}

LogAgent::LogAgent()
	: BaseAgent(LOG_AGENT_PR_NAME)
{
}

void LogAgent::write_pid_to_shm(pid_t agent_pid)
{
	oam.agent_ctrl_block->set_log_agent_id(agent_pid);
}

std::string LogAgent::get_formatted_date_suffix(long timestamp)
{
	TSRMLS_FETCH();
	std::string result;
	char *tmp_formatted_date_suffix = openrasp_format_date(ZEND_STRL(DEFAULT_LOG_FILE_SUFFIX), timestamp);
	result = std::string(tmp_formatted_date_suffix);
	efree(tmp_formatted_date_suffix);
	return result;
}

void LogAgent::run()
{
	AGENT_SET_PROC_NAME(this->name.c_str());
	TSRMLS_FETCH();
	install_signal_handler(
		[](int signal_no) {
			LogAgent::signal_received = signal_no;
		});
	std::string root_dir = std::string(openrasp_ini.root_dir);
	static const std::string position_backup_file = ".LogCollectingPos.xml";
	long last_post_time = 0;
	long time_offset = fetch_time_offset();
	std::string formatted_date_suffix = get_formatted_date_suffix((long)time(NULL));

	std::string buffer;
	std::string line;
	CURL *curl = nullptr;

	LogDirInfo alarm_dir_info(root_dir + default_slash + "logs" + default_slash + ALARM_LOG_DIR_NAME, "alarm.log.", "/v1/log/attack");
	LogDirInfo policy_dir_info(root_dir + default_slash + "logs" + default_slash + POLICY_LOG_DIR_NAME, "policy.log.", "/v1/log/policy");
	std::vector<LogDirInfo *> log_dirs{&alarm_dir_info, &policy_dir_info};
	try
	{
		std::ifstream is(root_dir + default_slash + "logs" + default_slash + position_backup_file);
		cereal::XMLInputArchive archive(is);
		archive(formatted_date_suffix, alarm_dir_info.fpos, policy_dir_info.fpos);
	}
	catch (std::exception &e)
	{
		//first startup throw excetion
	}
	while (true)
	{
		if (nullptr == curl)
		{
			curl = curl_easy_init();
		}
		long now = (long)time(NULL);
		bool file_rotate = !same_day_in_current_timezone(now, last_post_time, time_offset);
		for (int i = 0; i < log_dirs.size(); ++i)
		{
			LogDirInfo *ldi = log_dirs[i];
			std::string active_log_file = ldi->dir_abs_path + default_slash + ldi->prefix + formatted_date_suffix;
			if (VCWD_ACCESS(active_log_file.c_str(), F_OK) == 0)
			{
				if (!ldi->ifs.is_open())
				{
					ldi->ifs.open(active_log_file, std::ifstream::binary);
				}
				ldi->ifs.seekg(ldi->fpos);
				if (!ldi->ifs.good())
				{
					ldi->ifs.clear();
				}
				std::string url_string = std::string(openrasp_ini.backend) + ldi->backend_url;
				buffer.push_back('[');
				int count = 0;
				while (std::getline(ldi->ifs, line) && count < max_post_logs_account)
				{
					buffer.append(line);
					buffer.push_back(',');
					++count;
				}
				buffer.pop_back();
				buffer.push_back(']');
				if (buffer.size() > 1)
				{
					if (post_logs_via_curl(buffer, curl, url_string))
					{
						ldi->ifs.clear();
						ldi->fpos = ldi->ifs.tellg();
					}
				}
				buffer.clear();
			}
			if (file_rotate)
			{
				if (ldi->ifs.is_open())
				{
					ldi->ifs.close();
					ldi->ifs.clear();
				}
				ldi->fpos = 0;
				std::vector<std::string> files_tobe_deleted;
				std::string tobe_deleted_date_suffix = get_formatted_date_suffix(now - openrasp_ini.log_max_backup * 24 * 60 * 60);
				openrasp_scandir(ldi->dir_abs_path, files_tobe_deleted,
								 [&ldi, &tobe_deleted_date_suffix](const char *filename) {
									 return !strncmp(filename, ldi->prefix.c_str(), ldi->prefix.size()) &&
											std::string(filename) < (ldi->prefix + tobe_deleted_date_suffix);
								 });
				for (std::string delete_file : files_tobe_deleted)
				{
					VCWD_UNLINK(delete_file.c_str());
				}
			}
		}
		if (file_rotate)
		{
			formatted_date_suffix = get_formatted_date_suffix((long)time(NULL));
		}
		last_post_time = now;
		try
		{
			std::ofstream os(root_dir + default_slash + "logs" + default_slash + position_backup_file);
			cereal::XMLOutputArchive archive(os);
			archive(formatted_date_suffix, alarm_dir_info.fpos, policy_dir_info.fpos);
		}
		catch (std::exception &e)
		{
		}
		for (int i = 0; i < openrasp_ini.log_push_interval; ++i)
		{
			sleep(1);
			if (LogAgent::signal_received == SIGTERM)
			{
				curl_easy_cleanup(curl);
				curl = nullptr;
				exit(0);
			}
		}
	}
}

bool LogAgent::post_logs_via_curl(std::string log_arr, CURL *curl, std::string url_string)
{
	ResponseInfo res_info;
	perform_curl(curl, url_string, log_arr.c_str(), res_info);
	if (CURLE_OK != res_info.res ||
		res_info.response_code < 200 && res_info.response_code >= 300)
	{
		openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to post logs to %s."), url_string.c_str());
		return false;
	}
	return true;
}
} // namespace openrasp
<commit_msg>[PHP]fix last_post_time 初始值导致的重启状态重置<commit_after>/*
 * Copyright 2017-2018 Baidu Inc.
 *
 * 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 "openrasp_agent.h"
#include "utils/digest.h"
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <algorithm>
#include "cereal/archives/xml.hpp"
#include "cereal/types/string.hpp"
extern "C"
{
#include "ext/standard/php_smart_str.h"
#include "ext/json/php_json.h"
#include "ext/date/php_date.h"
#include "php_streams.h"
#include "php_main.h"
}

namespace openrasp
{

volatile int PluginAgent::signal_received = 0;
volatile int LogAgent::signal_received = 0;

BaseAgent::BaseAgent(std::string name)
	: default_slash(1, DEFAULT_SLASH)
{
	this->name = name;
	this->is_alive = false;
}

void BaseAgent::install_signal_handler(sighandler_t signal_handler)
{
	struct sigaction sa_usr = {0};
	sa_usr.sa_flags = 0;
	sa_usr.sa_handler = signal_handler;
	sigaction(SIGTERM, &sa_usr, NULL);
}

PluginAgent::PluginAgent()
	: BaseAgent(PLUGIN_AGENT_PR_NAME)
{
}

void PluginAgent::run()
{
	AGENT_SET_PROC_NAME(this->name.c_str());
	install_signal_handler(
		[](int signal_no) {
			PluginAgent::signal_received = signal_no;
		});
	TSRMLS_FETCH();
	CURL *curl = nullptr;
	std::string root_dir = std::string(openrasp_ini.root_dir);
	while (true)
	{
		if (nullptr == curl)
		{
			curl = curl_easy_init();
		}
		for (int i = 0; i < openrasp_ini.plugin_update_interval; ++i)
		{
			sleep(1);
			if (PluginAgent::signal_received == SIGTERM)
			{
				curl_easy_cleanup(curl);
				curl = nullptr;
				exit(0);
			}
		}
		std::string url_string = std::string(openrasp_ini.backend) + "/v1/plugin?version=" + std::string(oam.agent_ctrl_block->get_plugin_version());
		ResponseInfo res_info;
		perform_curl(curl, url_string, nullptr, res_info);
		if (CURLE_OK != res_info.res)
		{
			continue;
		}
		zval *return_value = nullptr;
		MAKE_STD_ZVAL(return_value);
		php_json_decode(return_value, (char *)res_info.response_string.c_str(), res_info.response_string.size(), 1, 512 TSRMLS_CC);
		zval **origin_zv;
		if (Z_TYPE_P(return_value) != IS_ARRAY)
		{
			zval_ptr_dtor(&return_value);
			continue;
		}
		if (res_info.response_code >= 200 && res_info.response_code < 300)
		{
			long status;
			char *description = nullptr;
			if ((status = fetch_outmost_long_from_ht(Z_ARRVAL_P(return_value), "status")) &&
				(description = fetch_outmost_string_from_ht(Z_ARRVAL_P(return_value), "description")))
			{
				if (0 < status)
				{
					openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to update offcial plugin, status: %ld."), status);
				}
				else if (0 == status)
				{
					if (HashTable *data = fetch_outmost_hashtable_from_ht(Z_ARRVAL_P(return_value), "data"))
					{
						char *version = nullptr;
						char *plugin = nullptr;
						char *md5 = nullptr;
						if ((version = fetch_outmost_string_from_ht(data, "version")) &&
							(plugin = fetch_outmost_string_from_ht(data, "plugin")) &&
							(md5 = fetch_outmost_string_from_ht(data, "md5")))
						{
							std::string cal_md5 = md5sum(static_cast<const void *>(plugin), strlen(plugin));
							if (!strcmp(cal_md5.c_str(), md5))
							{
								update_local_offcial_plugin(root_dir + "/plugins/offcial.js", plugin, version);
							}
						}
					}
				}
			}
		}
		else
		{
			openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to update offcial plugin, response code: %ld."), res_info.response_code);
		}
		zval_ptr_dtor(&return_value);
	}
}

void PluginAgent::write_pid_to_shm(pid_t agent_pid)
{
	oam.agent_ctrl_block->set_plugin_agent_id(agent_pid);
}

std::string PluginAgent::clear_old_offcial_plugins()
{
	TSRMLS_FETCH();
	std::string root_dir = std::string(openrasp_ini.root_dir);
	std::string plugin_dir = root_dir + "/plugins";
	std::vector<std::string> offcial_plugins;
	openrasp_scandir(plugin_dir, offcial_plugins,
					 [](const char *filename) { return !strncmp(filename, "official-", strlen("official-")) &&
													   !strcmp(filename + strlen(filename) - 3, ".js"); });
	std::sort(offcial_plugins.rbegin(), offcial_plugins.rend());
	std::string newest_plugin;
	for (int i = 0; i < offcial_plugins.size(); ++i)
	{
		std::string plugin_abs_path = plugin_dir + default_slash + offcial_plugins[i];
		if (0 == i)
		{
			newest_plugin = offcial_plugins[i];
		}
		else
		{
			VCWD_UNLINK(plugin_abs_path.c_str());
		}
	}
	return newest_plugin;
}

void PluginAgent::update_local_offcial_plugin(std::string plugin_abs_path, const char *plugin, const char *version)
{
	TSRMLS_FETCH();
	std::ofstream out_file(plugin_abs_path, std::ofstream::in | std::ofstream::out | std::ofstream::trunc);
	if (out_file.is_open() && out_file.good())
	{
		out_file << plugin;
		out_file.close();
		oam.agent_ctrl_block->set_plugin_version(version);
	}
	else
	{
		openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to write offcial plugin to %s."), plugin_abs_path.c_str());
	}
}

LogAgent::LogAgent()
	: BaseAgent(LOG_AGENT_PR_NAME)
{
}

void LogAgent::write_pid_to_shm(pid_t agent_pid)
{
	oam.agent_ctrl_block->set_log_agent_id(agent_pid);
}

std::string LogAgent::get_formatted_date_suffix(long timestamp)
{
	TSRMLS_FETCH();
	std::string result;
	char *tmp_formatted_date_suffix = openrasp_format_date(ZEND_STRL(DEFAULT_LOG_FILE_SUFFIX), timestamp);
	result = std::string(tmp_formatted_date_suffix);
	efree(tmp_formatted_date_suffix);
	return result;
}

void LogAgent::run()
{
	AGENT_SET_PROC_NAME(this->name.c_str());
	TSRMLS_FETCH();
	install_signal_handler(
		[](int signal_no) {
			LogAgent::signal_received = signal_no;
		});
	std::string root_dir = std::string(openrasp_ini.root_dir);
	static const std::string position_backup_file = ".LogCollectingPos.xml";
	long last_post_time = (long)time(NULL);
	long time_offset = fetch_time_offset();
	std::string formatted_date_suffix = get_formatted_date_suffix((long)time(NULL));

	std::string buffer;
	std::string line;
	CURL *curl = nullptr;

	LogDirInfo alarm_dir_info(root_dir + default_slash + "logs" + default_slash + ALARM_LOG_DIR_NAME, "alarm.log.", "/v1/log/attack");
	LogDirInfo policy_dir_info(root_dir + default_slash + "logs" + default_slash + POLICY_LOG_DIR_NAME, "policy.log.", "/v1/log/policy");
	std::vector<LogDirInfo *> log_dirs{&alarm_dir_info, &policy_dir_info};
	try
	{
		std::ifstream is(root_dir + default_slash + "logs" + default_slash + position_backup_file);
		cereal::XMLInputArchive archive(is);
		archive(formatted_date_suffix, alarm_dir_info.fpos, policy_dir_info.fpos);
	}
	catch (std::exception &e)
	{
		//first startup throw excetion
	}
	while (true)
	{
		if (nullptr == curl)
		{
			curl = curl_easy_init();
		}
		long now = (long)time(NULL);
		bool file_rotate = !same_day_in_current_timezone(now, last_post_time, time_offset);
		for (int i = 0; i < log_dirs.size(); ++i)
		{
			LogDirInfo *ldi = log_dirs[i];
			std::string active_log_file = ldi->dir_abs_path + default_slash + ldi->prefix + formatted_date_suffix;
			if (VCWD_ACCESS(active_log_file.c_str(), F_OK) == 0)
			{
				if (!ldi->ifs.is_open())
				{
					ldi->ifs.open(active_log_file, std::ifstream::binary);
				}
				ldi->ifs.seekg(ldi->fpos);
				if (!ldi->ifs.good())
				{
					ldi->ifs.clear();
				}
				std::string url_string = std::string(openrasp_ini.backend) + ldi->backend_url;
				buffer.push_back('[');
				int count = 0;
				while (std::getline(ldi->ifs, line) && count < max_post_logs_account)
				{
					buffer.append(line);
					buffer.push_back(',');
					++count;
				}
				buffer.pop_back();
				buffer.push_back(']');
				if (buffer.size() > 1)
				{
					if (post_logs_via_curl(buffer, curl, url_string))
					{
						ldi->ifs.clear();
						ldi->fpos = ldi->ifs.tellg();
					}
				}
				buffer.clear();
			}
			if (file_rotate)
			{
				if (ldi->ifs.is_open())
				{
					ldi->ifs.close();
					ldi->ifs.clear();
				}
				ldi->fpos = 0;
				std::vector<std::string> files_tobe_deleted;
				std::string tobe_deleted_date_suffix = get_formatted_date_suffix(now - openrasp_ini.log_max_backup * 24 * 60 * 60);
				openrasp_scandir(ldi->dir_abs_path, files_tobe_deleted,
								 [&ldi, &tobe_deleted_date_suffix](const char *filename) {
									 return !strncmp(filename, ldi->prefix.c_str(), ldi->prefix.size()) &&
											std::string(filename) < (ldi->prefix + tobe_deleted_date_suffix);
								 });
				for (std::string delete_file : files_tobe_deleted)
				{
					VCWD_UNLINK(delete_file.c_str());
				}
			}
		}
		if (file_rotate)
		{
			formatted_date_suffix = get_formatted_date_suffix((long)time(NULL));
		}
		last_post_time = now;
		try
		{
			std::ofstream os(root_dir + default_slash + "logs" + default_slash + position_backup_file);
			cereal::XMLOutputArchive archive(os);
			archive(formatted_date_suffix, alarm_dir_info.fpos, policy_dir_info.fpos);
		}
		catch (std::exception &e)
		{
		}
		for (int i = 0; i < openrasp_ini.log_push_interval; ++i)
		{
			sleep(1);
			if (LogAgent::signal_received == SIGTERM)
			{
				curl_easy_cleanup(curl);
				curl = nullptr;
				exit(0);
			}
		}
	}
}

bool LogAgent::post_logs_via_curl(std::string log_arr, CURL *curl, std::string url_string)
{
	ResponseInfo res_info;
	perform_curl(curl, url_string, log_arr.c_str(), res_info);
	if (CURLE_OK != res_info.res ||
		res_info.response_code < 200 && res_info.response_code >= 300)
	{
		openrasp_error(E_WARNING, AGENT_ERROR, _("Fail to post logs to %s."), url_string.c_str());
		return false;
	}
	return true;
}
} // namespace openrasp
<|endoftext|>


<commit_before>/**
 * @file   program-holders.hpp
 * @author nullkal <nullkal@nil.nu>
 *
 * @brief  declares IProgramHolder, ManagedProgramHolder, and
 *         RawProgramHolder.
 */

/*
 * Copyright (c) 2016 nullkal <nullkal@nil.nu>
 *
 * This file is distributed under the MIT License.
 * See LICENSE for more information.
 */

#ifndef OPENGL_COMMON_PROGRAM_HOLDERS_HPP
#define OPENGL_COMMON_PROGRAM_HOLDERS_HPP

#ifdef Apple
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

namespace kal {
namespace gl {
namespace internal {

/**
 * @brief The interface of program holder.
 */
class IProgramHolder {
public:
    /**
     * @brief The destructor
     */
    virtual ~IProgramHolder() {}

    /**
     * @brief Clone the instance
     *
     * @note The pointer this function returns should be deletable using
     *       `delete` operator.
     *
     * @return The cloned IProgramHolder object
     */
    virtual IProgramHolder* Clone() const = 0;

    /**
     * @brief  Get the holding program object
     * @return The program object
     */
    virtual GLuint Get() const = 0;
};

/**
 * @brief The program holder which manages all the life cycle.
 *
 * This program holder automatically creates a program object in the
 * constructor, and deletes it when the last object referencing it is
 * deleted.
 */
class ManagedProgramHolder : public IProgramHolder {
public:
    /**
     * @brief The default constructor
     */
    ManagedProgramHolder();

    /**
     * @brief The copy constructor
     */
    ManagedProgramHolder(const ManagedProgramHolder &obj);

    /**
     * @brief The copy assignment operator
     */
    ManagedProgramHolder &operator=(const ManagedProgramHolder &obj);

    /**
     * @brief The destructor
     */
    ~ManagedProgramHolder();

    virtual ManagedProgramHolder* Clone() const;
    virtual GLuint Get() const;

private:
    int* const m_refCount; /**< The referece counter  */
    const GLuint m_program; /**< The holding program object */
};

/**
 * @brief The program holder which only holds the program object ID.
 *
 * This program holder doesn't create/delete the program object. When you
 * use this class's instance, you must manage manually the life cycle of
 * the program object (i.e. you must call `glCreateProgram` before using
 * the object, and call `glDeleteProgram` after using it).
 */
class RawProgramHolder : public IProgramHolder {
public:
    /**
     * @brief The constructor
     *
     * @param[in] program  The program object
     */
    explicit RawProgramHolder(GLuint program);

    virtual RawProgramHolder* Clone() const;
    virtual GLuint Get() const;

private:
    const GLuint m_program; /** < The holding program object */
};

}}} // kal::gl::internal

#endif//OPENGL_COMMON_PROGRAM_HOLDERS_HPP
<commit_msg>correct documentation<commit_after>/**
 * @file   program-holders.hpp
 * @author nullkal <nullkal@nil.nu>
 *
 * @brief  declares IProgramHolder, ManagedProgramHolder, and
 *         RawProgramHolder.
 */

/*
 * Copyright (c) 2016 nullkal <nullkal@nil.nu>
 *
 * This file is distributed under the MIT License.
 * See LICENSE for more information.
 */

#ifndef OPENGL_COMMON_PROGRAM_HOLDERS_HPP
#define OPENGL_COMMON_PROGRAM_HOLDERS_HPP

#ifdef Apple
#include <OpenGL/gl.h>
#else
#include <GL/gl.h>
#endif

namespace kal {
namespace gl {
namespace internal {

/**
 * @brief The interface of program holder.
 */
class IProgramHolder {
public:
    /**
     * @brief The destructor
     */
    virtual ~IProgramHolder() {}

    /**
     * @brief Clone the instance
     *
     * @note The pointer this function returns should be deletable using
     *       `delete` operator.
     *
     * @return The cloned IProgramHolder object
     */
    virtual IProgramHolder* Clone() const = 0;

    /**
     * @brief  Get the holding program object
     * @return The program object
     */
    virtual GLuint Get() const = 0;
};

/**
 * @brief The program holder which manages all the life cycle.
 *
 * This program holder automatically creates a program object in the
 * constructor, and deletes it when the last object referencing it is
 * deleted.
 */
class ManagedProgramHolder : public IProgramHolder {
public:
    /**
     * @brief The default constructor
     */
    ManagedProgramHolder();

    /**
     * @brief The copy constructor
     */
    ManagedProgramHolder(const ManagedProgramHolder &obj);

    /**
     * @brief The copy assignment operator
     */
    ManagedProgramHolder &operator=(const ManagedProgramHolder &obj);

    /**
     * @brief The destructor
     */
    ~ManagedProgramHolder();

    virtual ManagedProgramHolder* Clone() const;
    virtual GLuint Get() const;

private:
    int* const m_refCount; /**< The referece counter  */
    const GLuint m_program; /**< The holding program object */
};

/**
 * @brief The program holder which only holds the program object ID.
 *
 * This program holder doesn't create/delete the program object. When you
 * use this class's instance, you must manage manually the life cycle of
 * the program object (i.e. you must call `glCreateProgram` before using
 * the object, and call `glDeleteProgram` after using it).
 */
class RawProgramHolder : public IProgramHolder {
public:
    /**
     * @brief The constructor
     *
     * @param[in] program  The program object
     */
    explicit RawProgramHolder(GLuint program);

    virtual RawProgramHolder* Clone() const;
    virtual GLuint Get() const;

private:
    const GLuint m_program; /**< The holding program object */
};

}}} // kal::gl::internal

#endif//OPENGL_COMMON_PROGRAM_HOLDERS_HPP
<|endoftext|>


<commit_before>/*
 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <memory>
#include <vector>

#include "webrtc/base/bind.h"
#include "webrtc/base/event.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/task_queue.h"
#include "webrtc/base/timeutils.h"

namespace rtc {

namespace {
void CheckCurrent(const char* expected_queue, Event* signal, TaskQueue* queue) {
  EXPECT_TRUE(TaskQueue::IsCurrent(expected_queue));
  EXPECT_TRUE(queue->IsCurrent());
  if (signal)
    signal->Set();
}

}  // namespace

TEST(TaskQueueTest, Construct) {
  static const char kQueueName[] = "Construct";
  TaskQueue queue(kQueueName);
  EXPECT_FALSE(queue.IsCurrent());
}

TEST(TaskQueueTest, PostAndCheckCurrent) {
  static const char kQueueName[] = "PostAndCheckCurrent";
  TaskQueue queue(kQueueName);

  // We're not running a task, so there shouldn't be a current queue.
  EXPECT_FALSE(queue.IsCurrent());
  EXPECT_FALSE(TaskQueue::Current());

  Event event(false, false);
  queue.PostTask(Bind(&CheckCurrent, kQueueName, &event, &queue));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostCustomTask) {
  static const char kQueueName[] = "PostCustomImplementation";
  TaskQueue queue(kQueueName);

  Event event(false, false);

  class CustomTask : public QueuedTask {
   public:
    explicit CustomTask(Event* event) : event_(event) {}

   private:
    bool Run() override {
      event_->Set();
      return false;  // Never allows the task to be deleted by the queue.
    }

    Event* const event_;
  } my_task(&event);

  // Please don't do this in production code! :)
  queue.PostTask(std::unique_ptr<QueuedTask>(&my_task));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostLambda) {
  static const char kQueueName[] = "PostLambda";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  queue.PostTask([&event]() { event.Set(); });
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostFromQueue) {
  static const char kQueueName[] = "PostFromQueue";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  queue.PostTask(
      [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); });
  EXPECT_TRUE(event.Wait(1000));
}

// Currently flaky on Windows. See issue 6610.
#if defined(WEBRTC_WIN)
#define MAYBE_PostDelayed DISABLED_PostDelayed
#else
#define MAYBE_PostDelayed PostDelayed
#endif
TEST(TaskQueueTest, MAYBE_PostDelayed) {
  static const char kQueueName[] = "PostDelayed";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  uint32_t start = Time();
  queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100);
  EXPECT_TRUE(event.Wait(1000));
  uint32_t end = Time();
  EXPECT_GE(end - start, 100u);
  EXPECT_NEAR(end - start, 200u, 100u);  // Accept 100-300.
}

TEST(TaskQueueTest, PostMultipleDelayed) {
  static const char kQueueName[] = "PostMultipleDelayed";
  TaskQueue queue(kQueueName);

  std::vector<std::unique_ptr<Event>> events;
  for (int i = 0; i < 10; ++i) {
    events.push_back(std::unique_ptr<Event>(new Event(false, false)));
    queue.PostDelayedTask(
        Bind(&CheckCurrent, kQueueName, events.back().get(), &queue), 10);
  }

  for (const auto& e : events)
    EXPECT_TRUE(e->Wait(100));
}

TEST(TaskQueueTest, PostDelayedAfterDestruct) {
  static const char kQueueName[] = "PostDelayedAfterDestruct";
  Event event(false, false);
  {
    TaskQueue queue(kQueueName);
    queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100);
  }
  EXPECT_FALSE(event.Wait(200));  // Task should not run.
}

TEST(TaskQueueTest, PostAndReply) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  Event event(false, false);
  post_queue.PostTaskAndReply(
      Bind(&CheckCurrent, kPostQueue, nullptr, &post_queue),
      Bind(&CheckCurrent, kReplyQueue, &event, &reply_queue), &reply_queue);
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostAndReuse) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  int call_count = 0;

  class ReusedTask : public QueuedTask {
   public:
    ReusedTask(int* counter, TaskQueue* reply_queue, Event* event)
        : counter_(counter), reply_queue_(reply_queue), event_(event) {
      EXPECT_EQ(0, *counter_);
    }

   private:
    bool Run() override {
      if (++(*counter_) == 1) {
        std::unique_ptr<QueuedTask> myself(this);
        reply_queue_->PostTask(std::move(myself));
        // At this point, the object is owned by reply_queue_ and it's
        // theoratically possible that the object has been deleted (e.g. if
        // posting wasn't possible).  So, don't touch any member variables here.

        // Indicate to the current queue that ownership has been transferred.
        return false;
      } else {
        EXPECT_EQ(2, *counter_);
        EXPECT_TRUE(reply_queue_->IsCurrent());
        event_->Set();
        return true;  // Indicate that the object should be deleted.
      }
    }

    int* const counter_;
    TaskQueue* const reply_queue_;
    Event* const event_;
  };

  Event event(false, false);
  std::unique_ptr<QueuedTask> task(
      new ReusedTask(&call_count, &reply_queue, &event));

  post_queue.PostTask(std::move(task));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostAndReplyLambda) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  Event event(false, false);
  bool my_flag = false;
  post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; },
                              [&event]() { event.Set(); }, &reply_queue);
  EXPECT_TRUE(event.Wait(1000));
  EXPECT_TRUE(my_flag);
}

void TestPostTaskAndReply(TaskQueue* work_queue,
                          const char* work_queue_name,
                          Event* event) {
  ASSERT_FALSE(work_queue->IsCurrent());
  work_queue->PostTaskAndReply(
      Bind(&CheckCurrent, work_queue_name, nullptr, work_queue),
      NewClosure([event]() { event->Set(); }));
}

// Does a PostTaskAndReply from within a task to post and reply to the current
// queue.  All in all there will be 3 tasks posted and run.
TEST(TaskQueueTest, PostAndReply2) {
  static const char kQueueName[] = "PostAndReply2";
  static const char kWorkQueueName[] = "PostAndReply2_Worker";
  TaskQueue queue(kQueueName);
  TaskQueue work_queue(kWorkQueueName);

  Event event(false, false);
  queue.PostTask(
      Bind(&TestPostTaskAndReply, &work_queue, kWorkQueueName, &event));
  EXPECT_TRUE(event.Wait(1000));
}

// Tests posting more messages than a queue can queue up.
// In situations like that, tasks will get dropped.
TEST(TaskQueueTest, PostALot) {
  // To destruct the event after the queue has gone out of scope.
  Event event(false, false);

  int tasks_executed = 0;
  int tasks_cleaned_up = 0;
  static const int kTaskCount = 0xffff;

  {
    static const char kQueueName[] = "PostALot";
    TaskQueue queue(kQueueName);

    // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
    // So here we post a total of 0xffff+1 messages, which triggers a failure
    // case inside of the libevent queue implementation.

    queue.PostTask([&event]() { event.Wait(Event::kForever); });
    for (int i = 0; i < kTaskCount; ++i)
      queue.PostTask(NewClosure([&tasks_executed]() { ++tasks_executed; },
                                [&tasks_cleaned_up]() { ++tasks_cleaned_up; }));
    event.Set();  // Unblock the first task.
  }

  EXPECT_GE(tasks_cleaned_up, tasks_executed);
  EXPECT_EQ(kTaskCount, tasks_cleaned_up);
}

}  // namespace rtc
<commit_msg>Re-enable PostDelayed test for TaskQueue on Windows. The requirements have been relaxed a little bit which should allow the test to pass on our VMs that run the tests.<commit_after>/*
 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <memory>
#include <vector>

#include "webrtc/base/bind.h"
#include "webrtc/base/event.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/task_queue.h"
#include "webrtc/base/timeutils.h"

namespace rtc {

namespace {
void CheckCurrent(const char* expected_queue, Event* signal, TaskQueue* queue) {
  EXPECT_TRUE(TaskQueue::IsCurrent(expected_queue));
  EXPECT_TRUE(queue->IsCurrent());
  if (signal)
    signal->Set();
}

}  // namespace

TEST(TaskQueueTest, Construct) {
  static const char kQueueName[] = "Construct";
  TaskQueue queue(kQueueName);
  EXPECT_FALSE(queue.IsCurrent());
}

TEST(TaskQueueTest, PostAndCheckCurrent) {
  static const char kQueueName[] = "PostAndCheckCurrent";
  TaskQueue queue(kQueueName);

  // We're not running a task, so there shouldn't be a current queue.
  EXPECT_FALSE(queue.IsCurrent());
  EXPECT_FALSE(TaskQueue::Current());

  Event event(false, false);
  queue.PostTask(Bind(&CheckCurrent, kQueueName, &event, &queue));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostCustomTask) {
  static const char kQueueName[] = "PostCustomImplementation";
  TaskQueue queue(kQueueName);

  Event event(false, false);

  class CustomTask : public QueuedTask {
   public:
    explicit CustomTask(Event* event) : event_(event) {}

   private:
    bool Run() override {
      event_->Set();
      return false;  // Never allows the task to be deleted by the queue.
    }

    Event* const event_;
  } my_task(&event);

  // Please don't do this in production code! :)
  queue.PostTask(std::unique_ptr<QueuedTask>(&my_task));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostLambda) {
  static const char kQueueName[] = "PostLambda";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  queue.PostTask([&event]() { event.Set(); });
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostFromQueue) {
  static const char kQueueName[] = "PostFromQueue";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  queue.PostTask(
      [&event, &queue]() { queue.PostTask([&event]() { event.Set(); }); });
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostDelayed) {
  static const char kQueueName[] = "PostDelayed";
  TaskQueue queue(kQueueName);

  Event event(false, false);
  uint32_t start = Time();
  queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100);
  EXPECT_TRUE(event.Wait(1000));
  uint32_t end = Time();
  // These tests are a little relaxed due to how "powerful" our test bots can
  // be.  Most recently we've seen windows bots fire the callback after 99ms,
  // which is why we have a little bit of leeway backwards as well.
  EXPECT_GE(end - start, 95u);
  EXPECT_NEAR(end - start, 195u, 100u);  // Accept 95-295.
}

TEST(TaskQueueTest, PostMultipleDelayed) {
  static const char kQueueName[] = "PostMultipleDelayed";
  TaskQueue queue(kQueueName);

  std::vector<std::unique_ptr<Event>> events;
  for (int i = 0; i < 10; ++i) {
    events.push_back(std::unique_ptr<Event>(new Event(false, false)));
    queue.PostDelayedTask(
        Bind(&CheckCurrent, kQueueName, events.back().get(), &queue), 10);
  }

  for (const auto& e : events)
    EXPECT_TRUE(e->Wait(100));
}

TEST(TaskQueueTest, PostDelayedAfterDestruct) {
  static const char kQueueName[] = "PostDelayedAfterDestruct";
  Event event(false, false);
  {
    TaskQueue queue(kQueueName);
    queue.PostDelayedTask(Bind(&CheckCurrent, kQueueName, &event, &queue), 100);
  }
  EXPECT_FALSE(event.Wait(200));  // Task should not run.
}

TEST(TaskQueueTest, PostAndReply) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  Event event(false, false);
  post_queue.PostTaskAndReply(
      Bind(&CheckCurrent, kPostQueue, nullptr, &post_queue),
      Bind(&CheckCurrent, kReplyQueue, &event, &reply_queue), &reply_queue);
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostAndReuse) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  int call_count = 0;

  class ReusedTask : public QueuedTask {
   public:
    ReusedTask(int* counter, TaskQueue* reply_queue, Event* event)
        : counter_(counter), reply_queue_(reply_queue), event_(event) {
      EXPECT_EQ(0, *counter_);
    }

   private:
    bool Run() override {
      if (++(*counter_) == 1) {
        std::unique_ptr<QueuedTask> myself(this);
        reply_queue_->PostTask(std::move(myself));
        // At this point, the object is owned by reply_queue_ and it's
        // theoratically possible that the object has been deleted (e.g. if
        // posting wasn't possible).  So, don't touch any member variables here.

        // Indicate to the current queue that ownership has been transferred.
        return false;
      } else {
        EXPECT_EQ(2, *counter_);
        EXPECT_TRUE(reply_queue_->IsCurrent());
        event_->Set();
        return true;  // Indicate that the object should be deleted.
      }
    }

    int* const counter_;
    TaskQueue* const reply_queue_;
    Event* const event_;
  };

  Event event(false, false);
  std::unique_ptr<QueuedTask> task(
      new ReusedTask(&call_count, &reply_queue, &event));

  post_queue.PostTask(std::move(task));
  EXPECT_TRUE(event.Wait(1000));
}

TEST(TaskQueueTest, PostAndReplyLambda) {
  static const char kPostQueue[] = "PostQueue";
  static const char kReplyQueue[] = "ReplyQueue";
  TaskQueue post_queue(kPostQueue);
  TaskQueue reply_queue(kReplyQueue);

  Event event(false, false);
  bool my_flag = false;
  post_queue.PostTaskAndReply([&my_flag]() { my_flag = true; },
                              [&event]() { event.Set(); }, &reply_queue);
  EXPECT_TRUE(event.Wait(1000));
  EXPECT_TRUE(my_flag);
}

void TestPostTaskAndReply(TaskQueue* work_queue,
                          const char* work_queue_name,
                          Event* event) {
  ASSERT_FALSE(work_queue->IsCurrent());
  work_queue->PostTaskAndReply(
      Bind(&CheckCurrent, work_queue_name, nullptr, work_queue),
      NewClosure([event]() { event->Set(); }));
}

// Does a PostTaskAndReply from within a task to post and reply to the current
// queue.  All in all there will be 3 tasks posted and run.
TEST(TaskQueueTest, PostAndReply2) {
  static const char kQueueName[] = "PostAndReply2";
  static const char kWorkQueueName[] = "PostAndReply2_Worker";
  TaskQueue queue(kQueueName);
  TaskQueue work_queue(kWorkQueueName);

  Event event(false, false);
  queue.PostTask(
      Bind(&TestPostTaskAndReply, &work_queue, kWorkQueueName, &event));
  EXPECT_TRUE(event.Wait(1000));
}

// Tests posting more messages than a queue can queue up.
// In situations like that, tasks will get dropped.
TEST(TaskQueueTest, PostALot) {
  // To destruct the event after the queue has gone out of scope.
  Event event(false, false);

  int tasks_executed = 0;
  int tasks_cleaned_up = 0;
  static const int kTaskCount = 0xffff;

  {
    static const char kQueueName[] = "PostALot";
    TaskQueue queue(kQueueName);

    // On linux, the limit of pending bytes in the pipe buffer is 0xffff.
    // So here we post a total of 0xffff+1 messages, which triggers a failure
    // case inside of the libevent queue implementation.

    queue.PostTask([&event]() { event.Wait(Event::kForever); });
    for (int i = 0; i < kTaskCount; ++i)
      queue.PostTask(NewClosure([&tasks_executed]() { ++tasks_executed; },
                                [&tasks_cleaned_up]() { ++tasks_cleaned_up; }));
    event.Set();  // Unblock the first task.
  }

  EXPECT_GE(tasks_cleaned_up, tasks_executed);
  EXPECT_EQ(kTaskCount, tasks_cleaned_up);
}

}  // namespace rtc
<|endoftext|>


<commit_before>
#include "TTASimDevice.h"
#include "TTASimRegion.h"
#include "TTASimControlRegion.h"
#include "accel-shared.h"

#include <SimpleSimulatorFrontend.hh>
#include <SimulatorCLI.hh>
#include <Machine.hh>
#include <MemorySystem.hh>
#include <AddressSpace.hh>
#include <Program.hh>
#include <Procedure.hh>
#include <Application.hh>

#include "pocl_cache.h"
#include "pocl_file_util.h"

#include <pthread.h>

#include <iostream>

static void *pocl_ttasim_thread (void *p);

  /**
 * A handler class for Ctrl-c signal.
 *
 * Stops the simulation (if it's running) and attaches the ttasim
 * console to it.
 */
class SigINTHandler : public Application::UnixSignalHandler {
public:
    /**
     * Constructor.
     *
     * @param target The target SimulatorFrontend instance.
     */
    SigINTHandler(TTASimDevice* d) :
        d_(d) {
    }

    /**
     * Stops the simulation.
     */
    virtual void execute(int /*data*/, siginfo_t* /*info*/);

private:
  TTASimDevice* d_;
};

TTASimDevice::TTASimDevice(char *adf_name) {

#ifdef ACCEL_TTASimMMAP_DEBUG
  POCL_MSG_PRINT_INFO(
      "TTASimMMAP: Initializing TTASimMMAPregion with Address %zu and Size %zu\n",
      Address, RegionSize);
#endif
  char adf_char[120];
  snprintf(adf_char, sizeof(adf_char), "%s.adf", adf_name);

  simulator_ = new SimpleSimulatorFrontend(adf_char, false);
  assert(simulator_ != NULL && "simulator null\n");
  simulatorCLI_ = new SimulatorCLI(simulator_->frontend());

   SigINTHandler* ctrlcHandler = new SigINTHandler(this);
   Application::setSignalHandler(SIGINT, *ctrlcHandler);

  const TTAMachine::Machine& mach = simulator_->machine();
/*  try {
    mach = TTAMachine::Machine::loadFromADF(adf_char);
  } catch (Exception &e) {
    POCL_MSG_WARN("Error: %s\n",e.errorMessage().c_str());
    POCL_ABORT("Couldn't open mach\n");
  }
  mach->writeToADF("temp.adf");
*/
  ControlMemory = new TTASimControlRegion(mach, this);

  discoverDeviceParameters();

  TTAMachine::Machine::FunctionUnitNavigator funav = mach.functionUnitNavigator();

  TTAMachine::Machine::AddressSpaceNavigator nav = mach.addressSpaceNavigator();
  TTAMachine::AddressSpace *global_as = nullptr;
  for (int i = 0; i < nav.count(); ++i) {
    global_as = nav.item(i);
    if (global_as->hasNumericalId(TTA_ASID_GLOBAL)) {
      break;
    }
  }
  assert(global_as != nullptr);

  MemorySystem &mems = simulator_->memorySystem();
  MemorySystem::MemoryPtr mem = mems.memory(*global_as);

  //Doesn't exist and should not ever be accessed
  InstructionMemory = nullptr;
  CQMemory = new TTASimRegion(cq_start, cq_size, mem);
  DataMemory = new TTASimRegion(dmem_start, dmem_size, mem);

  //For built-in kernel use-case. If the firmware.tpef exists, load it in
  char tpef_file[120];
  snprintf(tpef_file, sizeof(tpef_file), "%s.tpef", adf_name);
  if (pocl_exists(tpef_file)) {
    POCL_MSG_PRINT_INFO("Accel: Found built-in kernel firmware for ttasim. Loading it in.\n");
    loadProgram(tpef_file);
  } else {
    POCL_MSG_PRINT_INFO("File %s not found. Skipping program initialization\n", tpef_file);
  }

  POCL_INIT_LOCK(lock);
  POCL_INIT_COND(simulation_start_cond);
  pthread_create(&ttasim_thread, NULL, pocl_ttasim_thread, this);

}

TTASimDevice::~TTASimDevice() {
  shutdownRequested = true;
  simulator_->stop();
  POCL_LOCK(lock);
  POCL_SIGNAL_COND(simulation_start_cond);
  POCL_UNLOCK(lock);
  POCL_JOIN_THREAD(ttasim_thread);

  POCL_DESTROY_COND(simulation_start_cond);
  POCL_DESTROY_LOCK(lock);

  delete simulator_;
  delete simulatorCLI_;
}

void
TTASimDevice::loadProgram(char* tpef_file){
  if (simulator_->isRunning())
    ControlMemory->Write32(ACCEL_CONTROL_REG_COMMAND, ACCEL_RESET_CMD);
  while (simulator_->isRunning());
  /* Save the cycle count to maintain a global running cycle count
     over all the simulations. */
  //if (currentProgram != NULL)
  //  globalCycleCount += simulator_.cycleCount();
  simulator_->loadProgram(tpef_file);
}

void
TTASimDevice::loadProgramToDevice(almaif_kernel_data_t *kd, cl_kernel kernel, _cl_command_node *cmd)
{
  assert(kd);

  char tpef_file[POCL_FILENAME_LENGTH];
  char cachedir[POCL_FILENAME_LENGTH];
  // first try specialized
  pocl_cache_kernel_cachedir_path(tpef_file, kernel->program, cmd->program_device_i,
      kernel, "/parallel.tpef", cmd, 1);
  if (!pocl_exists(tpef_file)) {
    // if it doesn't exist, try specialized with local sizes 0-0-0
    // should pick either 0-0-0 or 0-0-0-goffs0
    _cl_command_node cmd_copy;
    memcpy(&cmd_copy, cmd, sizeof(_cl_command_node));
    cmd_copy.command.run.pc.local_size[0] = 0;
    cmd_copy.command.run.pc.local_size[1] = 0;
    cmd_copy.command.run.pc.local_size[2] = 0;
    pocl_cache_kernel_cachedir_path(tpef_file, kernel->program, cmd->program_device_i,
        kernel, "/parallel.tpef", &cmd_copy, 1);
    POCL_MSG_PRINT_INFO("Specialized kernel not found, using %s\n", cachedir);
  }

  loadProgram(tpef_file);

  char wg_func_name[120];
  snprintf(wg_func_name, sizeof(wg_func_name), "%s_workgroup_argbuffer", kernel->name);
  const TTAProgram::Program* prog = &simulator_->program();
  if (prog->hasProcedure(wg_func_name)){
    const TTAProgram::Procedure& proc = prog->procedure(wg_func_name);
    kd->kernel_address = proc.startAddress().location();
  } else {
      POCL_ABORT("Couldn't find wg_function procedure %s from the program\n", wg_func_name);
  }

  /*  for (int i=0; i<prog->procedureCount(); i++){
      POCL_MSG_PRINT_INFO("procedurename=%s\n", prog->procedure(i).name().c_str());
  }*/
  //TODO Figure out kernel addres

  ControlMemory->Write32(ACCEL_CONTROL_REG_COMMAND, ACCEL_CONTINUE_CMD);
//  //currentProgram = &simulator_->program();
}

  void *
pocl_ttasim_thread (void *p)
{
  TTASimDevice *d = (TTASimDevice*)p;
  do {
    if (d->shutdownRequested)
      goto EXIT;
    POCL_LOCK(d->lock);
    POCL_WAIT_COND(d->simulation_start_cond, d->lock);
    POCL_UNLOCK(d->lock);
    if (d->shutdownRequested)
      goto EXIT;

    d->simulator_->run();

    if (d->debuggerRequested) {
      d->debuggerRequested = false;
      d->simulatorCLI_->run();
      continue;
    }

    if (d->simulator_->hadRuntimeError()) {
      //            POCL_MSG_ERR ("Runtime error in a ttasim device! Launching
      //            debugger CLI \n"); d->simulatorCLI.run();
      POCL_ABORT("Runtime error in a ttasim device.\n");
    }

  } while (true);

EXIT:
  return NULL;
}

void TTASimDevice::restartProgram() {
  if(simulator_->isInitialized()){
    POCL_LOCK(lock);
    POCL_SIGNAL_COND(simulation_start_cond);
    POCL_UNLOCK(lock);
  }
  else {
    POCL_MSG_PRINT_INFO("Trying to start simulator without initialization\n");
  }
}

void SigINTHandler::execute(int /*data*/, siginfo_t* /*info*/) {
    std::cerr << "### ctrl-C handler" << std::endl;
    d_->debuggerRequested = true;
    d_->simulator_->stop();
    std::cerr << "### handler exit" << std::endl;
    /* Make it a one shot handler. Next Ctrl-C should kill the program. */
    Application::restoreSignalHandler(SIGINT);
}

<commit_msg>Accel: TTASim support separate CQ and data mem<commit_after>
#include "TTASimDevice.h"
#include "TTASimRegion.h"
#include "TTASimControlRegion.h"
#include "accel-shared.h"

#include <SimpleSimulatorFrontend.hh>
#include <SimulatorCLI.hh>
#include <Machine.hh>
#include <MemorySystem.hh>
#include <AddressSpace.hh>
#include <Program.hh>
#include <Procedure.hh>
#include <Application.hh>

#include "pocl_cache.h"
#include "pocl_file_util.h"

#include <pthread.h>

#include <iostream>

static void *pocl_ttasim_thread (void *p);

  /**
 * A handler class for Ctrl-c signal.
 *
 * Stops the simulation (if it's running) and attaches the ttasim
 * console to it.
 */
class SigINTHandler : public Application::UnixSignalHandler {
public:
    /**
     * Constructor.
     *
     * @param target The target SimulatorFrontend instance.
     */
    SigINTHandler(TTASimDevice* d) :
        d_(d) {
    }

    /**
     * Stops the simulation.
     */
    virtual void execute(int /*data*/, siginfo_t* /*info*/);

private:
  TTASimDevice* d_;
};

TTASimDevice::TTASimDevice(char *adf_name) {

#ifdef ACCEL_TTASimMMAP_DEBUG
  POCL_MSG_PRINT_INFO(
      "TTASimMMAP: Initializing TTASimMMAPregion with Address %zu and Size %zu\n",
      Address, RegionSize);
#endif
  char adf_char[120];
  snprintf(adf_char, sizeof(adf_char), "%s.adf", adf_name);

  simulator_ = new SimpleSimulatorFrontend(adf_char, false);
  assert(simulator_ != NULL && "simulator null\n");
  simulatorCLI_ = new SimulatorCLI(simulator_->frontend());

   SigINTHandler* ctrlcHandler = new SigINTHandler(this);
   Application::setSignalHandler(SIGINT, *ctrlcHandler);

  const TTAMachine::Machine& mach = simulator_->machine();
/*  try {
    mach = TTAMachine::Machine::loadFromADF(adf_char);
  } catch (Exception &e) {
    POCL_MSG_WARN("Error: %s\n",e.errorMessage().c_str());
    POCL_ABORT("Couldn't open mach\n");
  }
  mach->writeToADF("temp.adf");
*/
  ControlMemory = new TTASimControlRegion(mach, this);

  discoverDeviceParameters();

  TTAMachine::Machine::FunctionUnitNavigator funav = mach.functionUnitNavigator();

  TTAMachine::Machine::AddressSpaceNavigator nav = mach.addressSpaceNavigator();
  TTAMachine::AddressSpace *global_as = nullptr;
  TTAMachine::AddressSpace *cq_as = nullptr;

  for (int i = 0; i < nav.count(); ++i) {
    TTAMachine::AddressSpace *as = nav.item(i);
    if (as->hasNumericalId(TTA_ASID_GLOBAL)) {
      global_as = as;
    }
    if (as->hasNumericalId(TTA_ASID_LOCAL)) {
      cq_as = as;
    }
  }
  assert(global_as != nullptr);
  assert(cq_as != nullptr);

  MemorySystem &mems = simulator_->memorySystem();
  MemorySystem::MemoryPtr mem = mems.memory(*global_as);
  MemorySystem::MemoryPtr cq_mem = mems.memory(*cq_as);

  //Doesn't exist and should not ever be accessed
  InstructionMemory = nullptr;
  CQMemory = new TTASimRegion(cq_start, cq_size, cq_mem);
  DataMemory = new TTASimRegion(dmem_start, dmem_size, mem);

  //For built-in kernel use-case. If the firmware.tpef exists, load it in
  char tpef_file[120];
  snprintf(tpef_file, sizeof(tpef_file), "%s.tpef", adf_name);
  if (pocl_exists(tpef_file)) {
    POCL_MSG_PRINT_INFO("Accel: Found built-in kernel firmware for ttasim. Loading it in.\n");
    loadProgram(tpef_file);
  } else {
    POCL_MSG_PRINT_INFO("File %s not found. Skipping program initialization\n", tpef_file);
  }

  POCL_INIT_LOCK(lock);
  POCL_INIT_COND(simulation_start_cond);
  pthread_create(&ttasim_thread, NULL, pocl_ttasim_thread, this);

}

TTASimDevice::~TTASimDevice() {
  shutdownRequested = true;
  simulator_->stop();
  POCL_LOCK(lock);
  POCL_SIGNAL_COND(simulation_start_cond);
  POCL_UNLOCK(lock);
  POCL_JOIN_THREAD(ttasim_thread);

  POCL_DESTROY_COND(simulation_start_cond);
  POCL_DESTROY_LOCK(lock);

  delete simulator_;
  delete simulatorCLI_;
}

void
TTASimDevice::loadProgram(char* tpef_file){
  if (simulator_->isRunning())
    ControlMemory->Write32(ACCEL_CONTROL_REG_COMMAND, ACCEL_RESET_CMD);
  while (simulator_->isRunning());
  /* Save the cycle count to maintain a global running cycle count
     over all the simulations. */
  //if (currentProgram != NULL)
  //  globalCycleCount += simulator_.cycleCount();
  simulator_->loadProgram(tpef_file);
}

void
TTASimDevice::loadProgramToDevice(almaif_kernel_data_t *kd, cl_kernel kernel, _cl_command_node *cmd)
{
  assert(kd);

  char tpef_file[POCL_FILENAME_LENGTH];
  char cachedir[POCL_FILENAME_LENGTH];
  // first try specialized
  pocl_cache_kernel_cachedir_path(tpef_file, kernel->program, cmd->program_device_i,
      kernel, "/parallel.tpef", cmd, 1);
  if (!pocl_exists(tpef_file)) {
    // if it doesn't exist, try specialized with local sizes 0-0-0
    // should pick either 0-0-0 or 0-0-0-goffs0
    _cl_command_node cmd_copy;
    memcpy(&cmd_copy, cmd, sizeof(_cl_command_node));
    cmd_copy.command.run.pc.local_size[0] = 0;
    cmd_copy.command.run.pc.local_size[1] = 0;
    cmd_copy.command.run.pc.local_size[2] = 0;
    pocl_cache_kernel_cachedir_path(tpef_file, kernel->program, cmd->program_device_i,
        kernel, "/parallel.tpef", &cmd_copy, 1);
    POCL_MSG_PRINT_INFO("Specialized kernel not found, using %s\n", cachedir);
  }

  loadProgram(tpef_file);

  char wg_func_name[120];
  snprintf(wg_func_name, sizeof(wg_func_name), "%s_workgroup_argbuffer", kernel->name);
  const TTAProgram::Program* prog = &simulator_->program();
  if (prog->hasProcedure(wg_func_name)){
    const TTAProgram::Procedure& proc = prog->procedure(wg_func_name);
    kd->kernel_address = proc.startAddress().location();
  } else {
      POCL_ABORT("Couldn't find wg_function procedure %s from the program\n", wg_func_name);
  }

  /*  for (int i=0; i<prog->procedureCount(); i++){
      POCL_MSG_PRINT_INFO("procedurename=%s\n", prog->procedure(i).name().c_str());
  }*/
  //TODO Figure out kernel addres

  ControlMemory->Write32(ACCEL_CONTROL_REG_COMMAND, ACCEL_CONTINUE_CMD);
//  //currentProgram = &simulator_->program();
}

  void *
pocl_ttasim_thread (void *p)
{
  TTASimDevice *d = (TTASimDevice*)p;
  do {
    if (d->shutdownRequested)
      goto EXIT;
    POCL_LOCK(d->lock);
    POCL_WAIT_COND(d->simulation_start_cond, d->lock);
    POCL_UNLOCK(d->lock);
    if (d->shutdownRequested)
      goto EXIT;

    d->simulator_->run();

    if (d->debuggerRequested) {
      d->debuggerRequested = false;
      d->simulatorCLI_->run();
      continue;
    }

    if (d->simulator_->hadRuntimeError()) {
      //            POCL_MSG_ERR ("Runtime error in a ttasim device! Launching
      //            debugger CLI \n"); d->simulatorCLI.run();
      POCL_ABORT("Runtime error in a ttasim device.\n");
    }

  } while (true);

EXIT:
  return NULL;
}

void TTASimDevice::restartProgram() {
  if(simulator_->isInitialized()){
    POCL_LOCK(lock);
    POCL_SIGNAL_COND(simulation_start_cond);
    POCL_UNLOCK(lock);
  }
  else {
    POCL_MSG_PRINT_INFO("Trying to start simulator without initialization\n");
  }
}

void SigINTHandler::execute(int /*data*/, siginfo_t* /*info*/) {
    std::cerr << "### ctrl-C handler" << std::endl;
    d_->debuggerRequested = true;
    d_->simulator_->stop();
    std::cerr << "### handler exit" << std::endl;
    /* Make it a one shot handler. Next Ctrl-C should kill the program. */
    Application::restoreSignalHandler(SIGINT);
}

<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2021 Intel Corporation. All Rights Reserved.

//#cmake: static!
//#test:device D400*

#define CATCH_CONFIG_MAIN
#include <stdlib.h>
#include "../../catch.h"
#include "../../unit-tests-common.h"

using namespace rs2;
constexpr int RECEIVE_FRAMES_TIME = 10;

TEST_CASE("Syncer dynamic FPS - throughput test", "[live]")
{
    typedef enum configuration
    {
        IR_ONLY,
        IR_RGB_EXPOSURE,
        STOP
    }configuration;

    class ir_cfg
    {
    public:
        ir_cfg(sensor rgb_sensor,
            sensor ir_sensor,
            std::vector<rs2::stream_profile > rgb_stream_profile,
            std::vector<rs2::stream_profile > ir_stream_profile) : _rgb_sensor(rgb_sensor), _ir_sensor(ir_sensor),
            _rgb_stream_profile(rgb_stream_profile), _ir_stream_profile(ir_stream_profile) {}

        void test_configuration(configuration test)
        {
            std::cout << "==============================================" << std::endl;
            std::string cfg = test == IR_ONLY ? "IR Only" : "IR + RGB";
            std::cout << "Configuration: " << cfg << std::endl << std::endl;

            start_streaming(test);
            process_validate_frames(test);
            stop_streaming(test);
            // analysis
            analysis(test, _rgb_frames_arrival_info, "Color");
            analysis(test, _ir_frames_arrival_info);
        }

    private:
        void set_ir_exposure(float value = 18000.0f)
        {
            if (_ir_sensor.supports(RS2_OPTION_EXPOSURE))
                REQUIRE_NOTHROW(_ir_sensor.set_option(RS2_OPTION_EXPOSURE, value));
        }
        void start_streaming(configuration test)
        {
            _ir_sensor.set_option(RS2_OPTION_EXPOSURE, 1);
            _ir_sensor.open(_ir_stream_profile); // ir streams in all configurations
            _ir_sensor.start(_sync);
            if (test == IR_RGB_EXPOSURE)
            {
                _rgb_sensor.open(_rgb_stream_profile);
                _rgb_sensor.start(_sync);
            }
        }
        void stop_streaming(configuration test)
        {
            _ir_sensor.stop();
            _ir_sensor.close();
            if (test == IR_RGB_EXPOSURE)
            {
                _rgb_sensor.stop();
                _rgb_sensor.close();
            }
            set_ir_exposure(1.0f);
        }
        void process_validate_frames(configuration test)
        {
            auto t_start = std::chrono::system_clock::now();
            auto t_end = std::chrono::system_clock::now();

            bool exposure_set = false;
            auto process_frame = [&](const rs2::frame& f)
            {
                std::lock_guard<std::mutex> lock(_mutex);
                auto stream_type = std::string(f.get_profile().stream_name());
                // Only IR fps is relevant for this test, IR1 and IR2 have same fps so it is enough to get only one of them
                if (!(stream_type == "Infrared 1" || stream_type == "Color"))
                    return;
                if (!f.supports_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS) || !f.supports_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP))
                    return;
                auto frame_num = f.get_frame_number();
                auto actual_fps = (float)f.get_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS);
                auto frame_arrival = f.get_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP); // usec
                if (stream_type == "Infrared 1")
                    _ir_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
                if (stream_type == "Color")
                    _rgb_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
            };

            float delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
            while (delta < RECEIVE_FRAMES_TIME)
            {
                if (!exposure_set && delta > RECEIVE_FRAMES_TIME / 2)
                {
                    set_ir_exposure(); // set exposure to 18000 after 5 sec, set to 60000 to get fps = 15
                    exposure_set = true;
                }
                auto fs = _sync.wait_for_frames();
                for (const rs2::frame& ff : fs)
                {
                    process_frame(ff);
                }
                t_end = std::chrono::system_clock::now();
                delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
            }
        }
        void analysis(configuration test, std::vector <std::pair<float, float>>& frames_arrival_info, std::string stream_type = "Infrared 1")
        {
            if (frames_arrival_info.empty())
                return;
            float fps = 0.0f;
            while (!frames_arrival_info.empty() && fps < 10) // skip unstable frames at the beginning
            {
                fps = frames_arrival_info.front().second;
                frames_arrival_info.erase(frames_arrival_info.begin());
            }
            if (frames_arrival_info.size() < 10 || fps < 1.0f)
                return;
            std::vector<std::pair<float, float>>  vec[2]; // separate frames according to fps (before and after setting exposure)
            for (auto& frm : frames_arrival_info)
            {
                auto fps_ratio = frm.second / fps; // used ratio instead of precised fps because syncer doesn't change fps to exact value when running RGB
                if (fps_ratio > 0.9)
                    vec[0].push_back(frm);
                else
                    vec[1].push_back(frm);
            }

            int i = 0;
            for (auto& v : vec)
            {
                if (v.empty())
                    continue;
                auto dt = (v.back().first - v.front().first)/ 1000000;
                auto actual_fps = v.front().second;
                float calc_fps = (float)v.size() / dt;
                float fps_ratio = calc_fps / actual_fps;
                CAPTURE(stream_type, actual_fps, calc_fps, v.size());
                CHECK(fps_ratio > 0.9);
                CHECK(fps_ratio < 1.1);
                check_frame_drops(v);
                i += 1;
            }
        }
        void check_frame_drops(std::vector<std::pair<float, float>> frames)
        {
            float prev_frame_time = 0.0f;
            bool first = true;
            for (auto& frame : frames)
            {
                auto actual_fps = frame.second;
                float expected_dt_ms = 1000 / actual_fps; // convert sec -> msec
                auto frame_time = frame.first;
                float calc_dt_msec = ((float)frame_time - prev_frame_time)/1000; //convert usec -> msec
                float dt_msec_ratio = calc_dt_msec / expected_dt_ms;
                CAPTURE(expected_dt_ms, calc_dt_msec, dt_msec_ratio, frame_time, prev_frame_time);
                if (!first)
                    CHECK(dt_msec_ratio < 1.5);
                prev_frame_time = frame_time;
                first = false;
            }
        }

        sensor _rgb_sensor;
        sensor _ir_sensor;
        std::vector<rs2::stream_profile > _rgb_stream_profile;
        std::vector<rs2::stream_profile > _ir_stream_profile;
        std::vector <std::pair<float, float>> _ir_frames_arrival_info; //{HW timestamp, fps}
        std::vector <std::pair<float, float>> _rgb_frames_arrival_info; //{HW timestamp, fps}
        std::mutex _mutex;
        rs2::syncer _sync;
    };

    // Require at least one device to be plugged in
    rs2::context ctx;
    auto list = ctx.query_devices();
    REQUIRE(list.size());
    auto dev = list.front();
    auto sensors = dev.query_sensors();
    REQUIRE(dev.supports(RS2_CAMERA_INFO_PRODUCT_LINE));
    std::string device_type = list.front().get_info(RS2_CAMERA_INFO_PRODUCT_LINE);
    if (device_type != "D400")
    {
        std::cout << "This test runs only with D400 device!"<< std::endl;
        exit(EXIT_SUCCESS);
    }
    int width = 848;
    int height = 480;

    // extract IR/RGB sensors
    sensor rgb_sensor;
    sensor ir_sensor;
    std::vector<rs2::stream_profile > rgb_stream_profile;
    std::vector<rs2::stream_profile > ir_stream_profile;
    for (auto& s : sensors)
    {
        auto info = std::string(s.get_info(RS2_CAMERA_INFO_NAME));
        auto stream_profiles = s.get_stream_profiles();
        for (auto& sp : stream_profiles)
        {
            auto vid = sp.as<rs2::video_stream_profile>();
            if (!(vid.width() == width && vid.height() == height && vid.fps() == 60)) continue;
            if (sp.stream_type() == RS2_STREAM_COLOR && sp.format() == RS2_FORMAT_RGB8)
                rgb_stream_profile.push_back(sp);
            if (sp.stream_type() == RS2_STREAM_INFRARED && sp.format() == RS2_FORMAT_Y8)
                ir_stream_profile.push_back(sp);
        }
        if (s.supports(RS2_OPTION_GLOBAL_TIME_ENABLED))
        {
            s.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, 0);
            if (info == "RGB Camera")
                rgb_sensor = s;

            if (info == "Stereo Module")
                ir_sensor = s;
        }
    }
    if (rgb_sensor == NULL || ir_sensor == NULL)
    {
        std::cout << "ERROR : sensors are not valid!" << std::endl;
        exit(EXIT_FAILURE);
    }
    // test configurations
    configuration tests[2] = { IR_ONLY, IR_RGB_EXPOSURE }; // {cfg, exposure}
    for (auto& test : tests)
    {
        CAPTURE(test);
        ir_cfg test_cfg(rgb_sensor, ir_sensor, rgb_stream_profile, ir_stream_profile);
        test_cfg.test_configuration(test);
    }
}
<commit_msg>PR #9179 from Matan: fix throughput test following PR 9140<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2021 Intel Corporation. All Rights Reserved.

//#cmake: static!
//#test:device D400*

#include <stdlib.h>
#include "../../catch.h"
#include "../../unit-tests-common.h"

using namespace rs2;
constexpr int RECEIVE_FRAMES_TIME = 10;

TEST_CASE("Syncer dynamic FPS - throughput test", "[live]")
{
    typedef enum configuration
    {
        IR_ONLY,
        IR_RGB_EXPOSURE,
        STOP
    }configuration;

    class ir_cfg
    {
    public:
        ir_cfg(sensor rgb_sensor,
            sensor ir_sensor,
            std::vector<rs2::stream_profile > rgb_stream_profile,
            std::vector<rs2::stream_profile > ir_stream_profile) : _rgb_sensor(rgb_sensor), _ir_sensor(ir_sensor),
            _rgb_stream_profile(rgb_stream_profile), _ir_stream_profile(ir_stream_profile) {}

        void test_configuration(configuration test)
        {
            std::cout << "==============================================" << std::endl;
            std::string cfg = test == IR_ONLY ? "IR Only" : "IR + RGB";
            std::cout << "Configuration: " << cfg << std::endl << std::endl;

            start_streaming(test);
            process_validate_frames(test);
            stop_streaming(test);
            // analysis
            analysis(test, _rgb_frames_arrival_info, "Color");
            analysis(test, _ir_frames_arrival_info);
        }

    private:
        void set_ir_exposure(float value = 18000.0f)
        {
            if (_ir_sensor.supports(RS2_OPTION_EXPOSURE))
                REQUIRE_NOTHROW(_ir_sensor.set_option(RS2_OPTION_EXPOSURE, value));
        }
        void start_streaming(configuration test)
        {
            _ir_sensor.set_option(RS2_OPTION_EXPOSURE, 1);
            _ir_sensor.open(_ir_stream_profile); // ir streams in all configurations
            _ir_sensor.start(_sync);
            if (test == IR_RGB_EXPOSURE)
            {
                _rgb_sensor.open(_rgb_stream_profile);
                _rgb_sensor.start(_sync);
            }
        }
        void stop_streaming(configuration test)
        {
            _ir_sensor.stop();
            _ir_sensor.close();
            if (test == IR_RGB_EXPOSURE)
            {
                _rgb_sensor.stop();
                _rgb_sensor.close();
            }
            set_ir_exposure(1.0f);
        }
        void process_validate_frames(configuration test)
        {
            auto t_start = std::chrono::system_clock::now();
            auto t_end = std::chrono::system_clock::now();

            bool exposure_set = false;
            auto process_frame = [&](const rs2::frame& f)
            {
                std::lock_guard<std::mutex> lock(_mutex);
                auto stream_type = std::string(f.get_profile().stream_name());
                // Only IR fps is relevant for this test, IR1 and IR2 have same fps so it is enough to get only one of them
                if (!(stream_type == "Infrared 1" || stream_type == "Color"))
                    return;
                if (!f.supports_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS) || !f.supports_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP))
                    return;
                auto frame_num = f.get_frame_number();
                auto actual_fps = (float)f.get_frame_metadata(RS2_FRAME_METADATA_ACTUAL_FPS);
                auto frame_arrival = f.get_frame_metadata(RS2_FRAME_METADATA_FRAME_TIMESTAMP); // usec
                if (stream_type == "Infrared 1")
                    _ir_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
                if (stream_type == "Color")
                    _rgb_frames_arrival_info.push_back({ (float)frame_arrival, actual_fps });
            };

            float delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
            while (delta < RECEIVE_FRAMES_TIME)
            {
                if (!exposure_set && delta > RECEIVE_FRAMES_TIME / 2)
                {
                    set_ir_exposure(); // set exposure to 18000 after 5 sec, set to 60000 to get fps = 15
                    exposure_set = true;
                }
                auto fs = _sync.wait_for_frames();
                for (const rs2::frame& ff : fs)
                {
                    process_frame(ff);
                }
                t_end = std::chrono::system_clock::now();
                delta = (float)std::chrono::duration_cast<std::chrono::seconds>(t_end - t_start).count();
            }
        }
        void analysis(configuration test, std::vector <std::pair<float, float>>& frames_arrival_info, std::string stream_type = "Infrared 1")
        {
            if (frames_arrival_info.empty())
                return;
            float fps = 0.0f;
            while (!frames_arrival_info.empty() && fps < 10) // skip unstable frames at the beginning
            {
                fps = frames_arrival_info.front().second;
                frames_arrival_info.erase(frames_arrival_info.begin());
            }
            if (frames_arrival_info.size() < 10 || fps < 1.0f)
                return;
            std::vector<std::pair<float, float>>  vec[2]; // separate frames according to fps (before and after setting exposure)
            for (auto& frm : frames_arrival_info)
            {
                auto fps_ratio = frm.second / fps; // used ratio instead of precised fps because syncer doesn't change fps to exact value when running RGB
                if (fps_ratio > 0.9)
                    vec[0].push_back(frm);
                else
                    vec[1].push_back(frm);
            }

            int i = 0;
            for (auto& v : vec)
            {
                if (v.empty())
                    continue;
                auto dt = (v.back().first - v.front().first)/ 1000000;
                auto actual_fps = v.front().second;
                float calc_fps = (float)v.size() / dt;
                float fps_ratio = calc_fps / actual_fps;
                CAPTURE(stream_type, actual_fps, calc_fps, v.size());
                CHECK(fps_ratio > 0.9);
                CHECK(fps_ratio < 1.1);
                check_frame_drops(v);
                i += 1;
            }
        }
        void check_frame_drops(std::vector<std::pair<float, float>> frames)
        {
            float prev_frame_time = 0.0f;
            bool first = true;
            for (auto& frame : frames)
            {
                auto actual_fps = frame.second;
                float expected_dt_ms = 1000 / actual_fps; // convert sec -> msec
                auto frame_time = frame.first;
                float calc_dt_msec = ((float)frame_time - prev_frame_time)/1000; //convert usec -> msec
                float dt_msec_ratio = calc_dt_msec / expected_dt_ms;
                CAPTURE(expected_dt_ms, calc_dt_msec, dt_msec_ratio, frame_time, prev_frame_time);
                if (!first)
                    CHECK(dt_msec_ratio < 1.5);
                prev_frame_time = frame_time;
                first = false;
            }
        }

        sensor _rgb_sensor;
        sensor _ir_sensor;
        std::vector<rs2::stream_profile > _rgb_stream_profile;
        std::vector<rs2::stream_profile > _ir_stream_profile;
        std::vector <std::pair<float, float>> _ir_frames_arrival_info; //{HW timestamp, fps}
        std::vector <std::pair<float, float>> _rgb_frames_arrival_info; //{HW timestamp, fps}
        std::mutex _mutex;
        rs2::syncer _sync;
    };

    // Require at least one device to be plugged in
    rs2::context ctx;
    auto list = ctx.query_devices();
    REQUIRE(list.size());
    auto dev = list.front();
    auto sensors = dev.query_sensors();
    REQUIRE(dev.supports(RS2_CAMERA_INFO_PRODUCT_LINE));
    std::string device_type = list.front().get_info(RS2_CAMERA_INFO_PRODUCT_LINE);
    if (device_type != "D400")
    {
        std::cout << "This test runs only with D400 device!"<< std::endl;
        exit(EXIT_SUCCESS);
    }
    int width = 848;
    int height = 480;

    // extract IR/RGB sensors
    sensor rgb_sensor;
    sensor ir_sensor;
    std::vector<rs2::stream_profile > rgb_stream_profile;
    std::vector<rs2::stream_profile > ir_stream_profile;
    for (auto& s : sensors)
    {
        auto info = std::string(s.get_info(RS2_CAMERA_INFO_NAME));
        auto stream_profiles = s.get_stream_profiles();
        for (auto& sp : stream_profiles)
        {
            auto vid = sp.as<rs2::video_stream_profile>();
            if (!(vid.width() == width && vid.height() == height && vid.fps() == 60)) continue;
            if (sp.stream_type() == RS2_STREAM_COLOR && sp.format() == RS2_FORMAT_RGB8)
                rgb_stream_profile.push_back(sp);
            if (sp.stream_type() == RS2_STREAM_INFRARED && sp.format() == RS2_FORMAT_Y8)
                ir_stream_profile.push_back(sp);
        }
        if (s.supports(RS2_OPTION_GLOBAL_TIME_ENABLED))
        {
            s.set_option(RS2_OPTION_GLOBAL_TIME_ENABLED, 0);
            if (info == "RGB Camera")
                rgb_sensor = s;

            if (info == "Stereo Module")
                ir_sensor = s;
        }
    }
    if (rgb_sensor == NULL || ir_sensor == NULL)
    {
        std::cout << "ERROR : sensors are not valid!" << std::endl;
        exit(EXIT_FAILURE);
    }
    // test configurations
    configuration tests[2] = { IR_ONLY, IR_RGB_EXPOSURE }; // {cfg, exposure}
    for (auto& test : tests)
    {
        CAPTURE(test);
        ir_cfg test_cfg(rgb_sensor, ir_sensor, rgb_stream_profile, ir_stream_profile);
        test_cfg.test_configuration(test);
    }
}
<|endoftext|>


<commit_before>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2015, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "desktop/CrossDelegate.h"
#include "cross/Context.h"

using namespace std;

namespace chr
{
    namespace intern
    {
        CrossDelegate *instance = nullptr;
    }

    CrossDelegate& delegate()
    {
        return checkedReference(intern::instance);
    }

    // ---

    bool CrossDelegate::performInit()
    {
        if (!initialized_)
        {
            if (glfwInit())
            {
                glfwWindowHint(GLFW_SAMPLES, initInfo.windowInfo.aaSamples);
                glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

                glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
                glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

                initInfo.window = glfwCreateWindow(initInfo.windowInfo.size.x, initInfo.windowInfo.size.y, "", NULL, NULL);

                if (initInfo.window)
                {
                    glfwSetCursorPosCallback(initInfo.window, cursorPosCallback);
                    glfwSetMouseButtonCallback(initInfo.window, mouseButtonCallback);
                    glfwSetKeyCallback(initInfo.window, keyCallback);

                    glfwMakeContextCurrent(initInfo.window);
                    gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

                    // ---

                    intern::instance = this;
                    initialized_ = _init();
                }
            }
        }

        return initialized_;
    }

    void CrossDelegate::performUninit()
    {
        if (initialized_ && !setup_)
        {
            _uninit();

            initialized_ = false;
            intern::instance = nullptr;
        }
    }

    void CrossDelegate::performSetup()
    {
        if (!setup_ && initialized_)
        {
            _setup();

            // ---

            setup_ = true;
        }
    }

    void CrossDelegate::performShutdown()
    {
        if (setup_)
        {
            _shutdown();

            // ---

            setup_ = false;
        }
    }

    void CrossDelegate::performResize(const glm::vec2 &size)
    {
        setupInfo.windowInfo.size = size;
        sketch->performResize(size);
    }

    void CrossDelegate::performUpdate()
    {
        /*
         * SUBSEQUENT CALLS TO FrameClock::getTime() DURING THE FRAME WILL RETURN THE SAME TIME-SAMPLE
         */
        sketch->clock()->update(true);

        sketch->performUpdate();
        updateCount++;
    }

    void CrossDelegate::performDraw()
    {
        sketch->draw();
    }

    void CrossDelegate::run(int width, int height, int aaSamples)
    {
        initInfo.windowInfo = setupInfo.windowInfo = WindowInfo(width, height, aaSamples);

        performInit();
        performSetup();
        performResize(setupInfo.windowInfo.size);

        sketch->performStart(CrossSketch::START_REASON_VIEW_SHOWN);

        while (!glfwWindowShouldClose(initInfo.window))
        {
            intern::instance->processMouseEvents();
            performUpdate();
            performDraw();

            glfwSwapBuffers(initInfo.window);

            intern::instance->clearMouseEvents();
            glfwPollEvents();
        }

        sketch->performStop(CrossSketch::STOP_REASON_VIEW_HIDDEN);

        performShutdown();
        performUninit();
    }

    void CrossDelegate::processMouseEvents()
    {
        for (auto &event : mouseEvents)
        {
            switch (event.kind)
            {
                case MouseEvent::KIND_PRESSED:
                    sketch->addTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_DRAGGED:
                    sketch->updateTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_RELEASED:
                    sketch->removeTouch(event.button, event.x, event.y);
                    break;

                default:
                    break;
            }
        }
    }

    void CrossDelegate::clearMouseEvents()
    {
        mouseEvents.clear();
    }

    void CrossDelegate::cursorPosCallback(GLFWwindow* window, double xpos, double ypos)
    {
        intern::instance->mouseEvents.emplace_back(xpos, ypos, intern::instance->mouseButton, intern::instance->mousePressed ? MouseEvent::KIND_DRAGGED : MouseEvent::KIND_MOVED);

        intern::instance->mouseX = xpos;
        intern::instance->mouseY = ypos;
    }

    void CrossDelegate::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
    {
        intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, button, (action == GLFW_PRESS) ? MouseEvent::KIND_PRESSED : MouseEvent::KIND_RELEASED);

        intern::instance->mouseButton = button;
        intern::instance->mousePressed = (action == GLFW_PRESS);
    }

    void CrossDelegate::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
    {
        if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE))
        {
            glfwSetWindowShouldClose(window, true);
        }
    }
}
<commit_msg>DESKTOP: ADDING FULL-SCREEN CAPABILITIES<commit_after>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2015, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "desktop/CrossDelegate.h"
#include "cross/Context.h"

using namespace std;

namespace chr
{
    namespace intern
    {
        CrossDelegate *instance = nullptr;
    }

    CrossDelegate& delegate()
    {
        return checkedReference(intern::instance);
    }

    // ---

    bool CrossDelegate::performInit()
    {
        if (!initialized_)
        {
            if (glfwInit())
            {
                glfwWindowHint(GLFW_SAMPLES, initInfo.windowInfo.aaSamples);
                glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

                glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
                glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

                // ---

                int targetWidth;
                int targetHeight;

                if (initInfo.windowInfo.size.x * initInfo.windowInfo.size.y == 0)
                {
                    GLFWmonitor* monitor = glfwGetPrimaryMonitor();

                    if (monitor)
                    {
                        const GLFWvidmode *mode = glfwGetVideoMode(monitor);

                        targetWidth = mode->width;
                        targetHeight = mode->height;

                        glfwWindowHint(GLFW_RED_BITS, mode->redBits);
                        glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits);
                        glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits);
                        glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate);

                        initInfo.window = glfwCreateWindow(targetWidth, targetHeight, "", monitor, NULL);
                    }
                }
                else
                {
                    targetWidth = initInfo.windowInfo.size.x;
                    targetHeight = initInfo.windowInfo.size.y;

                    initInfo.window = glfwCreateWindow(targetWidth, targetHeight, "", NULL, NULL);
                }

                if (initInfo.window)
                {
                    setupInfo.windowInfo = WindowInfo(targetWidth, targetHeight, initInfo.windowInfo.aaSamples);

                    glfwSetCursorPosCallback(initInfo.window, cursorPosCallback);
                    glfwSetMouseButtonCallback(initInfo.window, mouseButtonCallback);
                    glfwSetKeyCallback(initInfo.window, keyCallback);

                    glfwMakeContextCurrent(initInfo.window);
                    gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

                    // ---

                    intern::instance = this;
                    initialized_ = _init();
                }
            }
        }

        return initialized_;
    }

    void CrossDelegate::performUninit()
    {
        if (initialized_ && !setup_)
        {
            _uninit();

            initialized_ = false;
            intern::instance = nullptr;
        }
    }

    void CrossDelegate::performSetup()
    {
        if (!setup_ && initialized_)
        {
            _setup();

            // ---

            setup_ = true;
        }
    }

    void CrossDelegate::performShutdown()
    {
        if (setup_)
        {
            _shutdown();

            // ---

            setup_ = false;
        }
    }

    void CrossDelegate::performResize(const glm::vec2 &size)
    {
        setupInfo.windowInfo.size = size;
        sketch->performResize(size);
    }

    void CrossDelegate::performUpdate()
    {
        /*
         * SUBSEQUENT CALLS TO FrameClock::getTime() DURING THE FRAME WILL RETURN THE SAME TIME-SAMPLE
         */
        sketch->clock()->update(true);

        sketch->performUpdate();
        updateCount++;
    }

    void CrossDelegate::performDraw()
    {
        sketch->draw();
    }

    void CrossDelegate::run(int width, int height, int aaSamples)
    {
        initInfo.windowInfo = WindowInfo(width, height, aaSamples);

        performInit(); // TODO: HANDLE FAILURES
        performSetup();
        performResize(setupInfo.windowInfo.size);

        sketch->performStart(CrossSketch::START_REASON_VIEW_SHOWN);

        while (!glfwWindowShouldClose(initInfo.window))
        {
            intern::instance->processMouseEvents();
            performUpdate();
            performDraw();

            glfwSwapBuffers(initInfo.window);

            intern::instance->clearMouseEvents();
            glfwPollEvents();
        }

        sketch->performStop(CrossSketch::STOP_REASON_VIEW_HIDDEN);

        performShutdown();
        performUninit();
    }

    void CrossDelegate::processMouseEvents()
    {
        for (auto &event : mouseEvents)
        {
            switch (event.kind)
            {
                case MouseEvent::KIND_PRESSED:
                    sketch->addTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_DRAGGED:
                    sketch->updateTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_RELEASED:
                    sketch->removeTouch(event.button, event.x, event.y);
                    break;

                default:
                    break;
            }
        }
    }

    void CrossDelegate::clearMouseEvents()
    {
        mouseEvents.clear();
    }

    void CrossDelegate::cursorPosCallback(GLFWwindow* window, double xpos, double ypos)
    {
        intern::instance->mouseEvents.emplace_back(xpos, ypos, intern::instance->mouseButton, intern::instance->mousePressed ? MouseEvent::KIND_DRAGGED : MouseEvent::KIND_MOVED);

        intern::instance->mouseX = xpos;
        intern::instance->mouseY = ypos;
    }

    void CrossDelegate::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
    {
        intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, button, (action == GLFW_PRESS) ? MouseEvent::KIND_PRESSED : MouseEvent::KIND_RELEASED);

        intern::instance->mouseButton = button;
        intern::instance->mousePressed = (action == GLFW_PRESS);
    }

    void CrossDelegate::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
    {
        if ((action == GLFW_PRESS) && (key == GLFW_KEY_ESCAPE))
        {
            glfwSetWindowShouldClose(window, true);
        }
    }
}
<|endoftext|>


<commit_before>#include "stan/math/functions/inv.hpp"
#include <gtest/gtest.h>
#include <stan/math/constants.hpp>

TEST(MathsSpecialFunctions, inv) {
  double y = 2.0;
  EXPECT_FLOAT_EQ(1 / y, stan::math::inv(y));

  y = 0.0;
  EXPECT_FLOAT_EQ(stan::math::positive_infinity(),stan::math::inv(y));

  y = -32.7;
  EXPECT_FLOAT_EQ(1 / y, stan::math::inv(y));
}
<commit_msg>added NaN test for inv<commit_after>#include <stan/math/functions/inv.hpp>
#include <stan/math/constants.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <gtest/gtest.h>

TEST(MathsSpecialFunctions, inv) {
  double y = 2.0;
  EXPECT_FLOAT_EQ(1 / y, stan::math::inv(y));

  y = 0.0;
  EXPECT_FLOAT_EQ(stan::math::positive_infinity(),stan::math::inv(y));

  y = -32.7;
  EXPECT_FLOAT_EQ(1 / y, stan::math::inv(y));
}

TEST(MathFunctions, inv_nan) {
  double nan = std::numeric_limits<double>::quiet_NaN();

  EXPECT_PRED1(boost::math::isnan<double>,
               stan::math::inv(nan));
}
<|endoftext|>