<commit_before>/* TA-LIB MySQL Data Source Driver Copyright (c) 2003, Pawel A. Konieczny
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * - Neither name of author nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* List of contributors:
 *
 *  Initial  Name/description
 *  -------------------------------------------------------------------
 *  PK       Pawel Konieczny
 *
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  101703 PK   First version.
 *
 */

/* Description:
 *    Allows to allocate/de-allocate TA_DataSourceHandle structure.
 */

/**** Headers ****/
extern "C" {
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "ta_memory.h"
#include "ta_trace.h"
#include "ta_fileindex.h"
#include "ta_token.h"
#include "ta_global.h"
}
#include "ta_mysql_handle.h"

/**** External functions declarations. ****/
/* None */

/**** External variables declarations. ****/
/* None */

/**** Global variables definitions.    ****/
/* None */

/**** Local declarations.              ****/
/* None */

/**** Local functions.    ****/
static TA_PrivateMySQLHandle *allocPrivateHandle( void );
static TA_RetCode freePrivateHandle( TA_PrivateMySQLHandle *privateHandle );
static TA_RetCode freeCategoryIndex( void *toBeFreed );
static TA_RetCode freeSymbolsIndex( void *toBeFreed );

/**** Local variables definitions.     ****/
TA_FILE_INFO;

/**** Global functions definitions.   ****/

TA_DataSourceHandle *TA_MYSQL_DataSourceHandleAlloc( const TA_AddDataSourceParamPriv *param )
{
   TA_DataSourceHandle *handle;
   TA_PrivateMySQLHandle *privateHandle;

   TA_ASSERT_RET( param != NULL, (TA_DataSourceHandle *)NULL );

   handle = (TA_DataSourceHandle *)TA_Malloc(sizeof( TA_DataSourceHandle ));
   if( !handle )
      return (TA_DataSourceHandle *)NULL;

   /* Initialized fields. */
   handle->nbCategory = 0;

   /* Allocate the opaque data. */
   handle->opaqueData = allocPrivateHandle();
   if( !handle->opaqueData )
   {
      TA_MYSQL_DataSourceHandleFree( handle );
      return (TA_DataSourceHandle *)NULL;
   }

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;
   privateHandle->param = param;

   return handle;
}

TA_RetCode TA_MYSQL_DataSourceHandleFree( TA_DataSourceHandle *handle )
{
   TA_PROLOG
   TA_PrivateMySQLHandle *privateHandle;

   if( !handle )
      return (TA_RetCode)TA_INTERNAL_ERROR(60);

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;

   TA_TRACE_BEGIN(  TA_MYSQL_DataSourceHandleFree );

   if( handle )
   {
      if( freePrivateHandle( (TA_PrivateMySQLHandle *)handle->opaqueData ) != TA_SUCCESS )
      {
         TA_FATAL(  NULL, handle, 0 );
      }

      TA_Free( handle );
   }

   TA_TRACE_RETURN( TA_SUCCESS );
}

TA_RetCode TA_MYSQL_BuildSymbolsIndex( TA_DataSourceHandle *handle )
{
   TA_PROLOG
   TA_RetCode retCode;
   TA_PrivateMySQLHandle *privateHandle;
   TA_MySQLCategoryNode *categoryNode;

   if( !handle )
      return (TA_RetCode)TA_INTERNAL_ERROR(61);

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;

   TA_TRACE_BEGIN(  TA_MYSQL_BuildSymbolsIndex );

   TA_ASSERT( privateHandle != NULL );
   TA_ASSERT( privateHandle->param != NULL );
   TA_ASSERT( privateHandle->param->category != NULL );
   TA_ASSERT( privateHandle->param->location != NULL );
   TA_ASSERT( privateHandle->con != NULL );

   /* De-allocate potentialy already existing category index. */
   if( privateHandle->theCategoryIndex != NULL )
   {
      retCode = TA_ListFreeAll(privateHandle->theCategoryIndex, &freeCategoryIndex);
      privateHandle->theCategoryIndex = NULL;
      if( retCode != TA_SUCCESS )
      {
         TA_TRACE_RETURN( retCode );
      }
   }

   /* Allocate new category index. */
   privateHandle->theCategoryIndex = TA_ListAlloc();
   if( !privateHandle->theCategoryIndex )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   /* create one category */
   categoryNode = (TA_MySQLCategoryNode*)TA_Malloc(sizeof( TA_MySQLCategoryNode ));
   memset(categoryNode, 0, sizeof( TA_MySQLCategoryNode ));
   categoryNode->category = TA_StringDup( TA_GetGlobalStringCache(), privateHandle->param->category);
   retCode = TA_ListAddTail(privateHandle->theCategoryIndex, categoryNode);

   TA_TRACE_RETURN( retCode );
}

/**** Local functions definitions.     ****/

static TA_PrivateMySQLHandle *allocPrivateHandle( void  )
{
   TA_PrivateMySQLHandle *privateHandle;

   privateHandle = (TA_PrivateMySQLHandle *)TA_Malloc( sizeof( TA_PrivateMySQLHandle ) );
   if( !privateHandle )
      return NULL;

   memset( privateHandle, 0, sizeof( TA_PrivateMySQLHandle ) );

   return privateHandle;
}

static TA_RetCode freePrivateHandle( TA_PrivateMySQLHandle *privateHandle )
{
   TA_RetCode retCode = TA_SUCCESS;

   if( privateHandle )
   {
      if( privateHandle->theCategoryIndex )
      {
         retCode = TA_ListFreeAll(privateHandle->theCategoryIndex, &freeCategoryIndex);
         privateHandle->theCategoryIndex = NULL;
      }

      if( privateHandle->con )
      try
      {
         delete privateHandle->con;
         privateHandle->con = NULL;
      }
      catch (...)
      {
         retCode = TA_INTERNAL_ERR;
         privateHandle->con = NULL;
      }

      TA_Free( privateHandle );
   }

   return retCode;
}

static TA_RetCode freeCategoryIndex( void *toBeFreed )
{
   TA_MySQLCategoryNode *node = (TA_MySQLCategoryNode*)toBeFreed;
   TA_RetCode retCode = TA_SUCCESS;

   if( !node )
      return TA_SUCCESS;

   if( node->category && retCode == TA_SUCCESS )
   {
      TA_StringFree( TA_GetGlobalStringCache(), node->category );
      node->category = NULL;
   }

   if( node->theSymbols && retCode == TA_SUCCESS )
   {
      retCode = TA_ListFreeAll( node->theSymbols, &freeSymbolsIndex);
      node->theSymbols = NULL;
   }

   if( retCode == TA_SUCCESS )
   {
      TA_Free(node);
   }

   return retCode;
}

static TA_RetCode freeSymbolsIndex( void *toBeFreed )
{
   TA_String *symbol = (TA_String*)toBeFreed;
   TA_RetCode retCode = TA_SUCCESS;

   if( symbol )
   {
      TA_StringFree( TA_GetGlobalStringCache(), symbol );
      symbol = NULL;
   }

   return retCode;
}
<commit_msg>Reporting category list using SQL query (duplicates not handled)<commit_after>/* TA-LIB MySQL Data Source Driver Copyright (c) 2003, Pawel A. Konieczny
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 *
 * - Neither name of author nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* List of contributors:
 *
 *  Initial  Name/description
 *  -------------------------------------------------------------------
 *  PK       Pawel Konieczny
 *
 *
 * Change history:
 *
 *  MMDDYY BY   Description
 *  -------------------------------------------------------------------
 *  101703 PK   First version.
 *
 */

/* Description:
 *    Allows to allocate/de-allocate TA_DataSourceHandle structure.
 */

/**** Headers ****/
extern "C" {
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "ta_memory.h"
#include "ta_trace.h"
#include "ta_fileindex.h"
#include "ta_token.h"
#include "ta_global.h"
}
#include "ta_mysql_handle.h"

/**** External functions declarations. ****/
/* None */

/**** External variables declarations. ****/
/* None */

/**** Global variables definitions.    ****/
/* None */

/**** Local declarations.              ****/
/* None */

/**** Local functions.    ****/
static TA_PrivateMySQLHandle *allocPrivateHandle( void );
static TA_RetCode freePrivateHandle( TA_PrivateMySQLHandle *privateHandle );
static TA_RetCode freeCategoryIndex( void *toBeFreed );
static TA_RetCode freeSymbolsIndex( void *toBeFreed );

/**** Local variables definitions.     ****/
TA_FILE_INFO;

/**** Global functions definitions.   ****/

TA_DataSourceHandle *TA_MYSQL_DataSourceHandleAlloc( const TA_AddDataSourceParamPriv *param )
{
   TA_DataSourceHandle *handle;
   TA_PrivateMySQLHandle *privateHandle;

   TA_ASSERT_RET( param != NULL, (TA_DataSourceHandle *)NULL );

   handle = (TA_DataSourceHandle *)TA_Malloc(sizeof( TA_DataSourceHandle ));
   if( !handle )
      return (TA_DataSourceHandle *)NULL;

   /* Initialized fields. */
   handle->nbCategory = 0;

   /* Allocate the opaque data. */
   handle->opaqueData = allocPrivateHandle();
   if( !handle->opaqueData )
   {
      TA_MYSQL_DataSourceHandleFree( handle );
      return (TA_DataSourceHandle *)NULL;
   }

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;
   privateHandle->param = param;

   return handle;
}

