<commit_before>/**
Copyright (c) 2016, Ubiquity Robotics
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 the name of ubiquity_motor 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

#include <ubiquity_motor/motor_serial.h>
#include <ros/ros.h>
#include <serial/serial.h>

MotorSerial::MotorSerial(const std::string &port, uint32_t baud_rate, double loopRate) {
	have_input = false;

	// Make sure baud rate is valid
	switch (baud_rate) {
		case 110 :
		case 300 :
		case 600 :
		case 1200 :
		case 2400 :
		case 4800 :
		case 9600 :
		case 14400 :
		case 19200 :
		case 28800 :
		case 38400 :
		case 56000 :
		case 57600 :
		case 115200 :
		case 128000 :
		case 153600 :
		case 230400 :
		case 256000 :
		case 460800 :
		case 921600 :
		this->_baud_rate = baud_rate;
		break;
		default :
		this->_baud_rate = 9600;
		break;
	}

	// TODO verify that port is valid
	this->_port = port;

	motors = new serial::Serial(_port, _baud_rate, serial::Timeout::simpleTimeout(10000));

	serial_loop_rate = new ros::Rate(loopRate);

	serial_thread = new boost::thread(&MotorSerial::SerialThread, this);
}

MotorSerial::~MotorSerial() {
	serial_thread->interrupt();
	serial_thread->join();
	motors->close();
	delete motors;
	delete serial_thread;
	delete serial_loop_rate;
}

int MotorSerial::transmitCommand(MotorMessage command) {
	// Make sure to lock mutex before accessing the input fifo
	input_mtx_.lock();
	this->input.push(command); // add latest command to end of fifo
	this->have_input = true; //Used to avoid input locking
	input_mtx_.unlock();
	return 0;
}

int MotorSerial::transmitCommands(const std::vector<MotorMessage> &commands) {
	// Make sure to lock mutex before accessing the input fifo
	input_mtx_.lock();
	for (std::vector<MotorMessage>::const_iterator it = commands.begin(); it != commands.end(); ++it) {
		this->input.push(*it);
		this->have_input = true; //Used to avoid input locking
	}
	input_mtx_.unlock();
	return 0;
}

MotorMessage MotorSerial::receiveCommand() {
	MotorMessage mc;

	output_mtx_.lock();
	if (!this->output.empty()) {
		mc = this->output.front();
		this->output.pop();
	}
	output_mtx_.unlock();
	return mc;
}

int MotorSerial::commandAvailable() {
	// If have_output is false return false
	// if it is true, then verify there is output and return true
	// if verification fails make sure have_output is false
	if(!this->have_output) {
		return false;
	}

	output_mtx_.lock();
	int out = !(this->output.empty());
	if(!out) {
		this->have_output = false;
	}
	output_mtx_.unlock();

	return out;
}

int MotorSerial::inputAvailable() {
	// If have_input is false return false
	// if it is true, then verify there is input and return true
	// if verification fails make sure have_input is false

	if (!this->have_input) {
		return false;
	}

	input_mtx_.lock();
	int out = !(this->input.empty());
	if (!out) {
		this->have_input = false;
	}
	input_mtx_.unlock();

	return out;
}

MotorMessage MotorSerial::getInputCommand() {
	MotorMessage mc;
	input_mtx_.lock();
	if (!this->input.empty()) {
		mc = this->input.front();
		this->input.pop();
	}

	// If we just popped the last message
	if (this->input.empty()) {
		this->have_input = false;
	}

	input_mtx_.unlock();
	return mc;
}

void MotorSerial::appendOutput(MotorMessage command) {
	output_mtx_.lock();
	this->output.push(command);
	this->have_output = true;
	output_mtx_.unlock();
}

void MotorSerial::SerialThread() {
	try {
		std::vector<uint8_t> in(0);
		bool failed_update = false;

		while (motors->isOpen()) {

			while (motors->available() >= (failed_update ? 1 : 9)) {
				std::vector<uint8_t> innew(0);
				motors->read(innew, failed_update ? 1 : 9);
				in.insert(in.end(), innew.begin(), innew.end());

				while (in.size() > 9) {
					in.erase(in.begin());
				}

				MotorMessage mc;
				int error_code = mc.deserialize(in);

				if (error_code == 0) {
					if (mc.getType() == MotorMessage::TYPE_ERROR){
						ROS_ERROR("GOT ERROR RESPONSE FROM PSOC FOR REGISTER 0x%02x", mc.getRegister());
					}
					appendOutput(mc);
					failed_update = false;
				} else if (error_code == 1) {
					failed_update = true;
					char rejected[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
					for (int i = 0; i < in.size() && i < 9; i++) {
						rejected[i] = in.at(i);
					}
					ROS_ERROR("REJECT: %s", rejected);
				} else {
					failed_update = true;
					ROS_ERROR("DESERIALIZATION ERROR! - %d", error_code);
				}
			}

			bool did_update = false;
			while (inputAvailable()) {
				did_update = true;

				std::vector<uint8_t> out(9);

				out = getInputCommand().serialize();
				// ROS_ERROR("out %x %x %x %x %x %x %x %x %x",
				// 	out[0],
				// 	out[1],
				// 	out[2],
				// 	out[3],
				// 	out[4],
				// 	out[5],
				// 	out[6],
				// 	out[7],
				// 	out[8]);
				motors->write(out);
			}

			if (did_update) {
				motors->flushOutput();
			}

			// boost::posix_time::milliseconds loopDelay(10);
			// boost::this_thread::sleep(loopDelay);
			boost::this_thread::interruption_point();
			serial_loop_rate->sleep();
		}

	}
	catch (const boost::thread_interrupted &e) {
		// ROS_INFO("boost::thread_interrupted");
		motors->close();
	}
	catch (const serial::IOException &e) {
		ROS_ERROR("%s", e.what());
	}
	catch (const serial::PortNotOpenedException &e) {
		ROS_ERROR("%s", e.what());
	}
	catch (...) {
		ROS_ERROR("Unknown Error");
		throw;
	}
}
<commit_msg>Initialize the anti-locking bools<commit_after>/**
Copyright (c) 2016, Ubiquity Robotics
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 the name of ubiquity_motor 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 COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

#include <ubiquity_motor/motor_serial.h>
#include <ros/ros.h>
#include <serial/serial.h>

MotorSerial::MotorSerial(const std::string &port, uint32_t baud_rate, double loopRate) {
	have_input = false;

	// Make sure baud rate is valid
	switch (baud_rate) {
		case 110 :
		case 300 :
		case 600 :
		case 1200 :
		case 2400 :
		case 4800 :
		case 9600 :
		case 14400 :
		case 19200 :
		case 28800 :
		case 38400 :
		case 56000 :
		case 57600 :
		case 115200 :
		case 128000 :
		case 153600 :
		case 230400 :
		case 256000 :
		case 460800 :
		case 921600 :
		this->_baud_rate = baud_rate;
		break;
		default :
		this->_baud_rate = 9600;
		break;
	}

	// TODO verify that port is valid
	this->_port = port;

	motors = new serial::Serial(_port, _baud_rate, serial::Timeout::simpleTimeout(10000));

	serial_loop_rate = new ros::Rate(loopRate);

	serial_thread = new boost::thread(&MotorSerial::SerialThread, this);

	have_input = false;
	have_output = false;
}

MotorSerial::~MotorSerial() {
	serial_thread->interrupt();
	serial_thread->join();
	motors->close();
	delete motors;
	delete serial_thread;
	delete serial_loop_rate;
}

int MotorSerial::transmitCommand(MotorMessage command) {
	// Make sure to lock mutex before accessing the input fifo
	input_mtx_.lock();
	this->input.push(command); // add latest command to end of fifo
	this->have_input = true; //Used to avoid input locking
	input_mtx_.unlock();
	return 0;
}

int MotorSerial::transmitCommands(const std::vector<MotorMessage> &commands) {
	// Make sure to lock mutex before accessing the input fifo
	input_mtx_.lock();
	for (std::vector<MotorMessage>::const_iterator it = commands.begin(); it != commands.end(); ++it) {
		this->input.push(*it);
		this->have_input = true; //Used to avoid input locking
	}
	input_mtx_.unlock();
	return 0;
}

MotorMessage MotorSerial::receiveCommand() {
	MotorMessage mc;

	output_mtx_.lock();
	if (!this->output.empty()) {
		mc = this->output.front();
		this->output.pop();
	}
	output_mtx_.unlock();
	return mc;
}

int MotorSerial::commandAvailable() {
	// If have_output is false return false
	// if it is true, then verify there is output and return true
	// if verification fails make sure have_output is false
	if(!this->have_output) {
		return false;
	}

	output_mtx_.lock();
	int out = !(this->output.empty());
	if(!out) {
		this->have_output = false;
	}
	output_mtx_.unlock();

	return out;
}

int MotorSerial::inputAvailable() {
	// If have_input is false return false
	// if it is true, then verify there is input and return true
	// if verification fails make sure have_input is false

	if (!this->have_input) {
		return false;
	}

	input_mtx_.lock();
	int out = !(this->input.empty());
	if (!out) {
		this->have_input = false;
	}
	input_mtx_.unlock();

	return out;
}

MotorMessage MotorSerial::getInputCommand() {
	MotorMessage mc;
	input_mtx_.lock();
	if (!this->input.empty()) {
		mc = this->input.front();
		this->input.pop();
	}

	// If we just popped the last message
	if (this->input.empty()) {
		this->have_input = false;
	}

	input_mtx_.unlock();
	return mc;
}

void MotorSerial::appendOutput(MotorMessage command) {
	output_mtx_.lock();
	this->output.push(command);
	this->have_output = true;
	output_mtx_.unlock();
}

void MotorSerial::SerialThread() {
	try {
		std::vector<uint8_t> in(0);
		bool failed_update = false;

		while (motors->isOpen()) {

			while (motors->available() >= (failed_update ? 1 : 9)) {
				std::vector<uint8_t> innew(0);
				motors->read(innew, failed_update ? 1 : 9);
				in.insert(in.end(), innew.begin(), innew.end());

				while (in.size() > 9) {
					in.erase(in.begin());
				}

				MotorMessage mc;
				int error_code = mc.deserialize(in);

				if (error_code == 0) {
					if (mc.getType() == MotorMessage::TYPE_ERROR){
						ROS_ERROR("GOT ERROR RESPONSE FROM PSOC FOR REGISTER 0x%02x", mc.getRegister());
					}
					appendOutput(mc);
					failed_update = false;
				} else if (error_code == 1) {
					failed_update = true;
					char rejected[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
					for (int i = 0; i < in.size() && i < 9; i++) {
						rejected[i] = in.at(i);
					}
					ROS_ERROR("REJECT: %s", rejected);
				} else {
					failed_update = true;
					ROS_ERROR("DESERIALIZATION ERROR! - %d", error_code);
				}
			}

			bool did_update = false;
			while (inputAvailable()) {
				did_update = true;

				std::vector<uint8_t> out(9);

				out = getInputCommand().serialize();
				// ROS_ERROR("out %x %x %x %x %x %x %x %x %x",
				// 	out[0],
				// 	out[1],
				// 	out[2],
				// 	out[3],
				// 	out[4],
				// 	out[5],
				// 	out[6],
				// 	out[7],
				// 	out[8]);
				motors->write(out);
			}

			if (did_update) {
				motors->flushOutput();
			}

			// boost::posix_time::milliseconds loopDelay(10);
			// boost::this_thread::sleep(loopDelay);
			boost::this_thread::interruption_point();
			serial_loop_rate->sleep();
		}

	}
	catch (const boost::thread_interrupted &e) {
		// ROS_INFO("boost::thread_interrupted");
		motors->close();
	}
	catch (const serial::IOException &e) {
		ROS_ERROR("%s", e.what());
	}
	catch (const serial::PortNotOpenedException &e) {
		ROS_ERROR("%s", e.what());
	}
	catch (...) {
		ROS_ERROR("Unknown Error");
		throw;
	}
}
<|endoftext|>


<commit_before>// Filename: hashVal.cxx
// Created by:  drose (14Nov00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "hashVal.h"
#include "virtualFileSystem.h"
#include "openSSLWrapper.h"  // must be included before any other openssl.
#include "openssl/md5.h"
#include <ctype.h>

////////////////////////////////////////////////////////////////////
//     Function: HashVal::output_hex
//       Access: Published
//  Description: Outputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
output_hex(ostream &out) const {
  char buffer[32];
  encode_hex(_hv[0], buffer);
  encode_hex(_hv[1], buffer + 8);
  encode_hex(_hv[2], buffer + 16);
  encode_hex(_hv[3], buffer + 24);
  out.write(buffer, 32);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::input_hex
//       Access: Published
//  Description: Inputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
input_hex(istream &in) {
  in >> ws;
  char buffer[32];
  size_t i = 0;
  int ch = in.get();

  while (!in.eof() && !in.fail() && isxdigit(ch)) {
    if (i < 32) {
      buffer[i] = ch;
    }
    i++;
    ch = in.get();
  }

  if (i != 32) {
    in.clear(ios::failbit|in.rdstate());
    return;
  }

  if (!in.eof()) {
    in.putback(ch);
  } else {
    in.clear();
  }

  decode_hex(buffer, _hv[0]);
  decode_hex(buffer + 8, _hv[1]);
  decode_hex(buffer + 16, _hv[2]);
  decode_hex(buffer + 24, _hv[3]);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::output_binary
//       Access: Published
//  Description: Outputs the HashVal as a binary stream of bytes in
//               order.  This is not the same order generated by
//               write_stream().
////////////////////////////////////////////////////////////////////
void HashVal::
output_binary(ostream &out) const {
  StreamWriter writer(out);
  writer.add_be_uint32(_hv[0]);
  writer.add_be_uint32(_hv[1]);
  writer.add_be_uint32(_hv[2]);
  writer.add_be_uint32(_hv[3]);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::input_binary
//       Access: Published
//  Description: Inputs the HashVal as a binary stream of bytes in
//               order.  This is not the same order expected by
//               read_stream().
////////////////////////////////////////////////////////////////////
void HashVal::
input_binary(istream &in) {
  StreamReader reader(in);
  _hv[0] = reader.get_be_uint32();
  _hv[1] = reader.get_be_uint32();
  _hv[2] = reader.get_be_uint32();
  _hv[3] = reader.get_be_uint32();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_dec
//       Access: Published
//  Description: Returns the HashVal as a string with four decimal
//               numbers.
////////////////////////////////////////////////////////////////////
string HashVal::
as_dec() const {
  ostringstream strm;
  output_dec(strm);
  return strm.str();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_dec
//       Access: Published
//  Description: Sets the HashVal from a string with four decimal
//               numbers.  Returns true if valid, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_dec(const string &text) {
  istringstream strm(text);
  input_dec(strm);
  return !strm.fail();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_hex
//       Access: Published
//  Description: Returns the HashVal as a 32-byte hexadecimal string.
////////////////////////////////////////////////////////////////////
string HashVal::
as_hex() const {
  char buffer[32];
  encode_hex(_hv[0], buffer);
  encode_hex(_hv[1], buffer + 8);
  encode_hex(_hv[2], buffer + 16);
  encode_hex(_hv[3], buffer + 24);
  return string(buffer, 32);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_hex
//       Access: Published
//  Description: Sets the HashVal from a 32-byte hexademical string.
//               Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_hex(const string &text) {
  istringstream strm(text);
  input_hex(strm);
  return !strm.fail();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_bin
//       Access: Published
//  Description: Returns the HashVal as a 16-byte binary string.
////////////////////////////////////////////////////////////////////
string HashVal::
as_bin() const {
  Datagram dg;
  write_datagram(dg);
  return dg.get_message();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_bin
//       Access: Published
//  Description: Sets the HashVal from a 16-byte binary string.
//               Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_bin(const string &text) {
  nassertr(text.size() == 16, false);
  Datagram dg(text);
  DatagramIterator dgi(dg);
  read_datagram(dgi);
  return true;
}

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_file
//       Access: Published
//  Description: Generates the hash value from the indicated file.
//               Returns true on success, false if the file cannot be
//               read.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
bool HashVal::
hash_file(const Filename &filename) {
  Filename bin_filename = Filename::binary_filename(filename);
  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
  istream *istr = vfs->open_read_file(bin_filename, false);
  if (istr == (istream *)NULL) {
    (*this) = HashVal();
    return false;
  }

  bool result = hash_stream(*istr);
  vfs->close_read_file(istr);

  return result;
}
#endif  // HAVE_OPENSSL

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_stream
//       Access: Published
//  Description: Generates the hash value from the indicated file.
//               Returns true on success, false if the file cannot be
//               read.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
bool HashVal::
hash_stream(istream &stream) {
  unsigned char md[16];

  MD5_CTX ctx;
  MD5_Init(&ctx);

  static const int buffer_size = 1024;
  char buffer[buffer_size];

  // Seek the stream to the beginning in case it wasn't there already.
  stream.seekg(0, ios::beg);

  stream.read(buffer, buffer_size);
  size_t count = stream.gcount();
  while (count != 0) {
    MD5_Update(&ctx, buffer, count);
    stream.read(buffer, buffer_size);
    count = stream.gcount();
  }

  // Clear the fail bit so the caller can still read the stream (if it
  // wants to).
  stream.clear();

  MD5_Final(md, &ctx);

  // Store the individual bytes as big-endian ints, from historical
  // convention.
  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);

  return true;
}
#endif  // HAVE_OPENSSL

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_buffer
//       Access: Published
//  Description: Generates the hash value by hashing the indicated
//               data.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
void HashVal::
hash_buffer(const char *buffer, int length) {
  unsigned char md[16];
  MD5((const unsigned char *)buffer, length, md);

  // Store the individual bytes as big-endian ints, from historical
  // convention.
  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
}

#endif  // HAVE_OPENSSL

////////////////////////////////////////////////////////////////////
//     Function: HashVal::encode_hex
//       Access: Private, Static
//  Description: Encodes the indicated unsigned int into an
//               eight-digit hex string, stored at the indicated
//               buffer and the following 8 positions.
////////////////////////////////////////////////////////////////////
void HashVal::
encode_hex(PN_uint32 val, char *buffer) {
  buffer[0] = tohex(val >> 28);
  buffer[1] = tohex(val >> 24);
  buffer[2] = tohex(val >> 20);
  buffer[3] = tohex(val >> 16);
  buffer[4] = tohex(val >> 12);
  buffer[5] = tohex(val >> 8);
  buffer[6] = tohex(val >> 4);
  buffer[7] = tohex(val);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::decode_hex
//       Access: Private, Static
//  Description: Decodes the indicated eight-digit hex string into an
//               unsigned integer.
////////////////////////////////////////////////////////////////////
void HashVal::
decode_hex(const char *buffer, PN_uint32 &val) {
  unsigned int bytes[8];
  for (int i = 0; i < 8; i++) {
    bytes[i] = fromhex(buffer[i]);
  }

  val = ((bytes[0] << 28) |
         (bytes[1] << 24) |
         (bytes[2] << 20) |
         (bytes[3] << 16) |
         (bytes[4] << 12) |
         (bytes[5] << 8) |
         (bytes[6] << 4) |
         (bytes[7]));
}

<commit_msg>build issue when openssl is not available<commit_after>// Filename: hashVal.cxx
// Created by:  drose (14Nov00)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

#include "hashVal.h"
#include "virtualFileSystem.h"
#include <ctype.h>

#ifdef HAVE_OPENSSL
#include "openSSLWrapper.h"  // must be included before any other openssl.
#include "openssl/md5.h"
#endif  // HAVE_OPENSSL

////////////////////////////////////////////////////////////////////
//     Function: HashVal::output_hex
//       Access: Published
//  Description: Outputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
output_hex(ostream &out) const {
  char buffer[32];
  encode_hex(_hv[0], buffer);
  encode_hex(_hv[1], buffer + 8);
  encode_hex(_hv[2], buffer + 16);
  encode_hex(_hv[3], buffer + 24);
  out.write(buffer, 32);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::input_hex
//       Access: Published
//  Description: Inputs the HashVal as a 32-digit hexadecimal number.
////////////////////////////////////////////////////////////////////
void HashVal::
input_hex(istream &in) {
  in >> ws;
  char buffer[32];
  size_t i = 0;
  int ch = in.get();

  while (!in.eof() && !in.fail() && isxdigit(ch)) {
    if (i < 32) {
      buffer[i] = ch;
    }
    i++;
    ch = in.get();
  }

  if (i != 32) {
    in.clear(ios::failbit|in.rdstate());
    return;
  }

  if (!in.eof()) {
    in.putback(ch);
  } else {
    in.clear();
  }

  decode_hex(buffer, _hv[0]);
  decode_hex(buffer + 8, _hv[1]);
  decode_hex(buffer + 16, _hv[2]);
  decode_hex(buffer + 24, _hv[3]);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::output_binary
//       Access: Published
//  Description: Outputs the HashVal as a binary stream of bytes in
//               order.  This is not the same order generated by
//               write_stream().
////////////////////////////////////////////////////////////////////
void HashVal::
output_binary(ostream &out) const {
  StreamWriter writer(out);
  writer.add_be_uint32(_hv[0]);
  writer.add_be_uint32(_hv[1]);
  writer.add_be_uint32(_hv[2]);
  writer.add_be_uint32(_hv[3]);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::input_binary
//       Access: Published
//  Description: Inputs the HashVal as a binary stream of bytes in
//               order.  This is not the same order expected by
//               read_stream().
////////////////////////////////////////////////////////////////////
void HashVal::
input_binary(istream &in) {
  StreamReader reader(in);
  _hv[0] = reader.get_be_uint32();
  _hv[1] = reader.get_be_uint32();
  _hv[2] = reader.get_be_uint32();
  _hv[3] = reader.get_be_uint32();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_dec
//       Access: Published
//  Description: Returns the HashVal as a string with four decimal
//               numbers.
////////////////////////////////////////////////////////////////////
string HashVal::
as_dec() const {
  ostringstream strm;
  output_dec(strm);
  return strm.str();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_dec
//       Access: Published
//  Description: Sets the HashVal from a string with four decimal
//               numbers.  Returns true if valid, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_dec(const string &text) {
  istringstream strm(text);
  input_dec(strm);
  return !strm.fail();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_hex
//       Access: Published
//  Description: Returns the HashVal as a 32-byte hexadecimal string.
////////////////////////////////////////////////////////////////////
string HashVal::
as_hex() const {
  char buffer[32];
  encode_hex(_hv[0], buffer);
  encode_hex(_hv[1], buffer + 8);
  encode_hex(_hv[2], buffer + 16);
  encode_hex(_hv[3], buffer + 24);
  return string(buffer, 32);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_hex
//       Access: Published
//  Description: Sets the HashVal from a 32-byte hexademical string.
//               Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_hex(const string &text) {
  istringstream strm(text);
  input_hex(strm);
  return !strm.fail();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::as_bin
//       Access: Published
//  Description: Returns the HashVal as a 16-byte binary string.
////////////////////////////////////////////////////////////////////
string HashVal::
as_bin() const {
  Datagram dg;
  write_datagram(dg);
  return dg.get_message();
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::set_from_bin
//       Access: Published
//  Description: Sets the HashVal from a 16-byte binary string.
//               Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool HashVal::
set_from_bin(const string &text) {
  nassertr(text.size() == 16, false);
  Datagram dg(text);
  DatagramIterator dgi(dg);
  read_datagram(dgi);
  return true;
}

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_file
//       Access: Published
//  Description: Generates the hash value from the indicated file.
//               Returns true on success, false if the file cannot be
//               read.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
bool HashVal::
hash_file(const Filename &filename) {
  Filename bin_filename = Filename::binary_filename(filename);
  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
  istream *istr = vfs->open_read_file(bin_filename, false);
  if (istr == (istream *)NULL) {
    (*this) = HashVal();
    return false;
  }

  bool result = hash_stream(*istr);
  vfs->close_read_file(istr);

  return result;
}
#endif  // HAVE_OPENSSL

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_stream
//       Access: Published
//  Description: Generates the hash value from the indicated file.
//               Returns true on success, false if the file cannot be
//               read.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
bool HashVal::
hash_stream(istream &stream) {
  unsigned char md[16];

  MD5_CTX ctx;
  MD5_Init(&ctx);

  static const int buffer_size = 1024;
  char buffer[buffer_size];

  // Seek the stream to the beginning in case it wasn't there already.
  stream.seekg(0, ios::beg);

  stream.read(buffer, buffer_size);
  size_t count = stream.gcount();
  while (count != 0) {
    MD5_Update(&ctx, buffer, count);
    stream.read(buffer, buffer_size);
    count = stream.gcount();
  }

  // Clear the fail bit so the caller can still read the stream (if it
  // wants to).
  stream.clear();

  MD5_Final(md, &ctx);

  // Store the individual bytes as big-endian ints, from historical
  // convention.
  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);

  return true;
}
#endif  // HAVE_OPENSSL

#ifdef HAVE_OPENSSL
////////////////////////////////////////////////////////////////////
//     Function: HashVal::hash_buffer
//       Access: Published
//  Description: Generates the hash value by hashing the indicated
//               data.  This method is only defined if we have the
//               OpenSSL library (which provides md5 functionality)
//               available.
////////////////////////////////////////////////////////////////////
void HashVal::
hash_buffer(const char *buffer, int length) {
  unsigned char md[16];
  MD5((const unsigned char *)buffer, length, md);

  // Store the individual bytes as big-endian ints, from historical
  // convention.
  _hv[0] = (md[0] << 24) | (md[1] << 16) | (md[2] << 8) | (md[3]);
  _hv[1] = (md[4] << 24) | (md[5] << 16) | (md[6] << 8) | (md[7]);
  _hv[2] = (md[8] << 24) | (md[9] << 16) | (md[10] << 8) | (md[11]);
  _hv[3] = (md[12] << 24) | (md[13] << 16) | (md[14] << 8) | (md[15]);
}

#endif  // HAVE_OPENSSL

////////////////////////////////////////////////////////////////////
//     Function: HashVal::encode_hex
//       Access: Private, Static
//  Description: Encodes the indicated unsigned int into an
//               eight-digit hex string, stored at the indicated
//               buffer and the following 8 positions.
////////////////////////////////////////////////////////////////////
void HashVal::
encode_hex(PN_uint32 val, char *buffer) {
  buffer[0] = tohex(val >> 28);
  buffer[1] = tohex(val >> 24);
  buffer[2] = tohex(val >> 20);
  buffer[3] = tohex(val >> 16);
  buffer[4] = tohex(val >> 12);
  buffer[5] = tohex(val >> 8);
  buffer[6] = tohex(val >> 4);
  buffer[7] = tohex(val);
}

////////////////////////////////////////////////////////////////////
//     Function: HashVal::decode_hex
//       Access: Private, Static
//  Description: Decodes the indicated eight-digit hex string into an
//               unsigned integer.
////////////////////////////////////////////////////////////////////
void HashVal::
decode_hex(const char *buffer, PN_uint32 &val) {
  unsigned int bytes[8];
  for (int i = 0; i < 8; i++) {
    bytes[i] = fromhex(buffer[i]);
  }

  val = ((bytes[0] << 28) |
         (bytes[1] << 24) |
         (bytes[2] << 20) |
         (bytes[3] << 16) |
         (bytes[4] << 12) |
         (bytes[5] << 8) |
         (bytes[6] << 4) |
         (bytes[7]));
}

<|endoftext|>


<commit_before>/*
** Anitomy
** Copyright (C) 2014, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "keyword.h"

namespace anitomy {

KeywordManager keyword_manager;

KeywordOptions::KeywordOptions()
    : safe(true) {
}

KeywordOptions::KeywordOptions(bool safe)
    : safe(safe) {
}

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

KeywordList::KeywordList()
    : length_min_max_(static_cast<size_t>(-1), 0) {
}

void KeywordList::Add(const string_t& str, const KeywordOptions& options) {
  if (str.empty())
    return;

  keys_.insert(std::make_pair(str, options));

  if (str.size() > length_min_max_.second)
    length_min_max_.second = str.size();
  if (str.size() < length_min_max_.first)
    length_min_max_.first = str.size();
}

bool KeywordList::Find(const string_t& str) const {
  if (str.size() < length_min_max_.first ||
      str.size() > length_min_max_.second)
    return false;

  return keys_.find(str) != keys_.end();
}

bool KeywordList::Find(const string_t& str,
                       KeywordOptions& options) const {
  if (str.size() < length_min_max_.first ||
      str.size() > length_min_max_.second)
    return false;

  auto key = keys_.find(str);

  if (key != keys_.end()) {
    options = key->second;
    return true;
  }

  return false;
}

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

KeywordManager::KeywordManager() {
  const KeywordOptions options_safe(true);
  const KeywordOptions options_unsafe(false);

  Add(kElementAnimeType, options_unsafe,
      _TEXT("ED, OAV, ONA, OP, OVA"));

  Add(kElementAudioTerm, options_safe,
      // Audio channels
      _TEXT("2CH, 5.1, 5.1CH, DTS, DTS-ES, DTS5.1, TRUEHD5.1, ")
      // Audio codec
      _TEXT("AAC, AC3, FLAC, MP3, OGG, VORBIS, ")
      // Audio language
      _TEXT("DUALAUDIO, DUAL AUDIO"));

  Add(kElementDeviceCompatibility, options_unsafe,
      _TEXT("ANDROID"));
  Add(kElementDeviceCompatibility, options_safe,
      _TEXT("IPAD3, IPHONE5, IPOD, PS3, XBOX, XBOX360"));

  Add(kElementEpisodePrefix, options_safe,
      _TEXT("E, EP, EP., EPS, EPS., EPISODE, EPISODE., ")
      _TEXT("VOL, VOL., VOLUME, ")
#ifdef ANITOMY_USE_WIDE_CHARACTERS
      _TEXT("\x7B2C")
#else
      // TODO
#endif
      );

  Add(kElementFileExtension, options_safe,
      _TEXT("3GP, AVI, DIVX, FLV, MKV, MOV, MP4, MPG, OGM, RM, RMVB, WMV"));

  Add(kElementLanguage, options_safe,
      _TEXT("ENG, ENGLISH, ESP, ESPANOL, ITA, JAP, SPANISH, VOSTFR"));

  Add(kElementOther, options_safe,
      _TEXT("REMASTERED, UNCENSORED, UNCUT, ")
      _TEXT("TS, VFR, WIDESCREEN, WS"));

  Add(kElementReleaseGroup, options_safe,
      _TEXT("THORA"));

  Add(kElementReleaseInformation, options_safe,
      _TEXT("BATCH, COMPLETE"));
  Add(kElementReleaseInformation, options_unsafe,
      _TEXT("END, FINAL"));

  Add(kElementReleaseVersion, options_safe,
      _TEXT("V0, V1, V2, V3, V4"));

  Add(kElementSource, options_safe,
      _TEXT("BD, BDRIP, BLURAY, BLU-RAY, ")
      _TEXT("DVD, DVD5, DVD9, DVD-R2J, DVDRIP, DVD-RIP, ")
      _TEXT("R2DVD, R2J, R2JDVD, R2JDVDRIP, ")
      _TEXT("HDTV, HDTVRIP, TVRIP, TV-RIP, WEBCAST"));

  Add(kElementSubtitles, options_safe,
      _TEXT("ASS, BIG5, HARDSUB, RAW, SOFTSUB, SUB, SUBBED"));

  Add(kElementVideoTerm, options_safe,
      // Video codec
      _TEXT("8BIT, 8-BIT, 10BIT, 10-BIT, HI10P, ")
      _TEXT("H264, H.264, X264, X.264, ")
      _TEXT("AVC, DIVX, XVID, ")
      // Video format
      _TEXT("AVI, RMVB, WMV, WMV3, WMV9, ")
      // Video quality
      _TEXT("HQ, LQ, ")
      // Video resolution
      _TEXT("HD, SD"));
}

void KeywordManager::Add(ElementCategory category,
                         const KeywordOptions& options,
                         const string_t& keywords) {
  auto& keyword_lists = keyword_lists_[category];

  const string_t separator = _TEXT(", ");
  size_t index_begin = 0, index_end;

  do {
    index_end = keywords.find(separator, index_begin);
    if (index_end == string_t::npos)
      index_end = keywords.size();
    keyword_lists.Add(
        keywords.substr(index_begin, index_end - index_begin), options);
    index_begin = index_end + separator.length();
  } while (index_begin <= keywords.size());
}

bool KeywordManager::Find(ElementCategory category, const string_t& str) {
  const auto& keyword_list = keyword_lists_.find(category);

  if (keyword_list != keyword_lists_.end())
    return keyword_list->second.Find(str);

  return false;
}

bool KeywordManager::Find(ElementCategory category, const string_t& str,
                          KeywordOptions& options) {
  const auto& keyword_list = keyword_lists_.find(category);

  if (keyword_list != keyword_lists_.end())
    return keyword_list->second.Find(str, options);

  return false;
}

}  // namespace anitomy<commit_msg>Add keywords: TV, Episodio, Folge<commit_after>/*
** Anitomy
** Copyright (C) 2014, Eren Okka
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "keyword.h"

namespace anitomy {

KeywordManager keyword_manager;

KeywordOptions::KeywordOptions()
    : safe(true) {
}

KeywordOptions::KeywordOptions(bool safe)
    : safe(safe) {
}

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

KeywordList::KeywordList()
    : length_min_max_(static_cast<size_t>(-1), 0) {
}

void KeywordList::Add(const string_t& str, const KeywordOptions& options) {
  if (str.empty())
    return;

  keys_.insert(std::make_pair(str, options));

  if (str.size() > length_min_max_.second)
    length_min_max_.second = str.size();
  if (str.size() < length_min_max_.first)
    length_min_max_.first = str.size();
}

bool KeywordList::Find(const string_t& str) const {
  if (str.size() < length_min_max_.first ||
      str.size() > length_min_max_.second)
    return false;

  return keys_.find(str) != keys_.end();
}

bool KeywordList::Find(const string_t& str,
                       KeywordOptions& options) const {
  if (str.size() < length_min_max_.first ||
      str.size() > length_min_max_.second)
    return false;

  auto key = keys_.find(str);

  if (key != keys_.end()) {
    options = key->second;
    return true;
  }

  return false;
}

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

KeywordManager::KeywordManager() {
  const KeywordOptions options_safe(true);
  const KeywordOptions options_unsafe(false);

  Add(kElementAnimeType, options_unsafe,
      _TEXT("ED, OAV, ONA, OP, OVA, TV"));

  Add(kElementAudioTerm, options_safe,
      // Audio channels
      _TEXT("2CH, 5.1, 5.1CH, DTS, DTS-ES, DTS5.1, TRUEHD5.1, ")
      // Audio codec
      _TEXT("AAC, AC3, FLAC, MP3, OGG, VORBIS, ")
      // Audio language
      _TEXT("DUALAUDIO, DUAL AUDIO"));

  Add(kElementDeviceCompatibility, options_unsafe,
      _TEXT("ANDROID"));
  Add(kElementDeviceCompatibility, options_safe,
      _TEXT("IPAD3, IPHONE5, IPOD, PS3, XBOX, XBOX360"));

  Add(kElementEpisodePrefix, options_safe,
      _TEXT("E, EP, EP., EPS, EPS., EPISODE, EPISODE., ")
      _TEXT("EPISODIO, FOLGE, ")
      _TEXT("VOL, VOL., VOLUME, ")
#ifdef ANITOMY_USE_WIDE_CHARACTERS
      _TEXT("\x7B2C")
#else
      // TODO
#endif
      );

  Add(kElementFileExtension, options_safe,
      _TEXT("3GP, AVI, DIVX, FLV, MKV, MOV, MP4, MPG, OGM, RM, RMVB, WMV"));

  Add(kElementLanguage, options_safe,
      _TEXT("ENG, ENGLISH, ESP, ESPANOL, ITA, JAP, SPANISH, VOSTFR"));

  Add(kElementOther, options_safe,
      _TEXT("REMASTERED, UNCENSORED, UNCUT, ")
      _TEXT("TS, VFR, WIDESCREEN, WS"));

  Add(kElementReleaseGroup, options_safe,
      _TEXT("THORA"));

  Add(kElementReleaseInformation, options_safe,
      _TEXT("BATCH, COMPLETE"));
  Add(kElementReleaseInformation, options_unsafe,
      _TEXT("END, FINAL"));

  Add(kElementReleaseVersion, options_safe,
      _TEXT("V0, V1, V2, V3, V4"));

  Add(kElementSource, options_safe,
      _TEXT("BD, BDRIP, BLURAY, BLU-RAY, ")
      _TEXT("DVD, DVD5, DVD9, DVD-R2J, DVDRIP, DVD-RIP, ")
      _TEXT("R2DVD, R2J, R2JDVD, R2JDVDRIP, ")
      _TEXT("HDTV, HDTVRIP, TVRIP, TV-RIP, WEBCAST"));

  Add(kElementSubtitles, options_safe,
      _TEXT("ASS, BIG5, HARDSUB, RAW, SOFTSUB, SUB, SUBBED"));

  Add(kElementVideoTerm, options_safe,
      // Video codec
      _TEXT("8BIT, 8-BIT, 10BIT, 10-BIT, HI10P, ")
      _TEXT("H264, H.264, X264, X.264, ")
      _TEXT("AVC, DIVX, XVID, ")
      // Video format
      _TEXT("AVI, RMVB, WMV, WMV3, WMV9, ")
      // Video quality
      _TEXT("HQ, LQ, ")
      // Video resolution
      _TEXT("HD, SD"));
}

void KeywordManager::Add(ElementCategory category,
                         const KeywordOptions& options,
                         const string_t& keywords) {
  auto& keyword_lists = keyword_lists_[category];

  const string_t separator = _TEXT(", ");
  size_t index_begin = 0, index_end;

  do {
    index_end = keywords.find(separator, index_begin);
    if (index_end == string_t::npos)
      index_end = keywords.size();
    keyword_lists.Add(
        keywords.substr(index_begin, index_end - index_begin), options);
    index_begin = index_end + separator.length();
  } while (index_begin <= keywords.size());
}

bool KeywordManager::Find(ElementCategory category, const string_t& str) {
  const auto& keyword_list = keyword_lists_.find(category);

  if (keyword_list != keyword_lists_.end())
    return keyword_list->second.Find(str);

  return false;
}

bool KeywordManager::Find(ElementCategory category, const string_t& str,
                          KeywordOptions& options) {
  const auto& keyword_list = keyword_lists_.find(category);

  if (keyword_list != keyword_lists_.end())
    return keyword_list->second.Find(str, options);

  return false;
}

}  // namespace anitomy<|endoftext|>


<commit_before>// Copyright 2015/2016 Yahoo Inc.
// Licensed under the BSD license, see LICENSE file for terms.
// Written by Chris Rohlf

#include "mathilda_fork.h"

/// Returns the PID for this child process
pid_t MathildaFork::get_pid() {
	return my_proc_info.pid;
}

/// Returns the shared memory ID for this child process
int MathildaFork::get_shm_id() {
	return my_proc_info.shm_id;
}

/// Returns the shared memory pointer for this child process
uint8_t *MathildaFork::get_shm_ptr() {
	return my_proc_info.shm_ptr;
}

/// Returns the size of the shared memory segment
size_t MathildaFork::get_shm_size() {
	return my_proc_info.shm_size;
}

/// Adds a string to an array of [size, string]
/// structures in shared memory
///
/// Inserts a string and its corresponding
/// length value into a list. Intended to
/// be used for parent<->child exchange of
/// data via shared memory
///
/// @param[in] str Pointer to a C string
/// @param[in] sz Size of the string
int MathildaFork::shm_store_string(const char *str, size_t sz) {
	RET_ERR_IF_PTR_INVALID(get_shm_ptr());

	if(sz == 0) {
		return 0;
	}

	if(sz > 16384) {
		sz = 16384;
	}

	StringEntry *tmp = (StringEntry *) get_shm_ptr();
	uint8_t *string = NULL;

	while(tmp->length != 0) {
		tmp = tmp + tmp->length;
	}

	if(tmp > (StringEntry *) get_shm_ptr() + get_shm_size()) {
		return ERR;
	}

	string = (uint8_t *) tmp + sizeof(StringEntry);
	tmp->length = sz;
	memcpy(string, str, sz);

	return OK;
}

/// Extracts strings from shared memory and puts
/// them into a std::vector
///
/// @param[in] strings A reference to a vector of std::string
/// @return Returns the size of the vector
int MathildaFork::shm_retrieve_strings(uint8_t *shm_ptr, size_t shm_size, std::vector<std::string> &strings) {
	RET_ERR_IF_PTR_INVALID(shm_ptr);

	StringEntry *head = (StringEntry *) shm_ptr;
	char *string;

	while(head->length != 0) {
		string = (char *) head + sizeof(StringEntry);

		if(string >= (char *) (shm_ptr + shm_size)) {
			return strings.size();
		}

		if(strlen(string) == head->length) {
			strings.push_back(string);
		}

		head += head->length;
	}

	return strings.size();
}

/// Adds a string to an array of [size, string]
/// structures in shared memory
///
/// Inserts a string and its corresponding
/// length value into a list. Intended to
/// be used for parent<->child exchange of
/// data via shared memory
///
/// @param[in] str Pointer to a NULL terminated C string
int MathildaFork::shm_store_string(const char *str) {
	return shm_store_string(str, strlen(str));
}

// Sets the processor affinity
//
// Mathilda works by breaking up sets of Instructions to be
// executed by child processes. This function is called
// by child processes to bind them to a specific cpu
//
// @param[in] CPU number to bind to
void MathildaFork::set_affinity(uint32_t c) {
	if(c >= cores) {
		c = 0;
	}

	cpu_set_t cpus;
	CPU_ZERO(&cpus);
	CPU_SET(c, &cpus);

	int ret = sched_setaffinity(0, sizeof(cpus), &cpus);

	core = c;

#ifdef DEBUG
	if(ret == ERR) {
		fprintf(stdout, "[MathildaFork] Failed to bind process %d to CPU %d. Cache invalidation may occur!\n", getpid(), c);
	} else {
		fprintf(stdout, "[MathildaFork] Child (pid: %d) successfully bound to CPU %d\n", getpid(), c);
	}
#endif
}

// Returns the ProcessInfo structure for a PID
//
// This function iterates through all the ProcessInfo
// structures for each child it is managing and return
// a pointer to the structure for a PID
//
// @param[in] pid The PID you want a ProcessInfo structure for
// @return Returns a pointer to the ProcessInfo structure for PID
ProcessInfo *MathildaFork::process_info_pid(pid_t pid) {
	for(auto p : children) {
		if(pid == p->pid) {
			return p;
		}
	}

	return NULL;
}

// Removes a ProcessInfo structure for a given PID
//
// This function iterates through all internal ProcessInfo
// structures and finds a pointer to the one that represents
// the PID passed in. That structure is deleted
//
// @param[in] pid The PID of the process we no longer
//			  need to track
void MathildaFork::remove_child_pid(pid_t pid) {
	auto it = std::remove_if(children.begin(), children.end(),
		[pid](ProcessInfo *p) {
			return p->pid == pid;
		}
	);

	ProcessInfo *p = process_info_pid(pid);
	delete_shm(p);

	children.erase(it, children.end());
}

// Create a shared memory segment for a child process
//
// This function takes a pointer to a ProcessInfo structure
// creates a shared memory segment for it. A default size
// of SHM_SIZE is used
//
// @param[in,out] pi A pointer to a ProcessInfo structure
void MathildaFork::create_shm(ProcessInfo *pi) {
	create_shm(pi, SHM_SIZE);
}

// Create a shared memory segment for a child process
//
// This function takes a pointer to a ProcessInfo structure
// creates a shared memory segment for it.
//
// @param[in,out] pi A pointer to a ProcessInfo structure
// @param[in] sz The size of the shared memory segment. This
//			  must be greater than SHM_SIZE
void MathildaFork::create_shm(ProcessInfo *pi, size_t sz) {
	if(sz < SHM_SIZE) {
		sz = SHM_SIZE;
	}

	pi->shm_size = sz;

	pi->shm_id = shmget(IPC_PRIVATE, sz, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);

	if(pi->shm_id == ERR) {
		fprintf(stderr, "[MathildaFork] Could not allocate shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}

	pi->shm_ptr = (uint8_t *) shmat(pi->shm_id, 0, 0);

	if(pi->shm_ptr == (void *) ERR) {
		fprintf(stderr, "[MathildaFork] Could not get handle to shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}
}

// Delete a shared memory segment
//
// This function takes a pointer to a ProcessInfo
// structure and destroys the shared memory used
// by it
//
// @param[in] s A pointer to a ProcessInfo structure
void MathildaFork::delete_shm(ProcessInfo *s) {
	if(s == NULL || s->shm_id == 0 || s->shm_ptr == NULL) {
		return;
	}

	int ret = shmctl(s->shm_id, IPC_RMID, NULL);

	if(ret == ERR) {
		fprintf(stderr, "[Mathilda] Failed to free shared memory (%d). Aborting!\n(%s)\n", s->shm_id, strerror(errno));
		abort();
	}

	ret = shmdt(s->shm_ptr);

	if(ret == ERR) {
		fprintf(stderr, "[Mathilda] Failed to detach shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}

	s->shm_ptr = NULL;
	s->shm_id = 0;
	s->shm_size = 0;
}

// Connect a shared memory segment given a ProcessInfo structure
//
// This is just a wrapper around shmat() that uses the information
// stored in a ProcessInfo structure
//
// @param[in] pi A pointer to a ProcessInfo structure
void MathildaFork::connect_shm(ProcessInfo *pi) {
	pi->shm_ptr = (uint8_t *) shmat(pi->shm_id, 0, 0);
}

// Forks a child process with no support for shared memory
//
// Forks a child process and handles creating the ProcessInfo
// structure associated with it. The default timeout is 90
// seconds.
//
// @param[in] set_core True if set_affinity should be called
// @return Returns the PID of the child process or ERR
pid_t MathildaFork::fork_child(bool set_core) {
	return fork_child(set_core, false, false, DEFAULT_TIMEOUT);
}

// Forks a child process with support for CPU binding and
// shared memory setup
//
// Forks a child process and handles creating the ProcessInfo
// structure associated with it. Supports shared memory creation
// via flags.
//
// @param[in] set_core True if set_affinity should be called
// @param[in] use_shm True if shared memory should be created
// @param[in] sz Size of the shared memory segment
// @return Returns the PID of the child process or ERR
pid_t MathildaFork::fork_child(bool set_core, bool use_shm, size_t sz, uint32_t timeout) {
	ProcessInfo *pi = new ProcessInfo;

	if(pi == NULL) {
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork] Failed to allocate ProcessInfo. Aborting!\n");
#endif
		abort();
	}

	memset(pi, 0x0, sizeof(ProcessInfo));

	if(use_shm == true) {
		MathildaFork::create_shm(pi, sz);
	}

	pi->timeout = timeout;

	pid_t p = fork();

	if(p == ERR) {
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork] Failed to fork!\n");
#endif
	} else if(p != 0) { // Parent
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork %d] Child process forked\n", p);
#endif
		pi->pid = p;

		if(use_shm == true) {
			connect_shm(pi);
		}

		children.push_back(pi);

		if(set_core == true) {
			core++;

			if(core >= cores) {
				core = 0;
			}
		}
	} else {  // Child
		parent = false;

		my_proc_info.pid = getpid();
		my_proc_info.shm_id = pi->shm_id;

		if(set_core == true) {
			set_affinity(core);
		}

		if(use_shm == true) {
			connect_shm(&my_proc_info);
		}

		alarm(timeout);
	}

	return p;
}

// A wait loop for child processes
//
// This function makes it easier for a parent process to
// wait on any child process for a basic set of signals
// and fills out the WaitResult structure passed to it
//
// @param[in,out] wr A pointer to a WaitResult structure that
//					 indicates whether the child process has
//					 exited or received another signal
// @return Returns an pid or ERR similar to waitpid()
int MathildaFork::wait(WaitResult *wr) {
	int status = 0;

	memset(wr, 0x0, sizeof(WaitResult));

	while((wr->pid = waitpid(-1, &status, 0))) {
		if(errno == ECHILD || wr->pid == ERR) {
			return ERR;
		}

		wr->return_code = WEXITSTATUS(status);

		if(WIFEXITED(status)) {
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d exited normally with return code %d\n", wr->pid, wr->return_code);
#endif
			return wr->pid;
		}

		if(WIFSIGNALED(status)) {
			wr->signal = WTERMSIG(status);
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d was terminated by signal %d\n", wr->pid, wr->signal);
#endif
			if(WCOREDUMP(status)) {
#ifdef DEBUG
				fprintf(stdout, "[MathildaFork] Child %d core dumped\n", wr->pid);
#endif
				return wr->pid;
			}

			// This process probably timed out. Use
			// kill so we don't get a zombie process
			if(wr->signal == SIGALRM) {
#ifdef DEBUG
				fprintf(stdout, "[MathildaFork] Child %d likely timed out\n", wr->pid);
#endif
				return wr->pid;
			}
		}

		if(WIFSTOPPED(status)) {
			wr->signal = WSTOPSIG(status);
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d was stopped by signal %d\n", wr->pid, wr->signal);
#endif
		}
	}

	return wr->pid;
}<commit_msg>fix order of operations bug that led to shm leak<commit_after>// Copyright 2015/2016 Yahoo Inc.
// Licensed under the BSD license, see LICENSE file for terms.
// Written by Chris Rohlf

#include "mathilda_fork.h"

/// Returns the PID for this child process
pid_t MathildaFork::get_pid() {
	return my_proc_info.pid;
}

/// Returns the shared memory ID for this child process
int MathildaFork::get_shm_id() {
	return my_proc_info.shm_id;
}

/// Returns the shared memory pointer for this child process
uint8_t *MathildaFork::get_shm_ptr() {
	return my_proc_info.shm_ptr;
}

/// Returns the size of the shared memory segment
size_t MathildaFork::get_shm_size() {
	return my_proc_info.shm_size;
}

/// Adds a string to an array of [size, string]
/// structures in shared memory
///
/// Inserts a string and its corresponding
/// length value into a list. Intended to
/// be used for parent<->child exchange of
/// data via shared memory
///
/// @param[in] str Pointer to a C string
/// @param[in] sz Size of the string
int MathildaFork::shm_store_string(const char *str, size_t sz) {
	RET_ERR_IF_PTR_INVALID(get_shm_ptr());

	if(sz == 0) {
		return 0;
	}

	if(sz > 16384) {
		sz = 16384;
	}

	StringEntry *tmp = (StringEntry *) get_shm_ptr();
	uint8_t *string = NULL;

	while(tmp->length != 0) {
		tmp = tmp + tmp->length;
	}

	if(tmp > (StringEntry *) get_shm_ptr() + get_shm_size()) {
		return ERR;
	}

	string = (uint8_t *) tmp + sizeof(StringEntry);
	tmp->length = sz;
	memcpy(string, str, sz);

	return OK;
}

/// Extracts strings from shared memory and puts
/// them into a std::vector
///
/// @param[in] strings A reference to a vector of std::string
/// @return Returns the size of the vector
int MathildaFork::shm_retrieve_strings(uint8_t *shm_ptr, size_t shm_size, std::vector<std::string> &strings) {
	RET_ERR_IF_PTR_INVALID(shm_ptr);

	StringEntry *head = (StringEntry *) shm_ptr;
	char *string;

	while(head->length != 0) {
		string = (char *) head + sizeof(StringEntry);

		if(string >= (char *) (shm_ptr + shm_size)) {
			return strings.size();
		}

		if(strlen(string) == head->length) {
			strings.push_back(string);
		}

		head += head->length;
	}

	return strings.size();
}

/// Adds a string to an array of [size, string]
/// structures in shared memory
///
/// Inserts a string and its corresponding
/// length value into a list. Intended to
/// be used for parent<->child exchange of
/// data via shared memory
///
/// @param[in] str Pointer to a NULL terminated C string
int MathildaFork::shm_store_string(const char *str) {
	return shm_store_string(str, strlen(str));
}

// Sets the processor affinity
//
// Mathilda works by breaking up sets of Instructions to be
// executed by child processes. This function is called
// by child processes to bind them to a specific cpu
//
// @param[in] CPU number to bind to
void MathildaFork::set_affinity(uint32_t c) {
	if(c >= cores) {
		c = 0;
	}

	cpu_set_t cpus;
	CPU_ZERO(&cpus);
	CPU_SET(c, &cpus);

	int ret = sched_setaffinity(0, sizeof(cpus), &cpus);

	core = c;

#ifdef DEBUG
	if(ret == ERR) {
		fprintf(stdout, "[MathildaFork] Failed to bind process %d to CPU %d. Cache invalidation may occur!\n", getpid(), c);
	} else {
		fprintf(stdout, "[MathildaFork] Child (pid: %d) successfully bound to CPU %d\n", getpid(), c);
	}
#endif
}

// Returns the ProcessInfo structure for a PID
//
// This function iterates through all the ProcessInfo
// structures for each child it is managing and return
// a pointer to the structure for a PID
//
// @param[in] pid The PID you want a ProcessInfo structure for
// @return Returns a pointer to the ProcessInfo structure for PID
ProcessInfo *MathildaFork::process_info_pid(pid_t pid) {
	for(auto p : children) {
		if(pid == p->pid) {
			return p;
		}
	}

	return NULL;
}

// Removes a ProcessInfo structure for a given PID
//
// This function iterates through all internal ProcessInfo
// structures and finds a pointer to the one that represents
// the PID passed in. That structure is deleted
//
// @param[in] pid The PID of the process we no longer
//			  need to track
void MathildaFork::remove_child_pid(pid_t pid) {
	ProcessInfo *p = process_info_pid(pid);

	if(p != NULL) {
		delete_shm(p);
	}

	auto it = std::remove_if(children.begin(), children.end(),
		[pid](ProcessInfo *p) {
			return p->pid == pid;
		}
	);

	children.erase(it, children.end());
}

// Create a shared memory segment for a child process
//
// This function takes a pointer to a ProcessInfo structure
// creates a shared memory segment for it. A default size
// of SHM_SIZE is used
//
// @param[in,out] pi A pointer to a ProcessInfo structure
void MathildaFork::create_shm(ProcessInfo *pi) {
	create_shm(pi, SHM_SIZE);
}

// Create a shared memory segment for a child process
//
// This function takes a pointer to a ProcessInfo structure
// creates a shared memory segment for it.
//
// @param[in,out] pi A pointer to a ProcessInfo structure
// @param[in] sz The size of the shared memory segment. This
//			  must be greater than SHM_SIZE
void MathildaFork::create_shm(ProcessInfo *pi, size_t sz) {
	if(sz < SHM_SIZE) {
		sz = SHM_SIZE;
	}

	pi->shm_size = sz;

	pi->shm_id = shmget(IPC_PRIVATE, sz, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);

	if(pi->shm_id == ERR) {
		fprintf(stderr, "[MathildaFork] Could not allocate shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}

	pi->shm_ptr = (uint8_t *) shmat(pi->shm_id, 0, 0);

	if(pi->shm_ptr == (void *) ERR) {
		fprintf(stderr, "[MathildaFork] Could not get handle to shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}
}

// Delete a shared memory segment
//
// This function takes a pointer to a ProcessInfo
// structure and destroys the shared memory used
// by it
//
// @param[in] s A pointer to a ProcessInfo structure
void MathildaFork::delete_shm(ProcessInfo *s) {
	if(s == NULL || s->shm_id == 0 || s->shm_ptr == NULL) {
		return;
	}

	int ret = shmctl(s->shm_id, IPC_RMID, NULL);

	if(ret == ERR) {
		fprintf(stderr, "[Mathilda] Failed to free shared memory (%d). Aborting!\n(%s)\n", s->shm_id, strerror(errno));
		abort();
	}

	ret = shmdt(s->shm_ptr);

	if(ret == ERR) {
		fprintf(stderr, "[Mathilda] Failed to detach shared memory. Aborting!\n(%s)\n", strerror(errno));
		abort();
	}

	s->shm_ptr = NULL;
	s->shm_id = 0;
	s->shm_size = 0;
}

// Connect a shared memory segment given a ProcessInfo structure
//
// This is just a wrapper around shmat() that uses the information
// stored in a ProcessInfo structure
//
// @param[in] pi A pointer to a ProcessInfo structure
void MathildaFork::connect_shm(ProcessInfo *pi) {
	pi->shm_ptr = (uint8_t *) shmat(pi->shm_id, 0, 0);
}

// Forks a child process with no support for shared memory
//
// Forks a child process and handles creating the ProcessInfo
// structure associated with it. The default timeout is 90
// seconds.
//
// @param[in] set_core True if set_affinity should be called
// @return Returns the PID of the child process or ERR
pid_t MathildaFork::fork_child(bool set_core) {
	return fork_child(set_core, false, false, DEFAULT_TIMEOUT);
}

// Forks a child process with support for CPU binding and
// shared memory setup
//
// Forks a child process and handles creating the ProcessInfo
// structure associated with it. Supports shared memory creation
// via flags.
//
// @param[in] set_core True if set_affinity should be called
// @param[in] use_shm True if shared memory should be created
// @param[in] sz Size of the shared memory segment
// @return Returns the PID of the child process or ERR
pid_t MathildaFork::fork_child(bool set_core, bool use_shm, size_t sz, uint32_t timeout) {
	ProcessInfo *pi = new ProcessInfo;

	if(pi == NULL) {
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork] Failed to allocate ProcessInfo. Aborting!\n");
#endif
		abort();
	}

	memset(pi, 0x0, sizeof(ProcessInfo));

	if(use_shm == true) {
		MathildaFork::create_shm(pi, sz);
	}

	pi->timeout = timeout;

	pid_t p = fork();

	if(p == ERR) {
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork] Failed to fork!\n");
#endif
	} else if(p != 0) { // Parent
#ifdef DEBUG
		fprintf(stdout, "[MathildaFork %d] Child process forked\n", p);
#endif
		pi->pid = p;

		if(use_shm == true) {
			connect_shm(pi);
		}

		children.push_back(pi);

		if(set_core == true) {
			core++;

			if(core >= cores) {
				core = 0;
			}
		}
	} else {  // Child
		parent = false;

		my_proc_info.pid = getpid();
		my_proc_info.shm_id = pi->shm_id;

		if(set_core == true) {
			set_affinity(core);
		}

		if(use_shm == true) {
			connect_shm(&my_proc_info);
		}

		alarm(timeout);
	}

	return p;
}

// A wait loop for child processes
//
// This function makes it easier for a parent process to
// wait on any child process for a basic set of signals
// and fills out the WaitResult structure passed to it
//
// @param[in,out] wr A pointer to a WaitResult structure that
//					 indicates whether the child process has
//					 exited or received another signal
// @return Returns an pid or ERR similar to waitpid()
int MathildaFork::wait(WaitResult *wr) {
	int status = 0;

	memset(wr, 0x0, sizeof(WaitResult));

	while((wr->pid = waitpid(-1, &status, 0))) {
		if(errno == ECHILD || wr->pid == ERR) {
			return ERR;
		}

		wr->return_code = WEXITSTATUS(status);

		if(WIFEXITED(status)) {
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d exited normally with return code %d\n", wr->pid, wr->return_code);
#endif
			return wr->pid;
		}

		if(WIFSIGNALED(status)) {
			wr->signal = WTERMSIG(status);
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d was terminated by signal %d\n", wr->pid, wr->signal);
#endif
			if(WCOREDUMP(status)) {
#ifdef DEBUG
				fprintf(stdout, "[MathildaFork] Child %d core dumped\n", wr->pid);
#endif
				return wr->pid;
			}

			// This process probably timed out. Use
			// kill so we don't get a zombie process
			if(wr->signal == SIGALRM) {
#ifdef DEBUG
				fprintf(stdout, "[MathildaFork] Child %d likely timed out\n", wr->pid);
#endif
				return wr->pid;
			}
		}

		if(WIFSTOPPED(status)) {
			wr->signal = WSTOPSIG(status);
#ifdef DEBUG
			fprintf(stdout, "[MathildaFork] Child %d was stopped by signal %d\n", wr->pid, wr->signal);
#endif
		}
	}

	return wr->pid;
}<|endoftext|>


<commit_before>#include "integrator.h"
#include <iostream>

using std::cerr;

PathTracerIntegrator::PathTracerIntegrator()
  : sampler(unique_ptr<UniformSampler>(new UniformSampler())), samples_per_pixel(16),
    russian_roulette(true), rr_kill_prob(0.2), max_depth(10)
{
  assert(0.0 <= rr_kill_prob && rr_kill_prob <= 1.0);
}

void PathTracerIntegrator::render(Camera* cam, Scene* scene, Film* film)
{

  for (uint x = 0; x < film->width; ++x)
  {
    for (uint y = 0; y < film->height; ++y)
    {
      for (uint d = 0; d < samples_per_pixel; ++d)
      {
        auto sample = sampler->sample_2d();
        PixelSample ps = cam->sample_pixel(film, x, y, sample[0], sample[1]);
        spectrum s = trace_ray(scene, ps.ray, 1);
        film->add_sample(ps, s);
      }
    }
  }
}

spectrum PathTracerIntegrator::trace_ray(Scene* scene, const Ray& ray, int depth)
{
  Intersection isect = scene->intersect(ray);
  const Vec3 ray_dir_n = -ray.direction.normal();
  if (!isect.valid())
    return environmental_lighting(-ray_dir_n);
  if (isect.shape->is_emissive())
    return isect.shape->emission() * isect.texture_at_point();

  // direct lighting: randomly choose a light or emissive shape, and contribute
  // the light from that shape if appropriate
  scalar light_prob;
  const Light* light = scene->sample_light(sampler->sample_1d(), light_prob);

  spectrum total{0};

  if (light_prob > 0)
  {
    Sample2D light_s = sampler->sample_2d();
    LightSample ls = light->sample_emission(isect, light_s[0], light_s[1]);

    if (ls)
    {
      if (!ls.is_occluded(scene))
      {
        scalar NL = max<scalar>(ls.direction().dot(isect.normal), 0.0);
        scalar ca = isect.shape->brdf->reflectance( ls.direction(),
                                                    ray_dir_n, isect.normal );

        auto light_contrib = ls.emission() * spectrum{NL * ca / light_prob};
        total += light_contrib;
      }
    }
  }

  // Decide whether or not to continue trace and, if so, what the multiplier
  // should be.
  bool continue_trace = true;
  scalar p_mult = 1.0;
  if (max_depth > 0 && depth >= max_depth)
    continue_trace = false;

  else if (russian_roulette)
  {
    if (sampler->sample_1d() < rr_kill_prob)
    {
      continue_trace = false;
    }
    else
    {
      p_mult /= (1 - rr_kill_prob);
    }
  }

  if (continue_trace)
  {
    scalar brdf_p = 0;
    auto brdf_u = sampler->sample_2d();
    scalar brdf_reflectance;
    Vec3 brdf_dir = isect.sample_brdf(ray_dir_n, brdf_u.u[0], brdf_u.u[1],
                                      brdf_p, brdf_reflectance);
    if (brdf_p > 0)
    {
       total += trace_ray( scene, Ray{isect.position, brdf_dir}.nudge(), depth + 1 ) *
        spectrum{p_mult / brdf_p * brdf_dir.dot(isect.normal) * brdf_reflectance};
    }
  }

  return total * isect.texture_at_point();
}

spectrum PathTracerIntegrator::trace_shadow_ray(Scene* scene, PossibleEmissive const* em,
                                                const Ray& ray)
{
  auto isect = scene->shadow_intersect(ray);
  if (isect.valid() && isect.shape == em)
    return em->emission();
  else
    return spectrum::zero;
}

spectrum PathTracerIntegrator::environmental_lighting(const Vec3& ray_dir) const
{
  return spectrum{1.0};
}
<commit_msg>Fixes field initialization order for path_tracer<commit_after>#include "integrator.h"
#include <iostream>

using std::cerr;

PathTracerIntegrator::PathTracerIntegrator()
  : samples_per_pixel(16), sampler(unique_ptr<UniformSampler>(new UniformSampler())),
    russian_roulette(true), rr_kill_prob(0.2), max_depth(10)
{
  assert(0.0 <= rr_kill_prob && rr_kill_prob <= 1.0);
}

void PathTracerIntegrator::render(Camera* cam, Scene* scene, Film* film)
{
  for (uint x = 0; x < film->width; ++x)
  {
    for (uint y = 0; y < film->height; ++y)
    {
      for (uint d = 0; d < samples_per_pixel; ++d)
      {
        auto sample = sampler->sample_2d();
        PixelSample ps = cam->sample_pixel(film, x, y, sample[0], sample[1]);
        spectrum s = trace_ray(scene, ps.ray, 1);
        film->add_sample(ps, s);
      }
    }
  }
}

spectrum PathTracerIntegrator::trace_ray(Scene* scene, const Ray& ray, int depth)
{
  Intersection isect = scene->intersect(ray);
  const Vec3 ray_dir_n = -ray.direction.normal();
  if (!isect.valid())
    return environmental_lighting(-ray_dir_n);
  if (isect.shape->is_emissive())
    return isect.shape->emission() * isect.texture_at_point();

  // direct lighting: randomly choose a light or emissive shape, and contribute
  // the light from that shape if appropriate
  scalar light_prob;
  const Light* light = scene->sample_light(sampler->sample_1d(), light_prob);

  spectrum total{0};

  if (light_prob > 0)
  {
    Sample2D light_s = sampler->sample_2d();
    LightSample ls = light->sample_emission(isect, light_s[0], light_s[1]);

    if (ls)
    {
      if (!ls.is_occluded(scene))
      {
        scalar NL = max<scalar>(ls.direction().dot(isect.normal), 0.0);
        scalar ca = isect.shape->brdf->reflectance( ls.direction(),
                                                    ray_dir_n, isect.normal );

        auto light_contrib = ls.emission() * spectrum{NL * ca / light_prob};
        total += light_contrib;
      }
    }
  }

  // Decide whether or not to continue trace and, if so, what the multiplier
  // should be.
  bool continue_trace = true;
  scalar p_mult = 1.0;
  if (max_depth > 0 && depth >= max_depth)
    continue_trace = false;

  else if (russian_roulette)
  {
    if (sampler->sample_1d() < rr_kill_prob)
    {
      continue_trace = false;
    }
    else
    {
      p_mult /= (1 - rr_kill_prob);
    }
  }

  if (continue_trace)
  {
    scalar brdf_p = 0;
    auto brdf_u = sampler->sample_2d();
    scalar brdf_reflectance;
    Vec3 brdf_dir = isect.sample_brdf(ray_dir_n, brdf_u.u[0], brdf_u.u[1],
                                      brdf_p, brdf_reflectance);
    if (brdf_p > 0)
    {
       total += trace_ray( scene, Ray{isect.position, brdf_dir}.nudge(), depth + 1 ) *
        spectrum{p_mult / brdf_p * brdf_dir.dot(isect.normal) * brdf_reflectance};
    }
  }

  return total * isect.texture_at_point();
}

spectrum PathTracerIntegrator::trace_shadow_ray(Scene* scene, PossibleEmissive const* em,
                                                const Ray& ray)
{
  auto isect = scene->shadow_intersect(ray);
  if (isect.valid() && isect.shape == em)
    return em->emission();
  else
    return spectrum::zero;
}

spectrum PathTracerIntegrator::environmental_lighting(const Vec3& ray_dir) const
{
  return spectrum{1.0};
}
<|endoftext|>


<commit_before>#include "DTK_C_API.h"

#include "Teuchos_UnitTestHarness.hpp"
#include "Teuchos_DefaultComm.hpp"

#include "mpi.h"

namespace {

TEUCHOS_UNIT_TEST( C_API, create_apply_delete_map )
{
  // get the raw mpi communicator
  Teuchos::RCP<const Teuchos::Comm<int>> teuchos_comm =
    Teuchos::DefaultComm<int>::getComm();
  MPI_Comm mpi_comm =
    *Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(
      teuchos_comm )->getRawMpiComm();
  int const comm_rank = teuchos_comm->getRank();
  int const comm_size = teuchos_comm->getSize();

  // set options using JSON format
  std::string const options = "{ "\
    "\"Map Type\": \"Moving Least Square Reconstruction\", "\
    "\"Basis Type\": \"Wendland\", "\
    "\"Basis Order\": 2, "\
    "\"RBF Radius\": 0.3 }";

  // TODO: fill these
  std::srand(123*comm_rank);
  double coord[3];
  int const space_dim = 3;
  int const field_dim = 2;
  unsigned const src_num = 3000;
  std::vector<double> src_coord(space_dim*src_num);
  std::vector<double> src_field(field_dim*src_num);
  for (unsigned i = 0; i < src_num; ++i)
  {
    coord[0] = (double) std::rand() / (double) RAND_MAX + comm_rank;
    coord[1] = (double) std::rand() / (double) RAND_MAX;
    coord[2] = (double) std::rand() / (double) RAND_MAX;
    // source coordinates data blocked
    src_coord[i+0*src_num] = coord[0];
    src_coord[i+1*src_num] = coord[1];
    src_coord[i+2*src_num] = coord[2];
    // source field data interleaved
    src_field[field_dim*i+0] = coord[0];
    src_field[field_dim*i+1] = coord[2];
  }
  unsigned const tgt_num = 50;
  std::vector<double> tgt_coord(space_dim*tgt_num);
  std::vector<double> tgt_field(field_dim*tgt_num);
  std::vector<double> gold_data(field_dim*tgt_num);
  for (unsigned i = 0; i < tgt_num; ++i)
  {
    coord[0] = (double) std::rand() / (double) RAND_MAX + comm_size - comm_rank - 1;
    coord[1] = (double) std::rand() / (double) RAND_MAX;
    coord[2] = (double) std::rand() / (double) RAND_MAX;
    // target coordinates data interleaved
    tgt_coord[space_dim*i+0] = coord[0];
    tgt_coord[space_dim*i+1] = coord[1];
    tgt_coord[space_dim*i+2] = coord[2];
    // target field data blocked
    gold_data[i+tgt_num*0] = coord[0];
    gold_data[i+tgt_num*1] = coord[2];
  }
  TEST_EQUALITY( src_coord.size(), space_dim * src_num );
  TEST_EQUALITY( tgt_coord.size(), space_dim * tgt_num );

  DTK_Map* dtk_map = DTK_Map_create( mpi_comm,
                                     src_coord.data(),
                                     src_num,
                                     DTK_BLOCKED,
                                     tgt_coord.data(),
                                     tgt_num,
                                     DTK_INTERLEAVED,
                                     space_dim,
                                     options.c_str() );

  DTK_Map_apply( dtk_map,
                 src_field.data(),
                 DTK_INTERLEAVED,
                 tgt_field.data(),
                 DTK_BLOCKED,
                 field_dim );

  DTK_Map_delete( dtk_map );

  double const rel_tol = 1e-8;
  double const abs_tol = 1e-6;
  for (unsigned i = 0; i < field_dim*tgt_num; ++i)
  {
    TEST_FLOATING_EQUALITY( gold_data[i], tgt_field[i], rel_tol );
    TEST_COMPARE( std::abs(gold_data[i] - tgt_field[i]), <, abs_tol );
  }
}

} // end namespace
<commit_msg>Add test for Node to Node map in C API<commit_after>#include "DTK_C_API.h"

#include "Teuchos_UnitTestHarness.hpp"
#include "Teuchos_DefaultComm.hpp"

#include "mpi.h"

namespace {

TEUCHOS_UNIT_TEST( C_API, create_apply_delete_map )
{
  // get the raw mpi communicator
  Teuchos::RCP<const Teuchos::Comm<int>> teuchos_comm =
    Teuchos::DefaultComm<int>::getComm();
  MPI_Comm mpi_comm =
    *Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(
      teuchos_comm )->getRawMpiComm();
  int const comm_rank = teuchos_comm->getRank();
  int const comm_size = teuchos_comm->getSize();

  // set options using JSON format
  std::string const options = "{ "\
    "\"Map Type\": \"Moving Least Square Reconstruction\", "\
    "\"Basis Type\": \"Wendland\", "\
    "\"Basis Order\": 2, "\
    "\"RBF Radius\": 0.3 }";

  // fill the source and taget vectors
  std::srand(123*comm_rank);
  double coord[3];
  int const space_dim = 3;
  int const field_dim = 2;
  unsigned const src_num = 3000;
  std::vector<double> src_coord(space_dim*src_num);
  std::vector<double> src_field(field_dim*src_num);
  for (unsigned i = 0; i < src_num; ++i)
  {
    coord[0] = (double) std::rand() / (double) RAND_MAX + comm_rank;
    coord[1] = (double) std::rand() / (double) RAND_MAX;
    coord[2] = (double) std::rand() / (double) RAND_MAX;
    // source coordinates data blocked
    src_coord[i+0*src_num] = coord[0];
    src_coord[i+1*src_num] = coord[1];
    src_coord[i+2*src_num] = coord[2];
    // source field data interleaved
    src_field[field_dim*i+0] = coord[0];
    src_field[field_dim*i+1] = coord[2];
  }
  unsigned const tgt_num = 50;
  std::vector<double> tgt_coord(space_dim*tgt_num);
  std::vector<double> tgt_field(field_dim*tgt_num);
  std::vector<double> gold_data(field_dim*tgt_num);
  for (unsigned i = 0; i < tgt_num; ++i)
  {
    coord[0] = (double) std::rand() / (double) RAND_MAX + comm_size - comm_rank - 1;
    coord[1] = (double) std::rand() / (double) RAND_MAX;
    coord[2] = (double) std::rand() / (double) RAND_MAX;
    // target coordinates data interleaved
    tgt_coord[space_dim*i+0] = coord[0];
    tgt_coord[space_dim*i+1] = coord[1];
    tgt_coord[space_dim*i+2] = coord[2];
    // target field data blocked
    gold_data[i+tgt_num*0] = coord[0];
    gold_data[i+tgt_num*1] = coord[2];
  }
  TEUCHOS_ASSERT( src_coord.size() == space_dim * src_num );
  TEUCHOS_ASSERT( tgt_coord.size() == space_dim * tgt_num );

  DTK_Map* dtk_map = DTK_Map_create( mpi_comm,
                                     src_coord.data(),
                                     src_num,
                                     DTK_BLOCKED,
                                     tgt_coord.data(),
                                     tgt_num,
                                     DTK_INTERLEAVED,
                                     space_dim,
                                     options.c_str() );

  DTK_Map_apply( dtk_map,
                 src_field.data(),
                 DTK_INTERLEAVED,
                 tgt_field.data(),
                 DTK_BLOCKED,
                 field_dim );

  DTK_Map_delete( dtk_map );

  // check the target against the gold values
  double const rel_tol = 1e-8;
  double const abs_tol = 1e-6;
  for (unsigned i = 0; i < field_dim*tgt_num; ++i)
  {
    TEST_FLOATING_EQUALITY( gold_data[i], tgt_field[i], rel_tol );
    TEST_COMPARE( std::abs(gold_data[i] - tgt_field[i]), <, abs_tol );
  }
}

TEUCHOS_UNIT_TEST( C_API, node_to_node_map )
{
  // get the raw mpi communicator
  Teuchos::RCP<const Teuchos::Comm<int>> teuchos_comm =
    Teuchos::DefaultComm<int>::getComm();
  MPI_Comm mpi_comm =
    *Teuchos::rcp_dynamic_cast<const Teuchos::MpiComm<int>>(
      teuchos_comm )->getRawMpiComm();
  int const comm_rank = teuchos_comm->getRank();
  int const comm_size = teuchos_comm->getSize();

  // fill the source and taget vectors
  int const space_dim = 2;
  int const field_dim = 3;
  double coord[2];
  unsigned const src_num = 4;
  std::vector<double> src_coord(space_dim*src_num);
  std::vector<double> src_field(field_dim*src_num);
  for (unsigned int i = 0; i < src_num; ++i)
  {
    coord[0] = (double) i / (double) src_num + comm_size - comm_rank - 1;
    coord[1] = (double) i / (double) src_num;
    // source coordinates interleaved
    src_coord[space_dim*i+0] = coord[0];
    src_coord[space_dim*i+1] = coord[1];
    // source field interleaved
    src_field[field_dim*i+0] = coord[0] * coord[0];
    src_field[field_dim*i+1] = coord[0] * coord[1];
    src_field[field_dim*i+2] = coord[1] * coord[1];
  }
  unsigned const tgt_num = src_num / 2;
  TEUCHOS_ASSERT( src_num % 2 == 0);
  std::vector<double> tgt_coord(space_dim*tgt_num);
  std::vector<double> tgt_field(field_dim*tgt_num);
  std::vector<double> gold_data(field_dim*tgt_num);
  for (unsigned int i = 0; i < tgt_num; ++i)
  {
    coord[0] = (double) i / (double) tgt_num + comm_rank;
    coord[1] = (double) i / (double) tgt_num;
    // target coordinates blocked
    tgt_coord[i+tgt_num*0] = coord[0];
    tgt_coord[i+tgt_num*1] = coord[1];
    // target field blocked
    gold_data[i+tgt_num*0] = coord[0] * coord[0];
    gold_data[i+tgt_num*1] = coord[0] * coord[1];
    gold_data[i+tgt_num*2] = coord[1] * coord[1];
  }

  // set options using JSON format
  std::string const options = "{ "\
    "\"Map Type\": \"Node To Node\" }";

  DTK_Map* dtk_map = DTK_Map_create( mpi_comm,
                                     src_coord.data(),
                                     src_num,
                                     DTK_INTERLEAVED,
                                     tgt_coord.data(),
                                     tgt_num,
                                     DTK_BLOCKED,
                                     space_dim,
                                     options.c_str() );

  DTK_Map_apply( dtk_map,
                 src_field.data(),
                 DTK_INTERLEAVED,
                 tgt_field.data(),
                 DTK_BLOCKED,
                 field_dim );

  DTK_Map_delete( dtk_map );

  // check the target angainst gold values
  for (unsigned i = 0; i < field_dim*tgt_num; ++i)
  {
    TEST_EQUALITY( gold_data[i], tgt_field[i] );
  }
}

} // end namespace
<|endoftext|>


<commit_before>#include "mediadatabase.h"
#include <QDebug>
#include <QSqlError>
#include <QSqlResult>
#include <QFile>

mediaDatabase::mediaDatabase(QObject *parent) :
    QObject(parent),
    _db(QSqlDatabase::addDatabase("QMYSQL")),
    _query(new QSqlQuery(_db))
{
    _db.setPort(3307);
    _db.setHostName("127.0.0.1");
    _db.setUserName("root");
    _db.setPassword("rootpass");

    bool ok = _db.open();

    if(ok)
    {
        qDebug() << "Database opened!";
        bool schemaExists = false;

//        Media_Player

        if(!_query->exec("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'Media_Player';"))
            qDebug() << _query->lastError().text();
        else
        {
            while(_query->next())
                schemaExists = _query->value(0).toInt();

            if(!schemaExists)
            {
                QFile::copy(":/resources/schema.sql","schema.sql");
                QFile * schemaFile = new QFile("schema.sql");
                schemaFile->open(QFile::ReadOnly);
                if(!_query->exec(schemaFile->readAll().toStdString().c_str()))
                    qDebug() << "Could not initiate schema!";
                else qDebug() << "Created schema.";
                schemaFile->close();
            }
        }

        _db.close();
    }
    else
    {
        qDebug() << "Could not open database!";
        qDebug() << "Error:" << _db.lastError().text();
    }
}

mediaDatabase::~mediaDatabase()
{

}

<commit_msg>Removed function setting port for MySQL server.<commit_after>#include "mediadatabase.h"
#include <QDebug>
#include <QSqlError>
#include <QSqlResult>
#include <QFile>

mediaDatabase::mediaDatabase(QObject *parent) :
    QObject(parent),
    _db(QSqlDatabase::addDatabase("QMYSQL")),
    _query(new QSqlQuery(_db))
{
    _db.setHostName("127.0.0.1");
    _db.setUserName("root");
    _db.setPassword("rootpass");

    bool ok = _db.open();

    if(ok)
    {
        qDebug() << "Database opened!";
        bool schemaExists = false;

//        Media_Player

        if(!_query->exec("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'Media_Player';"))
            qDebug() << _query->lastError().text();
        else
        {
            while(_query->next())
                schemaExists = _query->value(0).toInt();

            if(!schemaExists)
            {
                QFile::copy(":/resources/schema.sql","schema.sql");
                QFile * schemaFile = new QFile("schema.sql");
                schemaFile->open(QFile::ReadOnly);
                if(!_query->exec(schemaFile->readAll().toStdString().c_str()))
                    qDebug() << "Could not initiate schema!";
                else qDebug() << "Created schema.";
                schemaFile->close();
            }
        }

        _db.close();
    }
    else
    {
        qDebug() << "Could not open database!";
        qDebug() << "Error:" << _db.lastError().text();
    }
}

mediaDatabase::~mediaDatabase()
{

}

<|endoftext|>