TA_RetCode TA_MYSQL_DataSourceHandleFree( TA_DataSourceHandle *handle )
{
   TA_PROLOG
   TA_PrivateMySQLHandle *privateHandle;

   if( !handle )
      return (TA_RetCode)TA_INTERNAL_ERROR(60);

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;

   TA_TRACE_BEGIN(  TA_MYSQL_DataSourceHandleFree );

   if( handle )
   {
      if( freePrivateHandle( (TA_PrivateMySQLHandle *)handle->opaqueData ) != TA_SUCCESS )
      {
         TA_FATAL(  NULL, handle, 0 );
      }

      TA_Free( handle );
   }

   TA_TRACE_RETURN( TA_SUCCESS );
}

TA_RetCode TA_MYSQL_BuildSymbolsIndex( TA_DataSourceHandle *handle )
{
   TA_PROLOG
   TA_RetCode retCode = TA_SUCCESS;
   TA_PrivateMySQLHandle *privateHandle;
   TA_MySQLCategoryNode *categoryNode;
   TA_StringCache *stringCache = TA_GetGlobalStringCache();

   if( !handle )
      return (TA_RetCode)TA_INTERNAL_ERROR(61);

   privateHandle = (TA_PrivateMySQLHandle *)handle->opaqueData;

   TA_TRACE_BEGIN(  TA_MYSQL_BuildSymbolsIndex );

   TA_ASSERT( privateHandle != NULL );
   TA_ASSERT( privateHandle->param != NULL );
   TA_ASSERT( privateHandle->param->category != NULL );
   TA_ASSERT( privateHandle->param->location != NULL );
   TA_ASSERT( privateHandle->con != NULL );

   /* De-allocate potentialy already existing category index. */
   if( privateHandle->theCategoryIndex != NULL )
   {
      retCode = TA_ListFreeAll(privateHandle->theCategoryIndex, &freeCategoryIndex);
      privateHandle->theCategoryIndex = NULL;
      if( retCode != TA_SUCCESS )
      {
         TA_TRACE_RETURN( retCode );
      }
   }

   /* Allocate new category index. */
   privateHandle->theCategoryIndex = TA_ListAlloc();
   if( !privateHandle->theCategoryIndex )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   if( strnicmp("SELECT ", TA_StringToChar(privateHandle->param->category), 7) == 0)
   {
      /* This is an SQL query; execute it to obtain the list of categories */
      try {
         Query query = privateHandle->con->query();
         // This creates a query object that is bound to con.

         query << TA_StringToChar(privateHandle->param->category);
         // You can write to the query object like you would any other ostrem

         Result res = query.store();
         // Query::store() executes the query and returns the results

         // cout << "Query: " << query.preview() << endl;
         // Query::preview() simply returns a string with the current query
         // string in it.

         // cout << "Records Found: " << res.size() << endl << endl;

         // find the category column number, if present
         for (unsigned int col = 0; col < res.columns(); col++)
         {
            if( strcmp(res.names(col).c_str(), "category") == 0 )
               break;
         }
         if( col == res.columns() )
         {
            throw BadQuery("Column 'category' not found");
         }

         Row row;
         Result::iterator i;
         // The Result class has a read-only Random Access Iterator
         for (i = res.begin(); i != res.end(); i++) {
  	        row = *i;
            TA_String *cat_name = TA_StringAlloc( stringCache, row[col] );

            if( !cat_name )
            {
               TA_TRACE_RETURN( TA_ALLOC_ERR );
            }

            if( strcmp(TA_StringToChar(cat_name), "") == 0)  // ignore NULL fields
               continue;

            categoryNode = (TA_MySQLCategoryNode*)TA_Malloc(sizeof( TA_MySQLCategoryNode ));
            if( !categoryNode )
            {
               TA_StringFree(stringCache, cat_name);
               TA_TRACE_RETURN( TA_ALLOC_ERR );
            }
            memset(categoryNode, 0, sizeof( TA_MySQLCategoryNode ));

            categoryNode->category = cat_name;
            retCode = TA_ListAddTail( privateHandle->theCategoryIndex, categoryNode );
            if( retCode != TA_SUCCESS )
            {
               TA_StringFree(stringCache, categoryNode->category);
               TA_Free(categoryNode);
               break;
            }
         }
      }
      catch (BadQuery er)
      {
         // handle any connection or query errors that may come up
         retCode = TA_CATEGORY_NOT_FOUND;
      }
   }
   else
   {
      /* Create one category, taking the category sting literally */
      categoryNode = (TA_MySQLCategoryNode*)TA_Malloc(sizeof( TA_MySQLCategoryNode ));
      if( !categoryNode )
      {
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }
      memset(categoryNode, 0, sizeof( TA_MySQLCategoryNode ));

      categoryNode->category = TA_StringDup( stringCache, privateHandle->param->category);
      retCode = TA_ListAddTail(privateHandle->theCategoryIndex, categoryNode);
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree(stringCache, categoryNode->category);
         TA_Free(categoryNode);
      }
   }

   TA_TRACE_RETURN( retCode );
}

/**** Local functions definitions.     ****/

static TA_PrivateMySQLHandle *allocPrivateHandle( void  )
{
   TA_PrivateMySQLHandle *privateHandle;

   privateHandle = (TA_PrivateMySQLHandle *)TA_Malloc( sizeof( TA_PrivateMySQLHandle ) );
   if( !privateHandle )
      return NULL;

   memset( privateHandle, 0, sizeof( TA_PrivateMySQLHandle ) );

   return privateHandle;
}

static TA_RetCode freePrivateHandle( TA_PrivateMySQLHandle *privateHandle )
{
   TA_RetCode retCode = TA_SUCCESS;

   if( privateHandle )
   {
      if( privateHandle->theCategoryIndex )
      {
         retCode = TA_ListFreeAll(privateHandle->theCategoryIndex, &freeCategoryIndex);
         privateHandle->theCategoryIndex = NULL;
      }

      if( privateHandle->con )
      try
      {
         delete privateHandle->con;
         privateHandle->con = NULL;
      }
      catch (...)
      {
         retCode = TA_INTERNAL_ERR;
         privateHandle->con = NULL;
      }

      TA_Free( privateHandle );
   }

   return retCode;
}

static TA_RetCode freeCategoryIndex( void *toBeFreed )
{
   TA_MySQLCategoryNode *node = (TA_MySQLCategoryNode*)toBeFreed;
   TA_RetCode retCode = TA_SUCCESS;

   if( !node )
      return TA_SUCCESS;

   if( node->category && retCode == TA_SUCCESS )
   {
      TA_StringFree( TA_GetGlobalStringCache(), node->category );
      node->category = NULL;
   }

   if( node->theSymbols && retCode == TA_SUCCESS )
   {
      retCode = TA_ListFreeAll( node->theSymbols, &freeSymbolsIndex);
      node->theSymbols = NULL;
   }

   if( retCode == TA_SUCCESS )
   {
      TA_Free(node);
   }

   return retCode;
}

static TA_RetCode freeSymbolsIndex( void *toBeFreed )
{
   TA_String *symbol = (TA_String*)toBeFreed;
   TA_RetCode retCode = TA_SUCCESS;

   if( symbol )
   {
      TA_StringFree( TA_GetGlobalStringCache(), symbol );
      symbol = NULL;
   }

   return retCode;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <stdexcept>
#include <chrono>
#include <vector>
#include <memory>
#include <cmath>
#include <thread>
#include <signal.h>
#include <sched.h>
#include <sys/mman.h>

#include <eeros/core/Executor.hpp>
#include <eeros/task/Async.hpp>
#include <eeros/task/Lambda.hpp>
#include <eeros/task/HarmonicTaskList.hpp>
#include <eeros/control/TimeDomain.hpp>
#include <eeros/safety/SafetySystem.hpp>

volatile bool running = true;

void signalHandler(int signum) {
	running = false;
}

using namespace eeros;

namespace {

	using Logger = logger::Logger<logger::LogWriter>;

	struct TaskThread {
		TaskThread(double period, task::Periodic &task, task::HarmonicTaskList tasks) :
			taskList(tasks), async(taskList, task.getRealtime(), task.getNice())
		{
			async.counter.setPeriod(period);
			async.counter.monitors = task.monitors;
		}
		task::HarmonicTaskList taskList;
		task::Async async;
	};

	struct Harmonic {
		Harmonic(task::Periodic &base, task::Periodic &task) {
			k = static_cast<int>(task.getPeriod() / base.getPeriod());
			actualPeriod = k * base.getPeriod();
			deviation = std::abs(task.getPeriod() - actualPeriod) / task.getPeriod();
		}

		int k;
		double actualPeriod;
		double deviation;
	};

	template < typename F >
	void traverse(std::vector<task::Periodic> &tasks, F func) {
		for (auto &t: tasks) {
			func(&t);
			traverse(t.before, func);
			traverse(t.after, func);
		}
	}

	task::Harmonic createThread(Logger &log, std::vector<std::shared_ptr<TaskThread>> &threads, task::Periodic &baseTask, task::Periodic &task, std::vector<task::Harmonic> &output);

	void createThreads(Logger &log, std::vector<task::Periodic> &tasks, std::vector<std::shared_ptr<TaskThread>> &threads, task::Periodic &baseTask, task::HarmonicTaskList &output) {
		for (task::Periodic &t: tasks) {
			createThread(log, threads, baseTask, t, output.tasks);
		}
	}

	task::Harmonic createThread(Logger &log, std::vector<std::shared_ptr<TaskThread>> &threads, task::Periodic &baseTask, task::Periodic &task, std::vector<task::Harmonic> &output) {
		Harmonic param(baseTask, task);
		task::HarmonicTaskList taskList;

		if (task.before.size() > 0) {
			createThreads(log, task.before, threads, task, taskList);
		}
		taskList.add(task.getTask());
		if (task.after.size() > 0) {
			createThreads(log, task.after, threads, task, taskList);
		}

		if (task.getRealtime())
			log.trace() << "creating harmonic realtime task '" << task.getName()
						<< "' with period " << param.actualPeriod << " sec (k = "
						<< param.k << ") and priority " << (Executor::basePriority - task.getNice())
						<< " based on '" << baseTask.getName() << "'";
		else
			log.trace() << "creating harmonic task '" << task.getName() << "' with period "
						<< param.actualPeriod << " sec (k = " << param.k << ")"
						<< " based on '" << baseTask.getName() << "'";

		if (param.deviation > 0.01) throw std::runtime_error("period deviation too high");

		if (task.getRealtime() && task.getNice() <= 0)
			throw std::runtime_error("priority not set");

		if (taskList.tasks.size() == 0)
			throw std::runtime_error("no task to execute");

		threads.push_back(std::make_shared<TaskThread>(param.actualPeriod, task, taskList));
		output.emplace_back(threads.back()->async, param.k);
	}

}

Executor::Executor() :
	log('E'), period(0), mainTask(nullptr) { }

Executor::~Executor() {

}

Executor& Executor::instance() {
	static Executor executor;
	return executor;
}

void Executor::setPeriod(double period) {
	if (this->period != 0.0)
		throw std::runtime_error("The period of the executor can only be set once.");
	this->period = period;
	counter.setPeriod(period);
}

void Executor::setMainTask(task::Periodic &mainTask) {
	if (this->mainTask != nullptr)
		throw std::runtime_error("you can only define one main task per executor");
	if (mainTask.getPeriod() != period)
		throw std::runtime_error("the main task must have the same period as the executor");
	this->mainTask = &mainTask;
}

void Executor::setMainTask(safety::SafetySystem &mainTask) {
	task::Periodic *task = new task::Periodic("main", mainTask.getPeriod(), mainTask, true);
	setMainTask(*task);
}

void Executor::add(task::Periodic task) {
	tasks.push_back(task);
}

void Executor::add(control::TimeDomain &timedomain) {
	task::Periodic task(timedomain.getName().c_str(), timedomain.getPeriod(), timedomain, timedomain.getRealtime());
	tasks.push_back(task);
}

void Executor::prefault_stack() {
	unsigned char dummy[8*1024] = {};
}

bool Executor::lock_memory() {
	return (mlockall(MCL_CURRENT | MCL_FUTURE) != -1);
}

bool Executor::set_priority(int nice) {
	struct sched_param schedulingParam;
	schedulingParam.sched_priority = (Executor::basePriority - nice);
	return (sched_setscheduler(0, SCHED_FIFO, &schedulingParam) != -1);
}

void Executor::assignPriorities()
{
	std::vector<task::Periodic*> priorityAssignments;

	// add task to list of priority assignments
	traverse(tasks, [&priorityAssignments] (task::Periodic *task) {
		priorityAssignments.push_back(task);
	});

	// sort list of priority assignments
	std::sort(priorityAssignments.begin(), priorityAssignments.end(), [] (task::Periodic *a, task::Periodic *b) -> bool {
		if (a->getRealtime() == b->getRealtime())
			return (a->getPeriod() < b->getPeriod());
		else
			return a->getRealtime();
	});

	// assign priorities
	int nice = 1;
	for (auto t: priorityAssignments) {
		if (t->getRealtime()) {
			t->setNice(nice++);
		}
	}
}

void Executor::run() {
	log.trace() << "starting executor with base period " << period << " sec and priority " << basePriority;

	if (period == 0.0)
		throw std::runtime_error("period of executor not set");

	log.trace() << "assigning priorities";
	assignPriorities();

	Runnable *mainTask = nullptr;

	if (this->mainTask != nullptr) {
		mainTask = &this->mainTask->getTask();
		log.trace() << "setting '" << this->mainTask->getName() << "' as main task";
	}

	std::vector<std::shared_ptr<TaskThread>> threads; // smart pointer used because async objects must not be copied
	task::HarmonicTaskList list;
	task::Periodic executorTask("executor", period, this, true);

	createThreads(log, tasks, threads, executorTask, list);

	signal(SIGHUP, signalHandler);
	signal(SIGINT, signalHandler);
	signal(SIGQUIT, signalHandler);
	signal(SIGKILL, signalHandler);
	signal(SIGTERM, signalHandler);
	signal(SIGPWR, signalHandler);

	using seconds = std::chrono::duration<double, std::chrono::seconds::period>;

	// TODO: implement this with ready-flag (wait for all threads to be ready instead of blind sleep)
	std::this_thread::sleep_for(seconds(1)); // wait 1 sec to allow threads to be created

	if (!set_priority(0))
		log.error() << "could not set realtime priority";

	prefault_stack();

	if (!lock_memory())
		log.error() << "could not lock memory in RAM";

	log.trace() << "starting periodic execution";

	auto next_cylce = std::chrono::steady_clock::now() + seconds(period);
	while (running) {
		std::this_thread::sleep_until(next_cylce);

		counter.tick();
		list.run();

		if (mainTask != nullptr)
			mainTask->run();

		counter.tock();
		next_cylce += seconds(period);
	}

	log.trace() << "stopping all threads";

	for (auto &t: threads)
		t->async.stop();

	log.trace() << "joining all threads";

	for (auto &t: threads)
		t->async.join();

	log.trace() << "exiting executor";
}
<commit_msg>improve readability<commit_after>#include <algorithm>
#include <stdexcept>
#include <chrono>
#include <vector>
#include <memory>
#include <cmath>
#include <thread>
#include <signal.h>
#include <sched.h>
#include <sys/mman.h>

#include <eeros/core/Executor.hpp>
#include <eeros/task/Async.hpp>
#include <eeros/task/Lambda.hpp>
#include <eeros/task/HarmonicTaskList.hpp>
#include <eeros/control/TimeDomain.hpp>
#include <eeros/safety/SafetySystem.hpp>

volatile bool running = true;

void signalHandler(int signum) {
	running = false;
}

using namespace eeros;

namespace {

	using Logger = logger::Logger<logger::LogWriter>;

	struct TaskThread {
		TaskThread(double period, task::Periodic &task, task::HarmonicTaskList tasks) :
			taskList(tasks), async(taskList, task.getRealtime(), task.getNice())
		{
			async.counter.setPeriod(period);
			async.counter.monitors = task.monitors;
		}
		task::HarmonicTaskList taskList;
		task::Async async;
	};

	template < typename F >
	void traverse(std::vector<task::Periodic> &tasks, F func) {
		for (auto &t: tasks) {
			func(&t);
			traverse(t.before, func);
			traverse(t.after, func);
		}
	}

 	void createThread(Logger &log, task::Periodic &task, task::Periodic &baseTask, std::vector<std::shared_ptr<TaskThread>> &threads, std::vector<task::Harmonic> &output);

	void createThreads(Logger &log, std::vector<task::Periodic> &tasks, task::Periodic &baseTask, std::vector<std::shared_ptr<TaskThread>> &threads, task::HarmonicTaskList &output) {
		for (task::Periodic &t: tasks) {
			createThread(log, t, baseTask, threads, output.tasks);
		}
	}

	void createThread(Logger &log, task::Periodic &task, task::Periodic &baseTask, std::vector<std::shared_ptr<TaskThread>> &threads, std::vector<task::Harmonic> &output) {
		int k = static_cast<int>(task.getPeriod() / baseTask.getPeriod());
		double actualPeriod = k * baseTask.getPeriod();
		double deviation = std::abs(task.getPeriod() - actualPeriod) / task.getPeriod();
		task::HarmonicTaskList taskList;

		if (task.before.size() > 0) {
			createThreads(log, task.before, task, threads, taskList);
		}
		taskList.add(task.getTask());
		if (task.after.size() > 0) {
			createThreads(log, task.after, task, threads, taskList);
		}

		if (task.getRealtime())
			log.trace() << "creating harmonic realtime task '" << task.getName()
						<< "' with period " << actualPeriod << " sec (k = "
						<< k << ") and priority " << (Executor::basePriority - task.getNice())
						<< " based on '" << baseTask.getName() << "'";
		else
			log.trace() << "creating harmonic task '" << task.getName() << "' with period "
						<< actualPeriod << " sec (k = " << k << ")"
						<< " based on '" << baseTask.getName() << "'";

		if (deviation > 0.01) throw std::runtime_error("period deviation too high");

		if (task.getRealtime() && task.getNice() <= 0)
			throw std::runtime_error("priority not set");

		if (taskList.tasks.size() == 0)
			throw std::runtime_error("no task to execute");

		threads.push_back(std::make_shared<TaskThread>(actualPeriod, task, taskList));
		output.emplace_back(threads.back()->async, k);
	}
}

Executor::Executor() :
	log('E'), period(0), mainTask(nullptr) { }

Executor::~Executor() {

}

Executor& Executor::instance() {
	static Executor executor;
	return executor;
}

void Executor::setPeriod(double period) {
	if (this->period != 0.0)
		throw std::runtime_error("The period of the executor can only be set once.");
	this->period = period;
	counter.setPeriod(period);
}

void Executor::setMainTask(task::Periodic &mainTask) {
	if (this->mainTask != nullptr)
		throw std::runtime_error("you can only define one main task per executor");
	if (mainTask.getPeriod() != period)
		throw std::runtime_error("the main task must have the same period as the executor");
	this->mainTask = &mainTask;
}

void Executor::setMainTask(safety::SafetySystem &ss) {
	task::Periodic *task = new task::Periodic("safety system", ss.getPeriod(), ss, true);
	setMainTask(*task);
}

void Executor::add(task::Periodic task) {
	tasks.push_back(task);
}

void Executor::add(control::TimeDomain &timedomain) {
	task::Periodic task(timedomain.getName().c_str(), timedomain.getPeriod(), timedomain, timedomain.getRealtime());
	tasks.push_back(task);
}

void Executor::prefault_stack() {
	unsigned char dummy[8*1024] = {};
}

bool Executor::lock_memory() {
	return (mlockall(MCL_CURRENT | MCL_FUTURE) != -1);
}

bool Executor::set_priority(int nice) {
	struct sched_param schedulingParam;
	schedulingParam.sched_priority = (Executor::basePriority - nice);
	return (sched_setscheduler(0, SCHED_FIFO, &schedulingParam) != -1);
}

void Executor::assignPriorities()
{
	std::vector<task::Periodic*> priorityAssignments;

	// add task to list of priority assignments
	traverse(tasks, [&priorityAssignments] (task::Periodic *task) {
		priorityAssignments.push_back(task);
	});

	// sort list of priority assignments
	std::sort(priorityAssignments.begin(), priorityAssignments.end(), [] (task::Periodic *a, task::Periodic *b) -> bool {
		if (a->getRealtime() == b->getRealtime())
			return (a->getPeriod() < b->getPeriod());
		else
			return a->getRealtime();
	});

	// assign priorities
	int nice = 1;
	for (auto t: priorityAssignments) {
		if (t->getRealtime()) {
			t->setNice(nice++);
		}
	}
}

void Executor::run() {
	log.trace() << "starting executor with base period " << period << " sec and priority " << basePriority;

	if (period == 0.0)
		throw std::runtime_error("period of executor not set");

	log.trace() << "assigning priorities";
	assignPriorities();

	Runnable *mainTask = nullptr;

	if (this->mainTask != nullptr) {
		mainTask = &this->mainTask->getTask();
		log.trace() << "setting '" << this->mainTask->getName() << "' as main task";
	}

	std::vector<std::shared_ptr<TaskThread>> threads; // smart pointer used because async objects must not be copied
	task::HarmonicTaskList taskList;
	task::Periodic executorTask("executor", period, this, true);

	createThreads(log, tasks, executorTask, threads, taskList);

	signal(SIGHUP, signalHandler);
	signal(SIGINT, signalHandler);
	signal(SIGQUIT, signalHandler);
	signal(SIGKILL, signalHandler);
	signal(SIGTERM, signalHandler);
	signal(SIGPWR, signalHandler);

	using seconds = std::chrono::duration<double, std::chrono::seconds::period>;

	// TODO: implement this with ready-flag (wait for all threads to be ready instead of blind sleep)
	std::this_thread::sleep_for(seconds(1)); // wait 1 sec to allow threads to be created

	if (!set_priority(0))
		log.error() << "could not set realtime priority";

	prefault_stack();

	if (!lock_memory())
		log.error() << "could not lock memory in RAM";

	log.trace() << "starting periodic execution";

	auto next_cylce = std::chrono::steady_clock::now() + seconds(period);
	while (running) {
		std::this_thread::sleep_until(next_cylce);

		counter.tick();
		taskList.run();

		if (mainTask != nullptr)
			mainTask->run();

		counter.tock();
		next_cylce += seconds(period);
	}

	log.trace() << "stopping all threads";

	for (auto &t: threads)
		t->async.stop();

	log.trace() << "joining all threads";

	for (auto &t: threads)
		t->async.join();

	log.trace() << "exiting executor";
}
<|endoftext|>


<commit_before>/* Calf DSP Library
 * Example audio modules - parameters and LADSPA wrapper instantiation
 *
 * Copyright (C) 2001-2008 Krzysztof Foltman
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include <config.h>
#include <assert.h>
#include <memory.h>
#if USE_JACK
#include <jack/jack.h>
#endif
#include <calf/giface.h>
#include <calf/lv2wrap.h>
#include <calf/modules.h>
#include <calf/modules_dev.h>

using namespace synth;

#if USE_LADSPA
#define LADSPA_WRAPPER(mod) static synth::ladspa_wrapper<mod##_audio_module> ladspa_##mod(mod##_info);
#else
#define LADSPA_WRAPPER(mod)
#endif

#if USE_LV2
#define LV2_WRAPPER(mod) static synth::lv2_wrapper<mod##_audio_module> lv2_##mod(mod##_info);
#else
#define LV2_WRAPPER(mod)
#endif

#define ALL_WRAPPERS(mod) LADSPA_WRAPPER(mod) LV2_WRAPPER(mod)

const char *copyright = "(C) 2001-2007 Krzysztof Foltman, license: LGPL";

////////////////////////////////////////////////////////////////////////////

const char *flanger_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

parameter_properties flanger_audio_module::param_props[] = {
    { 0.1,      0.1, 10,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "min_delay", "Minimum delay" },
    { 0.5,      0.1, 10,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "mod_depth", "Modulation depth" },
    { 0.25,    0.01, 20,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Modulation rate" },
    { 0.90,   -0.99, 0.99,  0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" },
    { 1,          0, 2,     0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
};

static synth::ladspa_info flanger_info = { 0x847d, "Flanger", "Calf Flanger", "Krzysztof Foltman", copyright, "FlangerPlugin" };

ALL_WRAPPERS(flanger)

////////////////////////////////////////////////////////////////////////////

const char *reverb_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *reverb_room_sizes[] = { "Small", "Medium", "Large", "Tunnel-like" };

parameter_properties reverb_audio_module::param_props[] = {
    { 1.5,      0.5, 15.0,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "decay_time", "Decay time" },
    { 5000,    2000,20000,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hf_damp", "High Frq Damp" },
    { 2,          0,    3,    0, PF_ENUM | PF_CTL_COMBO , reverb_room_sizes, "room_size", "Room size", },
    { 0.5,        0,    1,    0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "diffusion", "Diffusion" },
    { 0.25,       0,    2,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
};

static synth::ladspa_info reverb_info = { 0x847e, "Reverb", "Calf Reverb", "Krzysztof Foltman", copyright, "ReverbPlugin" };

ALL_WRAPPERS(reverb)

////////////////////////////////////////////////////////////////////////////

const char *filter_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *filter_choices[] = {
    "12dB/oct Lowpass",
    "24dB/oct Lowpass",
    "36dB/oct Lowpass",
    "12dB/oct Highpass",
    "24dB/oct Highpass",
    "36dB/oct Highpass",
};

parameter_properties filter_audio_module::param_props[] = {
    { 2000,      10,20000,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" },
    { 0.707,  0.707,   20,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "res", "Resonance" },
    { 0,          0,    5,    1, PF_ENUM | PF_CTL_COMBO, filter_choices, "mode", "Mode" },
    { 20,         5,  100,    1, PF_INT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Inertia"},
};

static synth::ladspa_info filter_info = { 0x847f, "Filter", "Calf Filter", "Krzysztof Foltman", copyright, "FilterPlugin" };

ALL_WRAPPERS(filter)

////////////////////////////////////////////////////////////////////////////

const char *vintage_delay_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *vintage_delay_mixmodes[] = {
    "Stereo",
    "Ping-Pong",
};

const char *vintage_delay_fbmodes[] = {
    "Plain",
    "Tape",
    "Old Tape",
};

parameter_properties vintage_delay_audio_module::param_props[] = {
    { 120,      30,    300,   0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_BPM, NULL, "bpm", "Tempo" },
    {  4,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "subdiv", "Subdivide"},
    {  3,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_l", "Time L"},
    {  5,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_r", "Time R"},
    { 0.5,       0,    1,     0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "feedback", "Feedback" },
    { 0.25,      0,    2,   100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
    { 1,         0,    1,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" },
    { 1,         0,    2,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_fbmodes, "medium", "Medium" },
};

static synth::ladspa_info vintage_delay_info = { 0x8482, "VintageDelay", "Calf Vintage Delay", "Krzysztof Foltman", copyright, "DelayPlugin" };

ALL_WRAPPERS(vintage_delay)

////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_EXPERIMENTAL
static synth::ladspa_info rotary_speaker_info = { 0x8483, "RotarySpeaker", "Calf Rotary Speaker", "Krzysztof Foltman", copyright, "SimulationPlugin" };

ALL_WRAPPERS(rotary_speaker)

static synth::ladspa_info organ_info = { 0x8481, "Organ", "Calf Organ", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };

ALL_WRAPPERS(organ)

#endif
////////////////////////////////////////////////////////////////////////////

static synth::ladspa_info monosynth_info = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };

ALL_WRAPPERS(monosynth)

////////////////////////////////////////////////////////////////////////////

#if USE_LV2
extern "C" {

const LV2_Descriptor *lv2_descriptor(uint32_t index)
{
    switch (index) {
        case 0: return &::lv2_filter.descriptor;
        case 1: return &::lv2_flanger.descriptor;
        case 2: return &::lv2_reverb.descriptor;
        case 3: return &::lv2_vintage_delay.descriptor;
        case 4: return &::lv2_monosynth.descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 5: return &::lv2_organ.descriptor;
        case 6: return &::lv2_rotary_speaker.descriptor;
#endif
        default: return NULL;
    }
}

};

#endif
#if USE_LADSPA
extern "C" {

const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
{
    switch (Index) {
        case 0: return &::ladspa_filter.descriptor;
        case 1: return &::ladspa_flanger.descriptor;
        case 2: return &::ladspa_reverb.descriptor;
        case 3: return &::ladspa_vintage_delay.descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 4: return &::ladspa_rotary_speaker.descriptor;
#endif
        default: return NULL;
    }
}

};

#if USE_DSSI
extern "C" {

const DSSI_Descriptor *dssi_descriptor(unsigned long Index)
{
    switch (Index) {
        case 0: return &::ladspa_filter.dssi_descriptor;
        case 1: return &::ladspa_flanger.dssi_descriptor;
        case 2: return &::ladspa_reverb.dssi_descriptor;
        case 3: return &::ladspa_monosynth.dssi_descriptor;
        case 4: return &::ladspa_vintage_delay.dssi_descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 5: return &::ladspa_organ.dssi_descriptor;
        case 6: return &::ladspa_rotary_speaker.dssi_descriptor;
#endif
        default: return NULL;
    }
}

};
#endif

std::string synth::get_builtin_modules_rdf()
{
    std::string rdf;

    rdf += ::ladspa_flanger.generate_rdf();
    rdf += ::ladspa_reverb.generate_rdf();
    rdf += ::ladspa_filter.generate_rdf();
    rdf += ::ladspa_vintage_delay.generate_rdf();
    rdf += ::ladspa_monosynth.generate_rdf();

    return rdf;
}
#endif

template<class Module>
giface_plugin_info create_plugin_info(ladspa_info &info)
{
    giface_plugin_info pi;
    pi.info = &info;
    pi.inputs = Module::in_count;
    pi.outputs = Module::out_count;
    pi.params = Module::param_count;
    pi.rt_capable = Module::rt_capable;
    pi.midi_in_capable = Module::support_midi;
    pi.param_props = Module::param_props;
    return pi;
}

void synth::get_all_plugins(std::vector<giface_plugin_info> &plugins)
{
    plugins.push_back(create_plugin_info<filter_audio_module>(filter_info));
    plugins.push_back(create_plugin_info<flanger_audio_module>(flanger_info));
    plugins.push_back(create_plugin_info<reverb_audio_module>(reverb_info));
    plugins.push_back(create_plugin_info<monosynth_audio_module>(monosynth_info));
    plugins.push_back(create_plugin_info<vintage_delay_audio_module>(vintage_delay_info));
#ifdef ENABLE_EXPERIMENTAL
    plugins.push_back(create_plugin_info<organ_audio_module>(organ_info));
    plugins.push_back(create_plugin_info<rotary_speaker_audio_module>(rotary_speaker_info));
#endif
}
<commit_msg>+ Filter: made inertia parameter float&log instead of int&log to avoid rounding off problems<commit_after>/* Calf DSP Library
 * Example audio modules - parameters and LADSPA wrapper instantiation
 *
 * Copyright (C) 2001-2008 Krzysztof Foltman
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include <config.h>
#include <assert.h>
#include <memory.h>
#if USE_JACK
#include <jack/jack.h>
#endif
#include <calf/giface.h>
#include <calf/lv2wrap.h>
#include <calf/modules.h>
#include <calf/modules_dev.h>

using namespace synth;

#if USE_LADSPA
#define LADSPA_WRAPPER(mod) static synth::ladspa_wrapper<mod##_audio_module> ladspa_##mod(mod##_info);
#else
#define LADSPA_WRAPPER(mod)
#endif

#if USE_LV2
#define LV2_WRAPPER(mod) static synth::lv2_wrapper<mod##_audio_module> lv2_##mod(mod##_info);
#else
#define LV2_WRAPPER(mod)
#endif

#define ALL_WRAPPERS(mod) LADSPA_WRAPPER(mod) LV2_WRAPPER(mod)

const char *copyright = "(C) 2001-2007 Krzysztof Foltman, license: LGPL";

////////////////////////////////////////////////////////////////////////////

const char *flanger_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

parameter_properties flanger_audio_module::param_props[] = {
    { 0.1,      0.1, 10,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "min_delay", "Minimum delay" },
    { 0.5,      0.1, 10,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "mod_depth", "Modulation depth" },
    { 0.25,    0.01, 20,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "mod_rate", "Modulation rate" },
    { 0.90,   -0.99, 0.99,  0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "feedback", "Feedback" },
    { 1,          0, 2,     0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
};

static synth::ladspa_info flanger_info = { 0x847d, "Flanger", "Calf Flanger", "Krzysztof Foltman", copyright, "FlangerPlugin" };

ALL_WRAPPERS(flanger)

////////////////////////////////////////////////////////////////////////////

const char *reverb_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *reverb_room_sizes[] = { "Small", "Medium", "Large", "Tunnel-like" };

parameter_properties reverb_audio_module::param_props[] = {
    { 1.5,      0.5, 15.0,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "decay_time", "Decay time" },
    { 5000,    2000,20000,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hf_damp", "High Frq Damp" },
    { 2,          0,    3,    0, PF_ENUM | PF_CTL_COMBO , reverb_room_sizes, "room_size", "Room size", },
    { 0.5,        0,    1,    0, PF_FLOAT | PF_CTL_KNOB | PF_SCALE_PERC, NULL, "diffusion", "Diffusion" },
    { 0.25,       0,    2,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
};

static synth::ladspa_info reverb_info = { 0x847e, "Reverb", "Calf Reverb", "Krzysztof Foltman", copyright, "ReverbPlugin" };

ALL_WRAPPERS(reverb)

////////////////////////////////////////////////////////////////////////////

const char *filter_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *filter_choices[] = {
    "12dB/oct Lowpass",
    "24dB/oct Lowpass",
    "36dB/oct Lowpass",
    "12dB/oct Highpass",
    "24dB/oct Highpass",
    "36dB/oct Highpass",
};

parameter_properties filter_audio_module::param_props[] = {
    { 2000,      10,20000,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" },
    { 0.707,  0.707,   20,    0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "res", "Resonance" },
    { 0,          0,    5,    1, PF_ENUM | PF_CTL_COMBO, filter_choices, "mode", "Mode" },
    { 20,         5,  100,    20, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "inertia", "Inertia"},
};

static synth::ladspa_info filter_info = { 0x847f, "Filter", "Calf Filter", "Krzysztof Foltman", copyright, "FilterPlugin" };

ALL_WRAPPERS(filter)

////////////////////////////////////////////////////////////////////////////

const char *vintage_delay_audio_module::port_names[] = {"In L", "In R", "Out L", "Out R"};

const char *vintage_delay_mixmodes[] = {
    "Stereo",
    "Ping-Pong",
};

const char *vintage_delay_fbmodes[] = {
    "Plain",
    "Tape",
    "Old Tape",
};

parameter_properties vintage_delay_audio_module::param_props[] = {
    { 120,      30,    300,   0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_BPM, NULL, "bpm", "Tempo" },
    {  4,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "subdiv", "Subdivide"},
    {  3,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_l", "Time L"},
    {  5,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_r", "Time R"},
    { 0.5,       0,    1,     0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "feedback", "Feedback" },
    { 0.25,      0,    2,   100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
    { 1,         0,    1,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" },
    { 1,         0,    2,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_fbmodes, "medium", "Medium" },
};

static synth::ladspa_info vintage_delay_info = { 0x8482, "VintageDelay", "Calf Vintage Delay", "Krzysztof Foltman", copyright, "DelayPlugin" };

ALL_WRAPPERS(vintage_delay)

////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_EXPERIMENTAL
static synth::ladspa_info rotary_speaker_info = { 0x8483, "RotarySpeaker", "Calf Rotary Speaker", "Krzysztof Foltman", copyright, "SimulationPlugin" };

ALL_WRAPPERS(rotary_speaker)

static synth::ladspa_info organ_info = { 0x8481, "Organ", "Calf Organ", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };

ALL_WRAPPERS(organ)

#endif
////////////////////////////////////////////////////////////////////////////

static synth::ladspa_info monosynth_info = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };

ALL_WRAPPERS(monosynth)

////////////////////////////////////////////////////////////////////////////

#if USE_LV2
extern "C" {

const LV2_Descriptor *lv2_descriptor(uint32_t index)
{
    switch (index) {
        case 0: return &::lv2_filter.descriptor;
        case 1: return &::lv2_flanger.descriptor;
        case 2: return &::lv2_reverb.descriptor;
        case 3: return &::lv2_vintage_delay.descriptor;
        case 4: return &::lv2_monosynth.descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 5: return &::lv2_organ.descriptor;
        case 6: return &::lv2_rotary_speaker.descriptor;
#endif
        default: return NULL;
    }
}

};

#endif
#if USE_LADSPA
extern "C" {

const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
{
    switch (Index) {
        case 0: return &::ladspa_filter.descriptor;
        case 1: return &::ladspa_flanger.descriptor;
        case 2: return &::ladspa_reverb.descriptor;
        case 3: return &::ladspa_vintage_delay.descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 4: return &::ladspa_rotary_speaker.descriptor;
#endif
        default: return NULL;
    }
}

};

#if USE_DSSI
extern "C" {

const DSSI_Descriptor *dssi_descriptor(unsigned long Index)
{
    switch (Index) {
        case 0: return &::ladspa_filter.dssi_descriptor;
        case 1: return &::ladspa_flanger.dssi_descriptor;
        case 2: return &::ladspa_reverb.dssi_descriptor;
        case 3: return &::ladspa_monosynth.dssi_descriptor;
        case 4: return &::ladspa_vintage_delay.dssi_descriptor;
#ifdef ENABLE_EXPERIMENTAL
        case 5: return &::ladspa_organ.dssi_descriptor;
        case 6: return &::ladspa_rotary_speaker.dssi_descriptor;
#endif
        default: return NULL;
    }
}

};
#endif

std::string synth::get_builtin_modules_rdf()
{
    std::string rdf;

    rdf += ::ladspa_flanger.generate_rdf();
    rdf += ::ladspa_reverb.generate_rdf();
    rdf += ::ladspa_filter.generate_rdf();
    rdf += ::ladspa_vintage_delay.generate_rdf();
    rdf += ::ladspa_monosynth.generate_rdf();

    return rdf;
}
#endif

template<class Module>
giface_plugin_info create_plugin_info(ladspa_info &info)
{
    giface_plugin_info pi;
    pi.info = &info;
    pi.inputs = Module::in_count;
    pi.outputs = Module::out_count;
    pi.params = Module::param_count;
    pi.rt_capable = Module::rt_capable;
    pi.midi_in_capable = Module::support_midi;
    pi.param_props = Module::param_props;
    return pi;
}

void synth::get_all_plugins(std::vector<giface_plugin_info> &plugins)
{
    plugins.push_back(create_plugin_info<filter_audio_module>(filter_info));
    plugins.push_back(create_plugin_info<flanger_audio_module>(flanger_info));
    plugins.push_back(create_plugin_info<reverb_audio_module>(reverb_info));
    plugins.push_back(create_plugin_info<monosynth_audio_module>(monosynth_info));
    plugins.push_back(create_plugin_info<vintage_delay_audio_module>(vintage_delay_info));
#ifdef ENABLE_EXPERIMENTAL
    plugins.push_back(create_plugin_info<organ_audio_module>(organ_info));
    plugins.push_back(create_plugin_info<rotary_speaker_audio_module>(rotary_speaker_info));
#endif
}
<|endoftext|>


<commit_before><commit_msg>Fix a crash when a moust observer got a mouse event on a wnidow that has already been destroyed.<commit_after><|endoftext|>


<commit_before>/*
 * sampling.cpp
 *
 *  Created on: 2016年12月21日
 *      Author: zhuqian
 */
#include "sampling.h"
#include "rng.h"
void StratifiedSample1D(Float *samples, int nsamples, RNG &rng, bool jitter) {
	Float invNumSamples = 1.0f / nsamples;
	for (int i = 0; i < nsamples; ++i) {
		Float delta = jitter ? rng.UniformFloat() : 0.5f;
		Float sampleVaule = (i + delta) * invNumSamples;
		samples[i] = std::min(sampleVaule, OneMinusEpsilon);
	}
}

void StratifiedSample2D(Point2f *samples, int nx, int ny, RNG &rng,
		bool jitter) {
	Float invNX = 1.0f / nx;
	Float invNY = 1.0f / ny;
	for (int j = 0; j < ny; ++j) {
		for (int i = 0; i < nx; ++i) {
			Float dx = jitter ? rng.UniformFloat() : 0.5f;
			Float dy = jitter ? rng.UniformFloat() : 0.5f;
			samples->x = std::min((i + dx) * invNX, OneMinusEpsilon);
			samples->y = std::min((j + dy) * invNY, OneMinusEpsilon);
			++samples; //步进到下一个Point2f
		}
	}
}

Point2f RejectionSampleDisk(RNG& rng) {
	Float x, y;
	do {
		x = rng.UniformFloat();
		y = rng.UniformFloat();
	} while (x * x + y * y > 1);
	return Point2f(x, y);
}

Vector3f UniformSampleHemisphere(const Point2f &u) {
	Float z = u.x; //半球范围内 z的定义域是[0-1]
	Float r = std::sqrt(std::max(1.0f - z * z, 0.0f));
	Float phi = 2 * Pi * u.y; //计算得到phi
	//然后在xy平面上求x和y
	Float x = std::cos(phi) * r;
	Float y = std::sin(phi) * r;
	return Vector3f(x, y, z);
}

Float UniformHemispherePdf() {
	return Inv2Pi;
}

Vector3f UniformSampleSphere(const Point2f &u) {
	Float z = -(u.x * 2 - 1);
	Float r = std::sqrt(std::max(1.0f - z * z, 0.0f));
	Float phi = 2 * Pi * u.y;	//计算得到phi
	//然后在xy平面上求x和y
	Float x = std::cos(phi) * r;
	Float y = std::sin(phi) * r;
	return Vector3f(x, y, z);
}

Float UniformSpherePdf() {
	return Inv4Pi;
}

Point2f UniformSampleDisk(const Point2f &u) {
	Assert(u.x >= 0);
	Float r = std::sqrt(u.x);
	Float theta = 2 * Pi * u.y;
	Float x = std::cos(theta) * r;
	Float y = std::sin(theta) * r;
	return Point2f(x, y);
}

Point2f ConcentricSampleDisk(const Point2f &u) {
	Point2f uOffset =  u*2.0f - Vector2f(1, 1);
	//返回退化的情况
	if (uOffset.x == 0 && uOffset.y == 0) {
		return Point2f(0, 0);
	}

	Float theta, r;
	if (std::abs(uOffset.x) > std::abs(uOffset.y)) {
		r = uOffset.x;
		theta = PiOver4 * (uOffset.y / uOffset.x);
	} else {
		r = uOffset.y;
		theta = PiOver2 - PiOver4 * (uOffset.x / uOffset.y);
	}
	return Point2f(r * std::cos(theta), r * std::sin(theta));
}

void LatinHypercube(Float *samples, int nSamples, int nDim, RNG &rng){
	Float invNumSamples=1.0f/nSamples;
	//先生成对角线样本
	for(int i=0;i<nSamples;++i){
		for(int j=0;j<nDim;++j){
			Float sample=(i+rng.UniformFloat())*invNumSamples;
			samples[nDim*i+j]=std::min(sample,OneMinusEpsilon);
		}
	}
	//对每个维度的样本进行乱序排列
	//这里把x轴想象成nDim ,y轴想象成nSamples的二维数组
	for(int i=0;i<nDim;++i){
		for(int j=0;j<nSamples;++j){
			int other=rng.UniformUInt32(nSamples-j)+j;
			std::swap(samples[nDim*j+i],samples[nDim*other+i]);
		}
	}
}

//Malley’s method
Vector3f CosineSampleHemisphere(const Point2f &u){
	//获得x-y平面上的一个点
	Point2f pp=ConcentricSampleDisk(u);
	//计算到半球上，满足cosine分布
	Float z=std::sqrt(std::max(0.0f,1.0f-pp.x*pp.x-pp.y*pp.y));
	return Vector3f(pp.x,pp.y,z);
}

//cosTheta是和z轴的夹角的cos值
Float CosineHemispherePdf(Float cosTheta) {
	//这返回的是p(w),不是p(theta,phi)
	//这里一定要注意p(w)不等于p(theta,phi)
	return cosTheta * InvPi;
}

Float UniformConePdf(Float cosThetaMax) {
	return 1.0 / (2 * Pi*(1.0 - cosThetaMax));
}<commit_msg>浮点数稳定性和类型<commit_after>/*
 * sampling.cpp
 *
 *  Created on: 2016年12月21日
 *      Author: zhuqian
 */
#include "sampling.h"
#include "rng.h"
void StratifiedSample1D(Float *samples, int nsamples, RNG &rng, bool jitter) {
	Float invNumSamples = 1.0f / nsamples;
	for (int i = 0; i < nsamples; ++i) {
		Float delta = jitter ? rng.UniformFloat() : 0.5f;
		Float sampleVaule = (i + delta) * invNumSamples;
		samples[i] = std::min(sampleVaule, OneMinusEpsilon);
	}
}

void StratifiedSample2D(Point2f *samples, int nx, int ny, RNG &rng,
		bool jitter) {
	Float invNX = 1.0f / nx;
	Float invNY = 1.0f / ny;
	for (int j = 0; j < ny; ++j) {
		for (int i = 0; i < nx; ++i) {
			Float dx = jitter ? rng.UniformFloat() : 0.5f;
			Float dy = jitter ? rng.UniformFloat() : 0.5f;
			samples->x = std::min((i + dx) * invNX, OneMinusEpsilon);
			samples->y = std::min((j + dy) * invNY, OneMinusEpsilon);
			++samples; //步进到下一个Point2f
		}
	}
}

Point2f RejectionSampleDisk(RNG& rng) {
	Float x, y;
	do {
		x = rng.UniformFloat();
		y = rng.UniformFloat();
	} while (x * x + y * y > 1);
	return Point2f(x, y);
}

Vector3f UniformSampleHemisphere(const Point2f &u) {
	Float z = u.x; //半球范围内 z的定义域是[0-1]
	Float r = std::sqrt(std::max((Float)1.0f - z * z, (Float)0.0f));
	Float phi = 2 * Pi * u.y; //计算得到phi
	//然后在xy平面上求x和y
	Float x = std::cos(phi) * r;
	Float y = std::sin(phi) * r;
	return Vector3f(x, y, z);
}

Float UniformHemispherePdf() {
	return Inv2Pi;
}

Vector3f UniformSampleSphere(const Point2f &u) {
	Float z = -(u.x * 2 - 1);
	Float r = std::sqrt(std::max((Float)1.0f - z * z, (Float)0.0f));
	Float phi = 2 * Pi * u.y;	//计算得到phi
	//然后在xy平面上求x和y
	Float x = std::cos(phi) * r;
	Float y = std::sin(phi) * r;
	return Vector3f(x, y, z);
}

Float UniformSpherePdf() {
	return Inv4Pi;
}

Point2f UniformSampleDisk(const Point2f &u) {
	Assert(u.x >= 0);
	Float r = std::sqrt(u.x);
	Float theta = 2 * Pi * u.y;
	Float x = std::cos(theta) * r;
	Float y = std::sin(theta) * r;
	return Point2f(x, y);
}

Point2f ConcentricSampleDisk(const Point2f &u) {
	Point2f uOffset =  u*2.0f - Vector2f(1, 1);
	//返回退化的情况
	if (uOffset.x == 0 && uOffset.y == 0) {
		return Point2f(0, 0);
	}

	Float theta, r;
	if (std::abs(uOffset.x) > std::abs(uOffset.y)) {
		r = uOffset.x;
		theta = PiOver4 * (uOffset.y / uOffset.x);
	} else {
		r = uOffset.y;
		theta = PiOver2 - PiOver4 * (uOffset.x / uOffset.y);
	}
	return Point2f(r * std::cos(theta), r * std::sin(theta));
}

void LatinHypercube(Float *samples, int nSamples, int nDim, RNG &rng){
	Float invNumSamples=1.0f/nSamples;
	//先生成对角线样本
	for(int i=0;i<nSamples;++i){
		for(int j=0;j<nDim;++j){
			Float sample=(i+rng.UniformFloat())*invNumSamples;
			samples[nDim*i+j]=std::min(sample,OneMinusEpsilon);
		}
	}
	//对每个维度的样本进行乱序排列
	//这里把x轴想象成nDim ,y轴想象成nSamples的二维数组
	for(int i=0;i<nDim;++i){
		for(int j=0;j<nSamples;++j){
			int other=rng.UniformUInt32(nSamples-j)+j;
			std::swap(samples[nDim*j+i],samples[nDim*other+i]);
		}
	}
}

//Malley’s method
Vector3f CosineSampleHemisphere(const Point2f &u){
	//获得x-y平面上的一个点
	Point2f pp=ConcentricSampleDisk(u);
	//计算到半球上，满足cosine分布
	Float z=std::sqrt(std::max((Float)0.0f,(Float)1.0f-pp.x*pp.x-pp.y*pp.y));
	return Vector3f(pp.x,pp.y,z);
}

//cosTheta是和z轴的夹角的cos值
Float CosineHemispherePdf(Float cosTheta) {
	//这返回的是p(w),不是p(theta,phi)
	//这里一定要注意p(w)不等于p(theta,phi)
	return cosTheta * InvPi;
}

Float UniformConePdf(Float cosThetaMax) {
	return 1.0 / (2 * Pi*(1.0 - cosThetaMax));
}<|endoftext|>


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

#include "chrome/browser/renderer_host/blob_dispatcher_host.h"

#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chrome_blob_storage_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/render_messages.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
#include "webkit/blob/blob_data.h"
#include "webkit/blob/blob_storage_controller.h"

BlobDispatcherHost::BlobDispatcherHost(
    int process_id,
    ChromeBlobStorageContext* blob_storage_context)
    : process_id_(process_id),
      blob_storage_context_(blob_storage_context) {
}

BlobDispatcherHost::~BlobDispatcherHost() {
}

void BlobDispatcherHost::Shutdown() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  // Unregister all the blob URLs that are previously registered in this
  // process.
  for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin();
       iter != blob_urls_.end(); ++iter) {
    blob_storage_context_->controller()->UnregisterBlobUrl(GURL(*iter));
  }
}

bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message,
                                           bool* msg_is_ok) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  *msg_is_ok = true;
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(BlobDispatcherHost, message, *msg_is_ok)
    IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrl, OnRegisterBlobUrl)
    IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrlFrom, OnRegisterBlobUrlFrom)
    IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterBlobUrl, OnUnregisterBlobUrl)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

// Check if the child process has been granted permission to register the files.
bool BlobDispatcherHost::CheckPermission(
    webkit_blob::BlobData* blob_data) const {
  ChildProcessSecurityPolicy* policy =
      ChildProcessSecurityPolicy::GetInstance();
  for (std::vector<webkit_blob::BlobData::Item>::const_iterator iter =
           blob_data->items().begin();
       iter != blob_data->items().end(); ++iter) {
    if (iter->type() == webkit_blob::BlobData::TYPE_FILE) {
      if (!policy->CanReadFile(process_id_, iter->file_path()))
        return false;
    }
  }
  return true;
}

void BlobDispatcherHost::OnRegisterBlobUrl(
    const GURL& url, const scoped_refptr<webkit_blob::BlobData>& blob_data) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  if (!CheckPermission(blob_data.get()))
    return;
  blob_storage_context_->controller()->RegisterBlobUrl(url, blob_data);
  blob_urls_.insert(url.spec());
}

void BlobDispatcherHost::OnRegisterBlobUrlFrom(
    const GURL& url, const GURL& src_url) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  blob_storage_context_->controller()->RegisterBlobUrlFrom(url, src_url);
  blob_urls_.insert(src_url.spec());
}

void BlobDispatcherHost::OnUnregisterBlobUrl(const GURL& url) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  blob_storage_context_->controller()->UnregisterBlobUrl(url);
  blob_urls_.erase(url.spec());
}
<commit_msg>Fix a leak. We weren't keeping track of 'public' blob urls properly.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/blob_dispatcher_host.h"

#include "chrome/browser/child_process_security_policy.h"
#include "chrome/browser/chrome_blob_storage_context.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/render_messages.h"
#include "googleurl/src/gurl.h"
#include "ipc/ipc_message.h"
#include "webkit/blob/blob_data.h"
#include "webkit/blob/blob_storage_controller.h"

BlobDispatcherHost::BlobDispatcherHost(
    int process_id,
    ChromeBlobStorageContext* blob_storage_context)
    : process_id_(process_id),
      blob_storage_context_(blob_storage_context) {
}

BlobDispatcherHost::~BlobDispatcherHost() {
}

void BlobDispatcherHost::Shutdown() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  // Unregister all the blob URLs that are previously registered in this
  // process.
  for (base::hash_set<std::string>::const_iterator iter = blob_urls_.begin();
       iter != blob_urls_.end(); ++iter) {
    blob_storage_context_->controller()->UnregisterBlobUrl(GURL(*iter));
  }
}

bool BlobDispatcherHost::OnMessageReceived(const IPC::Message& message,
                                           bool* msg_is_ok) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  *msg_is_ok = true;
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP_EX(BlobDispatcherHost, message, *msg_is_ok)
    IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrl, OnRegisterBlobUrl)
    IPC_MESSAGE_HANDLER(ViewHostMsg_RegisterBlobUrlFrom, OnRegisterBlobUrlFrom)
    IPC_MESSAGE_HANDLER(ViewHostMsg_UnregisterBlobUrl, OnUnregisterBlobUrl)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

// Check if the child process has been granted permission to register the files.
bool BlobDispatcherHost::CheckPermission(
    webkit_blob::BlobData* blob_data) const {
  ChildProcessSecurityPolicy* policy =
      ChildProcessSecurityPolicy::GetInstance();
  for (std::vector<webkit_blob::BlobData::Item>::const_iterator iter =
           blob_data->items().begin();
       iter != blob_data->items().end(); ++iter) {
    if (iter->type() == webkit_blob::BlobData::TYPE_FILE) {
      if (!policy->CanReadFile(process_id_, iter->file_path()))
        return false;
    }
  }
  return true;
}

void BlobDispatcherHost::OnRegisterBlobUrl(
    const GURL& url, const scoped_refptr<webkit_blob::BlobData>& blob_data) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  if (!CheckPermission(blob_data.get()))
    return;
  blob_storage_context_->controller()->RegisterBlobUrl(url, blob_data);
  blob_urls_.insert(url.spec());
}

void BlobDispatcherHost::OnRegisterBlobUrlFrom(
    const GURL& url, const GURL& src_url) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  blob_storage_context_->controller()->RegisterBlobUrlFrom(url, src_url);
  blob_urls_.insert(url.spec());
}

void BlobDispatcherHost::OnUnregisterBlobUrl(const GURL& url) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  blob_storage_context_->controller()->UnregisterBlobUrl(url);
  blob_urls_.erase(url.spec());
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, 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 <thread>

#include <folly/synchronization/ParkingLot.h>

#include <folly/Benchmark.h>
#include <folly/detail/Futex.h>
#include <folly/synchronization/Baton.h>

DEFINE_uint64(threads, 32, "Number of threads for benchmark");

using namespace folly;

namespace {
struct SimpleBarrier {
  explicit SimpleBarrier(size_t count) : lock_(), cv_(), count_(count) {}

  void wait() {
    std::unique_lock<std::mutex> lockHeld(lock_);
    auto gen = gen_;
    if (++num_ == count_) {
      num_ = 0;
      gen_++;
      cv_.notify_all();
    } else {
      cv_.wait(lockHeld, [&]() { return gen == gen_; });
    }
  }

 private:
  std::mutex lock_;
  std::condition_variable cv_;
  size_t num_{0};
  size_t count_;
  size_t gen_{0};
};
} // namespace

ParkingLot<> lot;

BENCHMARK(FutexNoWaitersWake, iters) {
  BenchmarkSuspender susp;
  folly::detail::Futex<> fu;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      for (int i = 0; i < iters; i++) {
        fu.futexWake(1);
      }
    });
  }
  susp.dismiss();
  b.wait();

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotNoWaitersWake, iters) {
  BenchmarkSuspender susp;
  folly::detail::Futex<> fu;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      for (int i = 0; i < iters; i++) {
        lot.unpark(&lot, [](Unit) { return UnparkControl::RetainContinue; });
      }
    });
  }
  susp.dismiss();
  b.wait();

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK(FutexWakeOne, iters) {
  BenchmarkSuspender susp;
  folly::detail::Futex<> fu;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        fu.futexWait(0);
        if (fu.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (int i = 0; i < iters; i++) {
    fu.futexWake(1);
  }
  fu.store(1);
  fu.futexWake(threads.size());

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotWakeOne, iters) {
  BenchmarkSuspender susp;
  std::atomic<bool> done{false};
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        Unit f;
        lot.park(
            &done,
            f,
            [&] { return done.load(std::memory_order_relaxed) == 0; },
            [] {});
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (int i = 0; i < iters; i++) {
    lot.unpark(&done, [](Unit) { return UnparkControl::RemoveBreak; });
  }
  done = true;
  lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK(FutexWakeAll, iters) {
  BenchmarkSuspender susp;
  SimpleBarrier b(FLAGS_threads + 1);
  folly::detail::Futex<> fu;
  std::atomic<bool> done{false};

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        fu.futexWait(0);
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (int i = 0; i < iters; i++) {
    fu.futexWake(threads.size());
  }
  fu.store(1);
  done = true;
  fu.futexWake(threads.size());

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotWakeAll, iters) {
  BenchmarkSuspender susp;
  SimpleBarrier b(FLAGS_threads + 1);
  std::atomic<bool> done{false};

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        Unit f;
        lot.park(
            &done,
            f,
            [&] { return done.load(std::memory_order_relaxed) == 0; },
            [] {});
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (int i = 0; i < iters; i++) {
    lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
  }
  done = true;
  lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });

  for (auto& t : threads) {
    t.join();
  }
}

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);

  folly::runBenchmarks();
}
/*

./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
--bm_min_iters=10000 --threads=4
============================================================================
folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
============================================================================
FutexNoWaitersWake                                         163.43ns    6.12M
ParkingLotNoWaitersWake                           29.64%   551.43ns    1.81M
FutexWakeOne                                               156.78ns    6.38M
ParkingLotWakeOne                                 37.49%   418.21ns    2.39M
FutexWakeAll                                                 1.82us  549.52K
ParkingLotWakeAll                                449.63%   404.73ns    2.47M
============================================================================

./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
--bm_min_iters=10000 --threads=32
============================================================================
folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
============================================================================
FutexNoWaitersWake                                         379.59ns    2.63M
ParkingLotNoWaitersWake                            7.94%     4.78us  209.08K
FutexWakeOne                                               163.59ns    6.11M
ParkingLotWakeOne                                  6.41%     2.55us  392.07K
FutexWakeAll                                                12.46us   80.27K
ParkingLotWakeAll                                784.76%     1.59us  629.92K
============================================================================ */
<commit_msg>Fix Build: folly/synchronization/test/ParkingLotBenchmark.cpp (sign-compare, unused-variable)<commit_after>/*
 * Copyright 2017-present Facebook, 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 <thread>

#include <folly/synchronization/ParkingLot.h>

#include <folly/Benchmark.h>
#include <folly/detail/Futex.h>
#include <folly/synchronization/Baton.h>

DEFINE_uint64(threads, 32, "Number of threads for benchmark");

using namespace folly;

namespace {
struct SimpleBarrier {
  explicit SimpleBarrier(size_t count) : lock_(), cv_(), count_(count) {}

  void wait() {
    std::unique_lock<std::mutex> lockHeld(lock_);
    auto gen = gen_;
    if (++num_ == count_) {
      num_ = 0;
      gen_++;
      cv_.notify_all();
    } else {
      cv_.wait(lockHeld, [&]() { return gen == gen_; });
    }
  }

 private:
  std::mutex lock_;
  std::condition_variable cv_;
  size_t num_{0};
  size_t count_;
  size_t gen_{0};
};
} // namespace

ParkingLot<> lot;

BENCHMARK(FutexNoWaitersWake, iters) {
  BenchmarkSuspender susp;
  folly::detail::Futex<> fu;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      for (auto i = 0u; i < iters; i++) {
        fu.futexWake(1);
      }
    });
  }
  susp.dismiss();
  b.wait();

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotNoWaitersWake, iters) {
  BenchmarkSuspender susp;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      for (auto i = 0u; i < iters; i++) {
        lot.unpark(&lot, [](Unit) { return UnparkControl::RetainContinue; });
      }
    });
  }
  susp.dismiss();
  b.wait();

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK(FutexWakeOne, iters) {
  BenchmarkSuspender susp;
  folly::detail::Futex<> fu;
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        fu.futexWait(0);
        if (fu.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (auto i = 0u; i < iters; i++) {
    fu.futexWake(1);
  }
  fu.store(1);
  fu.futexWake(threads.size());

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotWakeOne, iters) {
  BenchmarkSuspender susp;
  std::atomic<bool> done{false};
  SimpleBarrier b(FLAGS_threads + 1);

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        Unit f;
        lot.park(
            &done,
            f,
            [&] { return done.load(std::memory_order_relaxed) == 0; },
            [] {});
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (auto i = 0u; i < iters; i++) {
    lot.unpark(&done, [](Unit) { return UnparkControl::RemoveBreak; });
  }
  done = true;
  lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK(FutexWakeAll, iters) {
  BenchmarkSuspender susp;
  SimpleBarrier b(FLAGS_threads + 1);
  folly::detail::Futex<> fu;
  std::atomic<bool> done{false};

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        fu.futexWait(0);
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (auto i = 0u; i < iters; i++) {
    fu.futexWake(threads.size());
  }
  fu.store(1);
  done = true;
  fu.futexWake(threads.size());

  for (auto& t : threads) {
    t.join();
  }
}

BENCHMARK_RELATIVE(ParkingLotWakeAll, iters) {
  BenchmarkSuspender susp;
  SimpleBarrier b(FLAGS_threads + 1);
  std::atomic<bool> done{false};

  std::vector<std::thread> threads{FLAGS_threads};
  for (auto& t : threads) {
    t = std::thread([&]() {
      b.wait();
      while (true) {
        Unit f;
        lot.park(
            &done,
            f,
            [&] { return done.load(std::memory_order_relaxed) == 0; },
            [] {});
        if (done.load(std::memory_order_relaxed)) {
          return;
        }
      }
    });
  }
  susp.dismiss();
  b.wait();
  for (auto i = 0u; i < iters; i++) {
    lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });
  }
  done = true;
  lot.unpark(&done, [](Unit) { return UnparkControl::RemoveContinue; });

  for (auto& t : threads) {
    t.join();
  }
}

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);

  folly::runBenchmarks();
}
/*

./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
--bm_min_iters=10000 --threads=4
============================================================================
folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
============================================================================
FutexNoWaitersWake                                         163.43ns    6.12M
ParkingLotNoWaitersWake                           29.64%   551.43ns    1.81M
FutexWakeOne                                               156.78ns    6.38M
ParkingLotWakeOne                                 37.49%   418.21ns    2.39M
FutexWakeAll                                                 1.82us  549.52K
ParkingLotWakeAll                                449.63%   404.73ns    2.47M
============================================================================

./buck-out/gen/folly/synchronization/test/parking_lot_test --benchmark
--bm_min_iters=10000 --threads=32
============================================================================
folly/synchronization/test/ParkingLotBenchmark.cpprelative  time/iter  iters/s
============================================================================
FutexNoWaitersWake                                         379.59ns    2.63M
ParkingLotNoWaitersWake                            7.94%     4.78us  209.08K
FutexWakeOne                                               163.59ns    6.11M
ParkingLotWakeOne                                  6.41%     2.55us  392.07K
FutexWakeAll                                                12.46us   80.27K
ParkingLotWakeAll                                784.76%     1.59us  629.92K
============================================================================ */
<|endoftext|>