<commit_before>#include "parlex/detail/job.hpp"

// ReSharper disable once CppUnusedIncludeDirective
#include "perf_timer.hpp"
#include "tarjan.hpp"

#include "parlex/detail/acceptor.hpp"
#include "parlex/detail/configuration.hpp"
#include "parlex/detail/grammar.hpp"
#include "parlex/detail/match_class.hpp"
#include "parlex/detail/parser.hpp"
#include "parlex/detail/producer_table.hpp"
#include "parlex/detail/subjob.hpp"
#include "parlex/detail/terminal.hpp"
#include "parlex/detail/token.hpp"

//#include "logging.hpp"

namespace parlex {
namespace detail {

job::job(parser & owner, std::u32string const & document, grammar const & g, uint16_t const rootRecognizerIndex, progress_handler_t const & progressHandler) :
	document(document),
	g(g),
	progress(0),
	owner(&owner),
	progress_handler(progressHandler),
	progress_counter(0) {
	//DBG("starting job using recognizer '", main, "'");

	//similar to get_product, but different for constructor
	//because parser::mutex is already locked
	match_class const matchClass(0, rootRecognizerIndex);
	auto & storage = producers[matchClass];
	auto const & root = g.get_recognizer(rootRecognizerIndex);
	if (root.is_terminal()) {
		auto const t = static_cast<terminal const *>(&root);  // NOLINT
		storage = new token(*this, matchClass, *t);
	} else {
		auto const machine = static_cast<acceptor const *>(&root);  // NOLINT
		auto result = new subjob(*machine);
		storage = result;
		//seed the parser with the root state
		result->begin_work_queue_reference();
		configuration const c = result->construct_start_state_configuration(0);
		uint8_t startState = machine->get_start_state();
		owner.work.emplace_back(matchClass, c);
		result->finish_creation(*this, matchClass);
		++owner.active_count;
		// start when parser::mutex is unlocked
		owner.work_cv.notify_one();
	}
}

void job::connect(match_class const & requestedMatchClass, subjob & subscriber, match_class const & subscriberId, uint8_t const nextState, leaf const * l, transition_record const * history) {
	get_producer(requestedMatchClass).add_subscription(nextState, l, history, subscriber, subscriberId, requestedMatchClass, *this);
}

producer & job::get_producer(match_class const & matchClass) {
	std::unique_lock<std::mutex> lock(producers_mutex);
	auto & storage = producers[matchClass];
	if (storage == nullptr) {
		auto const & r = g.get_recognizer(matchClass.recognizer_index);
		if (r.is_terminal()) {
			auto const & t = *static_cast<terminal const *>(&r);  // NOLINT
			storage = new token(*this, matchClass, t);
		} else {
			auto const machine = static_cast<acceptor const *>(&r);  // NOLINT
			auto newSubjobPtr = new subjob(*machine);
			storage = newSubjobPtr;
			lock.unlock();
			newSubjobPtr->start(*this, matchClass);
		}
	}
	return *storage;
}

void job::update_progress(uint32_t const completed)
{
	if (progress_handler) {
		uint32_t oldProgress = progress.load();
		while (!progress_counter.compare_exchange_weak(oldProgress, completed) && oldProgress < completed) {}
		if (oldProgress < completed) {
			progress_handler(completed, uint32_t(document.length()));
		}
	}
}

void job::fast_breakout() {
	for (auto & pair : producers) {
		auto const & matchClass = pair.first;
		auto & producer = *pair.second;
		if (g.is_recognizer_left_recursive(matchClass.recognizer_index)) {
			producer.terminate(*this, matchClass);
		}
	}
}

bool job::full_breakout() {
	std::vector<match_class> vertices;
	std::map<match_class, size_t> lookup;
	for (auto const & pair : producers) {
		auto const & matchClass = pair.first;
		auto const & producer = *pair.second;
		if (producer.completed) {
			continue;
		}
		lookup[matchClass] = vertices.size();
		vertices.push_back(matchClass);
	}

	std::function<std::vector<size_t> (size_t)> const edgeFunctor = [&](size_t vertexIndex){
		auto const & matchClass = vertices[vertexIndex];
		auto const & producer = producers.find(matchClass)->second;
		std::vector<size_t> results;
		for (auto const & subscription : producer->consumers) {
			if (get_producer(subscription.subscriber_id).completed) {
				continue;
			}
			results.push_back(lookup.find(subscription.subscriber_id)->second);
		}
		return results;
	};

	auto stronglyConnectedComponents = tarjan(vertices.size(), edgeFunctor, true);

	auto anyHalted = false;
	//halt subjobs that are subscribed to themselves (in)directly
	for (auto const & stronglyConnectedComponent : stronglyConnectedComponents) {
		for (auto vertexIndex: stronglyConnectedComponent) {
			auto const & matchClass = vertices[vertexIndex];
			get_producer(matchClass).terminate(*this, matchClass);
			anyHalted = true;
		}
	}

	return !anyHalted;
}

bool job::handle_deadlocks() {
	//perf_timer perf(__func__);

	fast_breakout();

	// Did fast_breakout free up any nodes to do some work?
	if (!owner->work.empty()) {
		return false;
	}

	return full_breakout();
}

//Construct an ASS, and if a solution was found, prunes unreachable nodes
abstract_syntax_semilattice job::construct_result(match const & m) {
	//perf_timer timer(__FUNCTION__);
	auto result = abstract_syntax_semilattice(m);
	for (auto const & pair : producers) {
		auto const & matchClass = pair.first;
		auto const & p = *pair.second;
		for (auto const & pair2 : p.match_length_to_derivations) {
			auto const matchLength = pair2.first;
			match const n(matchClass, matchLength);
			auto const & derivations = pair2.second;
			result.derivations_of_matches[n] = derivations;
		}
	}

	for (auto entry : producers) {
		delete entry.second;
	}
	producers.clear();

	if (result.is_rooted()) {
		result.prune_detached();
		parser::apply_precedence_and_associativity(g, result);
		result.prune_detached();
	}
	return result;
}

abstract_syntax_semilattice job::construct_result_and_postprocess(uint16_t const overrideRootRecognizerIndex, std::vector<post_processor> const & posts, std::u32string const & document) {
	//perf_timer perf(__func__);
	auto result = construct_result(match(0, overrideRootRecognizerIndex, uint32_t(document.size())));
	if (!posts.empty()) {
		for (auto const & post : posts) {
			post(result);
		}
		if (result.is_rooted()) {
			result.prune_detached();
		}
	}
	return result;
}

}
}
<commit_msg>Make parlex::job handle deadlocks differently.<commit_after>#include "parlex/detail/job.hpp"

// ReSharper disable once CppUnusedIncludeDirective
#include "perf_timer.hpp"
#include "tarjan.hpp"

#include "parlex/detail/acceptor.hpp"
#include "parlex/detail/configuration.hpp"
#include "parlex/detail/grammar.hpp"
#include "parlex/detail/match_class.hpp"
#include "parlex/detail/parser.hpp"
#include "parlex/detail/producer_table.hpp"
#include "parlex/detail/subjob.hpp"
#include "parlex/detail/terminal.hpp"
#include "parlex/detail/token.hpp"

//#include "logging.hpp"

namespace parlex {
namespace detail {

job::job(parser & owner, std::u32string const & document, grammar const & g, uint16_t const rootRecognizerIndex, progress_handler_t const & progressHandler) :
	document(document),
	g(g),
	progress(0),
	owner(&owner),
	progress_handler(progressHandler),
	progress_counter(0) {
	//DBG("starting job using recognizer '", main, "'");

	//similar to get_product, but different for constructor
	//because parser::mutex is already locked
	match_class const matchClass(0, rootRecognizerIndex);
	auto & storage = producers[matchClass];
	auto const & root = g.get_recognizer(rootRecognizerIndex);
	if (root.is_terminal()) {
		auto const t = static_cast<terminal const *>(&root);  // NOLINT
		storage = new token(*this, matchClass, *t);
	} else {
		auto const machine = static_cast<acceptor const *>(&root);  // NOLINT
		auto result = new subjob(*machine);
		storage = result;
		//seed the parser with the root state
		result->begin_work_queue_reference();
		configuration const c = result->construct_start_state_configuration(0);
		uint8_t startState = machine->get_start_state();
		owner.work.emplace_back(matchClass, c);
		result->finish_creation(*this, matchClass);
		++owner.active_count;
		// start when parser::mutex is unlocked
		owner.work_cv.notify_one();
	}
}

void job::connect(match_class const & requestedMatchClass, subjob & subscriber, match_class const & subscriberId, uint8_t const nextState, leaf const * l, transition_record const * history) {
	get_producer(requestedMatchClass).add_subscription(nextState, l, history, subscriber, subscriberId, requestedMatchClass, *this);
}

producer & job::get_producer(match_class const & matchClass) {
	std::unique_lock<std::mutex> lock(producers_mutex);
	auto & storage = producers[matchClass];
	if (storage == nullptr) {
		auto const & r = g.get_recognizer(matchClass.recognizer_index);
		if (r.is_terminal()) {
			auto const & t = *static_cast<terminal const *>(&r);  // NOLINT
			storage = new token(*this, matchClass, t);
		} else {
			auto const machine = static_cast<acceptor const *>(&r);  // NOLINT
			auto newSubjobPtr = new subjob(*machine);
			storage = newSubjobPtr;
			lock.unlock();
			newSubjobPtr->start(*this, matchClass);
		}
	}
	return *storage;
}

void job::update_progress(uint32_t const completed)
{
	if (progress_handler) {
		uint32_t oldProgress = progress.load();
		while (!progress_counter.compare_exchange_weak(oldProgress, completed) && oldProgress < completed) {}
		if (oldProgress < completed) {
			progress_handler(completed, uint32_t(document.length()));
		}
	}
}

//void job::fast_breakout() {
//	for (auto & pair : producers) {
//		auto const & matchClass = pair.first;
//		auto & producer = *pair.second;
//		if (g.is_recognizer_left_recursive(matchClass.recognizer_index)) {
//			producer.terminate(*this, matchClass);
//		}
//	}
//}

bool job::full_breakout() {
	std::vector<match_class> vertices;
	std::map<match_class, size_t> lookup;
	for (auto const & pair : producers) {
		auto const & matchClass = pair.first;
		auto const & producer = *pair.second;
		if (producer.completed) {
			continue;
		}
		lookup[matchClass] = vertices.size();
		vertices.push_back(matchClass);
	}

	std::function<std::vector<size_t> (size_t)> const edgeFunctor = [&](size_t vertexIndex){
		auto const & matchClass = vertices[vertexIndex];
		auto const & producer = producers.find(matchClass)->second;
		std::vector<size_t> results;
		for (auto const & subscription : producer->consumers) {
			if (get_producer(subscription.subscriber_id).completed) {
				continue;
			}
			results.push_back(lookup.find(subscription.subscriber_id)->second);
		}
		return results;
	};

	auto stronglyConnectedComponents = tarjan(vertices.size(), edgeFunctor, true);

	auto anyHalted = false;
	//halt the subjobs furthest down the hierarchy that are subscribed to themselves (in)directly
	for (auto i = stronglyConnectedComponents.rbegin(); i != stronglyConnectedComponents.rend(); ++i) {
		std::vector<std::vector<size_t>>::value_type const & stronglyConnectedComponent = *i;
		for (auto vertexIndex: stronglyConnectedComponent) {
			auto const & matchClass = vertices[vertexIndex];
			get_producer(matchClass).terminate(*this, matchClass);
			anyHalted = true;
		}
		if (!owner->work.empty()) {
			break;
		}
	}

	return !anyHalted;
}

bool job::handle_deadlocks() {
	//perf_timer perf(__func__);

	//fast_breakout();

	// Did fast_breakout free up any nodes to do some work?
	if (!owner->work.empty()) {
		return false;
	}

	return full_breakout();
}

//Construct an ASS, and if a solution was found, prunes unreachable nodes
abstract_syntax_semilattice job::construct_result(match const & m) {
	//perf_timer timer(__FUNCTION__);
	auto result = abstract_syntax_semilattice(m);
	for (auto const & pair : producers) {
		auto const & matchClass = pair.first;
		auto const & p = *pair.second;
		for (auto const & pair2 : p.match_length_to_derivations) {
			auto const matchLength = pair2.first;
			match const n(matchClass, matchLength);
			auto const & derivations = pair2.second;
			result.derivations_of_matches[n] = derivations;
		}
	}

	for (auto entry : producers) {
		delete entry.second;
	}
	producers.clear();

	if (result.is_rooted()) {
		result.prune_detached();
		parser::apply_precedence_and_associativity(g, result);
		result.prune_detached();
	}
	return result;
}

abstract_syntax_semilattice job::construct_result_and_postprocess(uint16_t const overrideRootRecognizerIndex, std::vector<post_processor> const & posts, std::u32string const & document) {
	//perf_timer perf(__func__);
	auto result = construct_result(match(0, overrideRootRecognizerIndex, uint32_t(document.size())));
	if (!posts.empty()) {
		for (auto const & post : posts) {
			post(result);
		}
		if (result.is_rooted()) {
			result.prune_detached();
		}
	}
	return result;
}

}
}
<|endoftext|>


<commit_before>//! @Yue Wang
//!
//! ex12.13 What happens if we excute the following code?
//!
//  generate a runtime error : double free
//!

#include <iostream>
#include <memory>

int main()
{
    {
        auto sp = std::make_shared<int>();
        auto p = sp.get();
        delete p;
    }

    return 0;
}
<commit_msg>Update ex12_13.cpp<commit_after>//!
//! ex12.13 What happens if we execute the following code?
//!
//! generate a runtime error : double free
//!

#include <iostream>
#include <memory>

int main()
{
    {
        auto sp = make_shared<int>();
        auto p = sp.get();
        delete p;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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 "net/base/host_resolver.h"

#if defined(OS_WIN)
#include <ws2tcpip.h>
#include <wspiapi.h>  // Needed for Win2k compat.
#elif defined(OS_POSIX)
#include <netdb.h>
#include <sys/socket.h>
#endif
#if defined(OS_LINUX)
#include <resolv.h>
#endif

#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/worker_pool.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"

#if defined(OS_WIN)
#include "net/base/winsock_init.h"
#endif

namespace net {

//-----------------------------------------------------------------------------

static HostMapper* host_mapper;

std::string HostMapper::MapUsingPrevious(const std::string& host) {
  return previous_mapper_.get() ? previous_mapper_->Map(host) : host;
}

HostMapper* SetHostMapper(HostMapper* value) {
  std::swap(host_mapper, value);
  return value;
}

static int HostResolverProc(
    const std::string& host, const std::string& port, struct addrinfo** out) {
  struct addrinfo hints = {0};
  hints.ai_family = AF_UNSPEC;

#if defined(OS_WIN)
  // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
  //
  // The following comment in <winsock2.h> is the best documentation I found
  // on AI_ADDRCONFIG for Windows:
  //   Flags used in "hints" argument to getaddrinfo()
  //       - AI_ADDRCONFIG is supported starting with Vista
  //       - default is AI_ADDRCONFIG ON whether the flag is set or not
  //         because the performance penalty in not having ADDRCONFIG in
  //         the multi-protocol stack environment is severe;
  //         this defaulting may be disabled by specifying the AI_ALL flag,
  //         in that case AI_ADDRCONFIG must be EXPLICITLY specified to
  //         enable ADDRCONFIG behavior
  //
  // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful.  If the
  // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
  // to fail with WSANO_DATA (11004) for "localhost", probably because of the
  // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
  //   The IPv4 or IPv6 loopback address is not considered a valid global
  //   address.
  // See http://crbug.com/5234.
  hints.ai_flags = 0;
#else
  hints.ai_flags = AI_ADDRCONFIG;
#endif

  // Restrict result set to only this socket type to avoid duplicates.
  hints.ai_socktype = SOCK_STREAM;

  int err = getaddrinfo(host.c_str(), port.c_str(), &hints, out);
#if defined(OS_LINUX)
  // If we fail, re-initialise the resolver just in case there have been any
  // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
  if (err && !res_init())
    err = getaddrinfo(host.c_str(), port.c_str(), &hints, out);
#endif

  return err ? ERR_NAME_NOT_RESOLVED : OK;
}

static int ResolveAddrInfo(HostMapper* mapper, const std::string& host,
                           const std::string& port, struct addrinfo** out) {
  if (mapper) {
    std::string mapped_host = mapper->Map(host);

    if (mapped_host.empty())
      return ERR_NAME_NOT_RESOLVED;

    return HostResolverProc(mapped_host, port, out);
  } else {
    return HostResolverProc(host, port, out);
  }
}

//-----------------------------------------------------------------------------

class HostResolver::Request :
    public base::RefCountedThreadSafe<HostResolver::Request> {
 public:
  Request(HostResolver* resolver,
          const std::string& host,
          const std::string& port,
          AddressList* addresses,
          CompletionCallback* callback)
      : host_(host),
        port_(port),
        resolver_(resolver),
        addresses_(addresses),
        callback_(callback),
        origin_loop_(MessageLoop::current()),
        host_mapper_(host_mapper),
        error_(OK),
        results_(NULL) {
  }

  ~Request() {
    if (results_)
      freeaddrinfo(results_);
  }

  void DoLookup() {
    // Running on the worker thread
    error_ = ResolveAddrInfo(host_mapper_, host_, port_, &results_);

    Task* reply = NewRunnableMethod(this, &Request::DoCallback);

    // The origin loop could go away while we are trying to post to it, so we
    // need to call its PostTask method inside a lock.  See ~HostResolver.
    {
      AutoLock locked(origin_loop_lock_);
      if (origin_loop_) {
        origin_loop_->PostTask(FROM_HERE, reply);
        reply = NULL;
      }
    }

    // Does nothing if it got posted.
    delete reply;
  }

  void DoCallback() {
    // Running on the origin thread.
    DCHECK(error_ || results_);

    // We may have been cancelled!
    if (!resolver_)
      return;

    if (!error_) {
      addresses_->Adopt(results_);
      results_ = NULL;
    }

    // Drop the resolver's reference to us.  Do this before running the
    // callback since the callback might result in the resolver being
    // destroyed.
    resolver_->request_ = NULL;

    callback_->Run(error_);
  }

  void Cancel() {
    resolver_ = NULL;

    AutoLock locked(origin_loop_lock_);
    origin_loop_ = NULL;
  }

 private:
  // Set on the origin thread, read on the worker thread.
  std::string host_;
  std::string port_;

  // Only used on the origin thread (where Resolve was called).
  HostResolver* resolver_;
  AddressList* addresses_;
  CompletionCallback* callback_;

  // Used to post ourselves onto the origin thread.
  Lock origin_loop_lock_;
  MessageLoop* origin_loop_;

  // Hold an owning reference to the host mapper that we are going to use.
  // This may not be the current host mapper by the time we call
  // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
  // reference ensures that it remains valid until we are done.
  scoped_refptr<HostMapper> host_mapper_;

  // Assigned on the worker thread, read on the origin thread.
  int error_;
  struct addrinfo* results_;
};

//-----------------------------------------------------------------------------

HostResolver::HostResolver() {
#if defined(OS_WIN)
  EnsureWinsockInit();
#endif
}

HostResolver::~HostResolver() {
  if (request_)
    request_->Cancel();
}

int HostResolver::Resolve(const std::string& hostname, int port,
                          AddressList* addresses,
                          CompletionCallback* callback) {
  DCHECK(!request_) << "resolver already in use";

  const std::string& port_str = IntToString(port);

  // Do a synchronous resolution.
  if (!callback) {
    struct addrinfo* results;
    int rv = ResolveAddrInfo(host_mapper, hostname, port_str, &results);
    if (rv == OK)
      addresses->Adopt(results);
    return rv;
  }

  request_ = new Request(this, hostname, port_str, addresses, callback);

  // Dispatch to worker thread...
  if (!WorkerPool::PostTask(FROM_HERE,
          NewRunnableMethod(request_.get(), &Request::DoLookup), true)) {
    NOTREACHED();
    request_ = NULL;
    return ERR_FAILED;
  }

  return ERR_IO_PENDING;
}

}  // namespace net
<commit_msg>Use res_ninit for thread safety and a timer for reloading resolv.conf on Linux.<commit_after>// Copyright (c) 2006-2008 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 "net/base/host_resolver.h"

#if defined(OS_WIN)
#include <ws2tcpip.h>
#include <wspiapi.h>  // Needed for Win2k compat.
#elif defined(OS_POSIX)
#include <netdb.h>
#include <sys/socket.h>
#endif
#if defined(OS_LINUX)
#include <resolv.h>
#endif

#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/worker_pool.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"

#if defined(OS_LINUX)
#include "base/singleton.h"
#include "base/thread_local_storage.h"
#include "base/time.h"
#endif

#if defined(OS_WIN)
#include "net/base/winsock_init.h"
#endif

namespace net {

//-----------------------------------------------------------------------------

static HostMapper* host_mapper;

std::string HostMapper::MapUsingPrevious(const std::string& host) {
  return previous_mapper_.get() ? previous_mapper_->Map(host) : host;
}

HostMapper* SetHostMapper(HostMapper* value) {
  std::swap(host_mapper, value);
  return value;
}

#if defined(OS_LINUX)
// On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in
// DNS queries failing either because nameservers are unknown on startup
// or because nameserver info has changed as a result of e.g. connecting to
// a new network. Some distributions patch glibc to stat /etc/resolv.conf
// to try to automatically detect such changes but these patches are not
// universal and even patched systems such as Jaunty appear to need calls
// to res_ninit to reload the nameserver information in different threads.
//
// We adopt the Mozilla solution here which is to call res_ninit when
// lookups fail and to rate limit the reloading to once per second per
// thread.

// Keep a timer per calling thread to rate limit the calling of res_ninit.
class DnsReloadTimer {
 public:
  DnsReloadTimer() {
    tls_index_.Initialize(SlotReturnFunction);
  }

  ~DnsReloadTimer() { }

  // Check if the timer for the calling thread has expired. When no
  // timer exists for the calling thread, create one.
  bool Expired() {
    const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
    base::TimeTicks now = base::TimeTicks::Now();
    base::TimeTicks* timer_ptr =
      static_cast<base::TimeTicks*>(tls_index_.Get());

    if (!timer_ptr) {
      timer_ptr = new base::TimeTicks();
      *timer_ptr = base::TimeTicks::Now();
      tls_index_.Set(timer_ptr);
      // Return true to reload dns info on the first call for each thread.
      return true;
    } else if (now - *timer_ptr > kRetryTime) {
      *timer_ptr = now;
      return true;
    } else {
      return false;
    }
  }

  // Free the allocated timer.
  static void SlotReturnFunction(void* data) {
    base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
    delete tls_data;
  }

 private:
  // We use thread local storage to identify which base::TimeTicks to
  // interact with.
  static ThreadLocalStorage::Slot tls_index_ ;

  DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
};

// A TLS slot to the TimeTicks for the current thread.
// static
ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);

#endif  // defined(OS_LINUX)

static int HostResolverProc(
    const std::string& host, const std::string& port, struct addrinfo** out) {
  struct addrinfo hints = {0};
  hints.ai_family = AF_UNSPEC;

#if defined(OS_WIN)
  // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
  //
  // The following comment in <winsock2.h> is the best documentation I found
  // on AI_ADDRCONFIG for Windows:
  //   Flags used in "hints" argument to getaddrinfo()
  //       - AI_ADDRCONFIG is supported starting with Vista
  //       - default is AI_ADDRCONFIG ON whether the flag is set or not
  //         because the performance penalty in not having ADDRCONFIG in
  //         the multi-protocol stack environment is severe;
  //         this defaulting may be disabled by specifying the AI_ALL flag,
  //         in that case AI_ADDRCONFIG must be EXPLICITLY specified to
  //         enable ADDRCONFIG behavior
  //
  // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful.  If the
  // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
  // to fail with WSANO_DATA (11004) for "localhost", probably because of the
  // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
  //   The IPv4 or IPv6 loopback address is not considered a valid global
  //   address.
  // See http://crbug.com/5234.
  hints.ai_flags = 0;
#else
  hints.ai_flags = AI_ADDRCONFIG;
#endif

  // Restrict result set to only this socket type to avoid duplicates.
  hints.ai_socktype = SOCK_STREAM;

  int err = getaddrinfo(host.c_str(), port.c_str(), &hints, out);
#if defined(OS_LINUX)
  net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
  // If we fail, re-initialise the resolver just in case there have been any
  // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
  if (err && dns_timer->Expired() && !res_ninit(&_res))
    err = getaddrinfo(host.c_str(), port.c_str(), &hints, out);
#endif

  return err ? ERR_NAME_NOT_RESOLVED : OK;
}

static int ResolveAddrInfo(HostMapper* mapper, const std::string& host,
                           const std::string& port, struct addrinfo** out) {
  if (mapper) {
    std::string mapped_host = mapper->Map(host);

    if (mapped_host.empty())
      return ERR_NAME_NOT_RESOLVED;

    return HostResolverProc(mapped_host, port, out);
  } else {
    return HostResolverProc(host, port, out);
  }
}

//-----------------------------------------------------------------------------

class HostResolver::Request :
    public base::RefCountedThreadSafe<HostResolver::Request> {
 public:
  Request(HostResolver* resolver,
          const std::string& host,
          const std::string& port,
          AddressList* addresses,
          CompletionCallback* callback)
      : host_(host),
        port_(port),
        resolver_(resolver),
        addresses_(addresses),
        callback_(callback),
        origin_loop_(MessageLoop::current()),
        host_mapper_(host_mapper),
        error_(OK),
        results_(NULL) {
  }

  ~Request() {
    if (results_)
      freeaddrinfo(results_);
  }

  void DoLookup() {
    // Running on the worker thread
    error_ = ResolveAddrInfo(host_mapper_, host_, port_, &results_);

    Task* reply = NewRunnableMethod(this, &Request::DoCallback);

    // The origin loop could go away while we are trying to post to it, so we
    // need to call its PostTask method inside a lock.  See ~HostResolver.
    {
      AutoLock locked(origin_loop_lock_);
      if (origin_loop_) {
        origin_loop_->PostTask(FROM_HERE, reply);
        reply = NULL;
      }
    }

    // Does nothing if it got posted.
    delete reply;
  }

  void DoCallback() {
    // Running on the origin thread.
    DCHECK(error_ || results_);

    // We may have been cancelled!
    if (!resolver_)
      return;

    if (!error_) {
      addresses_->Adopt(results_);
      results_ = NULL;
    }

    // Drop the resolver's reference to us.  Do this before running the
    // callback since the callback might result in the resolver being
    // destroyed.
    resolver_->request_ = NULL;

    callback_->Run(error_);
  }

  void Cancel() {
    resolver_ = NULL;

    AutoLock locked(origin_loop_lock_);
    origin_loop_ = NULL;
  }

 private:
  // Set on the origin thread, read on the worker thread.
  std::string host_;
  std::string port_;

  // Only used on the origin thread (where Resolve was called).
  HostResolver* resolver_;
  AddressList* addresses_;
  CompletionCallback* callback_;

  // Used to post ourselves onto the origin thread.
  Lock origin_loop_lock_;
  MessageLoop* origin_loop_;

  // Hold an owning reference to the host mapper that we are going to use.
  // This may not be the current host mapper by the time we call
  // ResolveAddrInfo, but that's OK... we'll use it anyways, and the owning
  // reference ensures that it remains valid until we are done.
  scoped_refptr<HostMapper> host_mapper_;

  // Assigned on the worker thread, read on the origin thread.
  int error_;
  struct addrinfo* results_;
};

//-----------------------------------------------------------------------------

HostResolver::HostResolver() {
#if defined(OS_WIN)
  EnsureWinsockInit();
#endif
}

HostResolver::~HostResolver() {
  if (request_)
    request_->Cancel();
}

int HostResolver::Resolve(const std::string& hostname, int port,
                          AddressList* addresses,
                          CompletionCallback* callback) {
  DCHECK(!request_) << "resolver already in use";

  const std::string& port_str = IntToString(port);

  // Do a synchronous resolution.
  if (!callback) {
    struct addrinfo* results;
    int rv = ResolveAddrInfo(host_mapper, hostname, port_str, &results);
    if (rv == OK)
      addresses->Adopt(results);
    return rv;
  }

  request_ = new Request(this, hostname, port_str, addresses, callback);

  // Dispatch to worker thread...
  if (!WorkerPool::PostTask(FROM_HERE,
          NewRunnableMethod(request_.get(), &Request::DoLookup), true)) {
    NOTREACHED();
    request_ = NULL;
    return ERR_FAILED;
  }

  return ERR_IO_PENDING;
}

}  // namespace net
<|endoftext|>


<commit_before>/*
 * CogServerSCM.cc
 *
 * Copyright (C) 2015 OpenCog Foundation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

// The header file bits.

#ifndef _OPENCOG_COGSERVER_SCM_H
#define _OPENCOG_COGSERVER_SCM_H

#include <thread>

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/server/CogServer.h>

namespace opencog
{

class CogServerSCM
{
private:
    static void* init_in_guile(void*);
    static void init_in_module(void*);
    void init(void);

    void start_server(const std::string&);
    void stop_server(void);

    CogServer* srvr = NULL;
    std::thread * main_loop = NULL;

public:
    CogServerSCM();
};

extern "C" {
void opencog_cogserver_init(void);
};

}
#endif // _OPENCOG_COGSERVER_SCM_H

// --------------------------------------------------------------

#include <opencog/util/Config.h>
#include <opencog/guile/SchemePrimitive.h>

/**
 * Implement a dynamically-loadable cogserver guile module.
 * This is mostly to allow a networked, agent-based system to run.
 *
 * This is a bare-bones implementation. Things like the server
 * port number, and maybe even the server atomspace, should be
 * configurable from guile, instead of the conf file.
 *
 * If/when python agents are supplanted by something newer, then
 * maybe this goes away.
 */

using namespace opencog;

CogServerSCM::CogServerSCM()
{
    static bool is_init = false;
    if (is_init) return;
    is_init = true;
    scm_with_guile(init_in_guile, this);
}

void* CogServerSCM::init_in_guile(void* self)
{
    scm_c_define_module("opencog cogserver", init_in_module, self);
    scm_c_use_module("opencog cogserver");
    return NULL;
}

void CogServerSCM::init_in_module(void* data)
{
    CogServerSCM* self = (CogServerSCM*) data;
    self->init();
}

/**
 * The main init function for the CogServerSCM object.
 */
void CogServerSCM::init()
{
    define_scheme_primitive("c-start-cogserver", &CogServerSCM::start_server, this, "cogserver");
}

extern "C" {
void opencog_cogserver_init(void)
{
    static CogServerSCM cogserver;
}
};

// --------------------------------------------------------------

void CogServerSCM::start_server(const std::string& cfg)
{
    // singleton instance
    if (srvr) return;

    // The default config file is installed from
    // $SRCDIR/lib/cogserver.conf and is copied to
    // /usr/local/etc/cogservedr.conf
    // by default. Use it if we can; it has sane file paths in it.
    if (0 < cfg.size())
        config().load(cfg.c_str(), true);
    else
        config().load("cogserver.conf", true);

    srvr = &cogserver();

    // Open database *before* loading modules, since the modules
    // might create atoms, and we can't have that happen until
    // storage is open, as otherwise, there will be handle conflicts.
    srvr->openDatabase();

    // Load modules specified in config
    srvr->loadModules();
    srvr->loadSCMModules();

    // Enable the network server and run the server's main loop
    srvr->enableNetworkServer();
    main_loop = new std::thread(&CogServer::serverLoop, srvr);
}

void CogServerSCM::stop_server(void)
{
}
<commit_msg>Add a server shutdown.<commit_after>/*
 * CogServerSCM.cc
 *
 * Copyright (C) 2015 OpenCog Foundation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the
 * exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * 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 Affero General Public
 * License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

// The header file bits.

#ifndef _OPENCOG_COGSERVER_SCM_H
#define _OPENCOG_COGSERVER_SCM_H

#include <thread>

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/server/CogServer.h>

namespace opencog
{

class CogServerSCM
{
private:
    static void* init_in_guile(void*);
    static void init_in_module(void*);
    void init(void);

    void start_server(const std::string&);
    void stop_server(void);

    CogServer* srvr = NULL;
    std::thread * main_loop = NULL;

public:
    CogServerSCM();
};

extern "C" {
void opencog_cogserver_init(void);
};

}
#endif // _OPENCOG_COGSERVER_SCM_H

// --------------------------------------------------------------

#include <opencog/util/Config.h>
#include <opencog/guile/SchemePrimitive.h>

/**
 * Implement a dynamically-loadable cogserver guile module.
 * This is mostly to allow a networked, agent-based system to run.
 *
 * This is a bare-bones implementation. Things like the server
 * port number, and maybe even the server atomspace, should be
 * configurable from guile, instead of the conf file.
 *
 * If/when python agents are supplanted by something newer, then
 * maybe this goes away.
 */

using namespace opencog;

CogServerSCM::CogServerSCM()
{
    static bool is_init = false;
    if (is_init) return;
    is_init = true;
    scm_with_guile(init_in_guile, this);
}

void* CogServerSCM::init_in_guile(void* self)
{
    scm_c_define_module("opencog cogserver", init_in_module, self);
    scm_c_use_module("opencog cogserver");
    return NULL;
}

void CogServerSCM::init_in_module(void* data)
{
    CogServerSCM* self = (CogServerSCM*) data;
    self->init();
}

/**
 * The main init function for the CogServerSCM object.
 */
void CogServerSCM::init()
{
    define_scheme_primitive("c-start-cogserver", &CogServerSCM::start_server, this, "cogserver");
    define_scheme_primitive("stop-cogserver", &CogServerSCM::stop_server, this, "cogserver");
}

extern "C" {
void opencog_cogserver_init(void)
{
    static CogServerSCM cogserver;
}
};

// --------------------------------------------------------------

void CogServerSCM::start_server(const std::string& cfg)
{
    // singleton instance
    if (srvr) return;

    // The default config file is installed from
    // $SRCDIR/lib/cogserver.conf and is copied to
    // /usr/local/etc/cogservedr.conf
    // by default. Use it if we can; it has sane file paths in it.
    if (0 < cfg.size())
        config().load(cfg.c_str(), true);
    else
        config().load("cogserver.conf", true);

    srvr = &cogserver();

    // Open database *before* loading modules, since the modules
    // might create atoms, and we can't have that happen until
    // storage is open, as otherwise, there will be handle conflicts.
    srvr->openDatabase();

    // Load modules specified in config
    srvr->loadModules();
    srvr->loadSCMModules();

    // Enable the network server and run the server's main loop
    srvr->enableNetworkServer();
    main_loop = new std::thread(&CogServer::serverLoop, srvr);
}

void CogServerSCM::stop_server(void)
{
    // delete singleton instance
    if (NULL == srvr) return;

    // This is probably not thread-safe...
    srvr->stop();
    main_loop->join();

    // I suspect this does not close the listen socket correctly.
    // XXX this all needs to be fixed.
    srvr->disableNetworkServer();
    delete main_loop;
    delete srvr;
    srvr = NULL;
}
<|endoftext|>


<commit_before>#include "JobManager.h"

#include <vector>
#include <mutex>

#include <thread>
#include <algorithm>
#include <cassert>

#include "Job.h"

#if _WIN32 || _WIN64
#include <immintrin.h>
#define YIELD_COMMAND _mm_pause();
#else
static_assert(0 && "YIELD COMMAND Not Specified For Platform")
#endif

// based on the job system detailed at molecular musings: https://blog.molecular-matters.com/2015/08/24/job-system-2-0-lock-free-work-stealing-part-1-basics/

constexpr unsigned int NUMBER_OF_JOBS{ 4096 };
constexpr unsigned int NUMBER_OF_JOBS_MASK{ 4096 - 1 };
constexpr unsigned int MAX_NUMBER_OF_QUEUES{ 8 };

bool g_runJobs { true };
std::condition_variable g_hasJobsConditionVariable{};

struct VeritasEngine::JobManager::WorkQueue
{
	void Push(Job* job)
	{
		auto b = m_bottom.load(std::memory_order_acquire);
		m_jobs[b & NUMBER_OF_JOBS_MASK] = job;
		m_bottom.store(b + 1, std::memory_order_release);
	}

	Job* Pop()
	{
		auto b = m_bottom.load(std::memory_order_acquire) - 1;
		m_bottom.exchange(b, std::memory_order_release);

		auto t = m_top.load();
		if(t <= b)
		{
			auto job = m_jobs[b & NUMBER_OF_JOBS_MASK];

			if(t != b)
			{
				return job;
			}

			if(!m_top.compare_exchange_strong(t, t+1))
			{
				job = nullptr;
			}

			m_bottom = t + 1;
			return job;
		}
		else
		{
			m_bottom = t;
			return nullptr;
		}
	}

	Job* Steal()
	{
		auto t = m_top.load(std::memory_order_acquire);
		auto b = m_bottom.load(std::memory_order_acquire);
		if(t < b)
		{
			const auto job = m_jobs[t & NUMBER_OF_JOBS_MASK];

			if(!m_top.compare_exchange_strong(t, t+1))
			{
				return nullptr;
			}

			return job;
		}
		else
		{
			return nullptr;
		}
	}

private:
	Job* m_jobs[NUMBER_OF_JOBS];
	std::atomic_long m_bottom{ 0 };
	std::atomic_long m_top{ 0 };

};

struct VeritasEngine::JobManager::Impl
{
	Impl()
	: m_queueCount{ std::min(std::thread::hardware_concurrency(), MAX_NUMBER_OF_QUEUES) }
	{
		static_assert(std::atomic_int32_t::is_always_lock_free == true && "Platform is not lock free");
	}

	void Init()
	{
		m_queueIndex = 0;

		m_workerThreads.reserve(m_queueCount - 1);

		for (unsigned i = 1; i < m_queueCount; i++)
		{
			m_workerThreads.emplace_back(ThreadMain, this, i);
		}
	}

	~Impl()
	{
		g_runJobs = false;
		g_hasJobsConditionVariable.notify_all();

		for(auto& t : m_workerThreads)
		{
			if (t.joinable())
			{
				t.join();
			}
		}

		m_workerThreads.clear();
	}

	void Push(Job* job)
	{
		GetQueue().Push(job);
		++m_activeJobCount;
		g_hasJobsConditionVariable.notify_all();
	}

	Job* AllocateJob()
	{
		const auto index = m_allocatedJobs++;
		return &m_jobs[index & NUMBER_OF_JOBS_MASK];
	}

	WorkQueue& GetQueue()
	{
		return m_queues[m_queueIndex];
	}

	void ExecuteJob(Job* job)
	{
		(job->Callback)(job, job->Data);
		FinishJob(job);
	}

	Job* GetJob()
	{
		auto& queue = GetQueue();

		const auto job = queue.Pop();
		if (job == nullptr)
		{
			auto& otherQueue = m_queues[0];

			if (&queue == &otherQueue)
			{
				Yield();
				return nullptr;
			}

			Job* stolenJob = otherQueue.Steal();

			if (stolenJob)
			{
				return stolenJob;
			}

			auto& randomQueue = m_queues[rand() % m_queueCount];

			if (&queue == &randomQueue)
			{
				Yield();
				return nullptr;
			}

			stolenJob = randomQueue.Steal();

			if (stolenJob == nullptr)
			{
				Yield();
				return nullptr;
			}

			return stolenJob;
		}
		return job;
	}

private:
	void FinishJob(Job* job)
	{
		const auto jobCount = --job->UnfinishedJobs;

		if (jobCount == 0 && (job->Parent))
		{
			FinishJob(job->Parent);
		}

		--m_activeJobCount;
	}

	static void Yield()
	{
		YIELD_COMMAND
	}

	static void ThreadMain(Impl* impl, const unsigned int queueIndex)
	{
		m_queueIndex = queueIndex;

		std::unique_lock<std::mutex> lock{ m_threadMainMutex };

		while (g_runJobs)
		{
			g_hasJobsConditionVariable.wait(lock, [&] { return impl->m_activeJobCount > 0 || !g_runJobs; });

			// double check if we need to run jobs since we may be trying to shut down the engine
			if (g_runJobs)
			{
				const auto job = impl->GetJob();
				if (job != nullptr)
				{
					impl->ExecuteJob(job);
				}
			}
		}
	}

	static thread_local unsigned int m_queueIndex;
	static thread_local unsigned int m_allocatedJobs;
	static thread_local std::mutex m_threadMainMutex;
	static thread_local Job m_jobs[NUMBER_OF_JOBS];

	unsigned int m_queueCount;
	std::atomic_int32_t m_activeJobCount{ 0 };
	WorkQueue m_queues[MAX_NUMBER_OF_QUEUES];
	std::vector<std::thread> m_workerThreads{};
};

thread_local unsigned int VeritasEngine::JobManager::Impl::m_queueIndex;
thread_local unsigned int VeritasEngine::JobManager::Impl::m_allocatedJobs { 0 };
thread_local std::mutex VeritasEngine::JobManager::Impl::m_threadMainMutex{};
thread_local VeritasEngine::Job VeritasEngine::JobManager::Impl::m_jobs[NUMBER_OF_JOBS];

VeritasEngine::JobManager::JobManager()
	: m_impl{std::make_unique<Impl>() }
{

}

VeritasEngine::JobManager::JobManager(JobManager&& other) noexcept
	: m_impl{ std::move(other.m_impl) }
{

}

void VeritasEngine::JobManager::Init()
{
	m_impl->Init();
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJob(JobFunction&& function)
{
	return CreateJob(std::move(function), nullptr, 0);
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJob(JobFunction&& function, void* data, const size_t sizeOfData)
{
	assert(sizeOfData < sizeof(Job::Data));

	auto job = m_impl->AllocateJob();
	job->Callback = std::move(function);
	job->Parent = nullptr;
	job->UnfinishedJobs = 1;

	if (data)
	{
		std::memcpy(job->Data, data, sizeOfData);
	}

	return job;
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJobAsChild(Job* parent, JobFunction&& jobFunction)
{
	return CreateJobAsChild(parent, std::move(jobFunction), nullptr, 0);
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJobAsChild(Job* parent, JobFunction&& jobFunction, void* data, const size_t sizeOfData)
{
	++parent->UnfinishedJobs;

	auto job = m_impl->AllocateJob();
	job->Callback = std::move(jobFunction);
	job->Parent = parent;
	job->UnfinishedJobs = 1;

	if (data)
	{
		std::memcpy(job->Data, data, sizeOfData);
	}

	return job;
}

void VeritasEngine::JobManager::Run(Job* job)
{
	m_impl->Push(job);
}

void VeritasEngine::JobManager::Wait(Job* job)
{
	while(job->UnfinishedJobs > 0)
	{
		const auto nextJob = m_impl->GetJob();

		if(nextJob != nullptr)
		{
			m_impl->ExecuteJob(nextJob);
		}
	}
}

VeritasEngine::JobManager& VeritasEngine::JobManager::operator=(JobManager&& other) noexcept
{
	if(this != &other)
	{
		this->m_impl = std::move(other.m_impl);
	}

	return *this;
}
<commit_msg>changing to use relaxed with atomic_fences<commit_after>#include "JobManager.h"

#include <vector>
#include <mutex>

#include <thread>
#include <algorithm>
#include <cassert>

#include "Job.h"

#if _WIN32 || _WIN64
#include <immintrin.h>
#define YIELD_COMMAND _mm_pause();
#else
static_assert(0 && "YIELD COMMAND Not Specified For Platform")
#endif

// based on the job system detailed at molecular musings: https://blog.molecular-matters.com/2015/08/24/job-system-2-0-lock-free-work-stealing-part-1-basics/

constexpr unsigned int NUMBER_OF_JOBS{ 4096 };
constexpr unsigned int NUMBER_OF_JOBS_MASK{ 4096 - 1 };
constexpr unsigned int MAX_NUMBER_OF_QUEUES{ 8 };

bool g_runJobs { true };
std::condition_variable g_hasJobsConditionVariable{};

struct VeritasEngine::JobManager::WorkQueue
{
	void Push(Job* job)
	{
		auto b = m_bottom.load(std::memory_order_relaxed);
		m_jobs[b & NUMBER_OF_JOBS_MASK] = job;

		std::atomic_thread_fence(std::memory_order_acquire);

		m_bottom.store(b + 1, std::memory_order_relaxed);
	}

	Job* Pop()
	{
		auto b = m_bottom.load(std::memory_order_relaxed) - 1;
		m_bottom.exchange(b, std::memory_order_relaxed);

		auto t = m_top.load(std::memory_order_relaxed);
		if(t <= b)
		{
			auto job = m_jobs[b & NUMBER_OF_JOBS_MASK];

			if(t != b)
			{
				return job;
			}

			if(!m_top.compare_exchange_strong(t, t+1, std::memory_order_release))
			{
				job = nullptr;
			}

			m_bottom = t + 1;
			return job;
		}
		else
		{
			m_bottom = t;
			return nullptr;
		}
	}

	Job* Steal()
	{
		auto t = m_top.load(std::memory_order_relaxed);

		std::atomic_thread_fence(std::memory_order_acquire);

		auto b = m_bottom.load(std::memory_order_relaxed);
		if(t < b)
		{
			const auto job = m_jobs[t & NUMBER_OF_JOBS_MASK];

			if(!m_top.compare_exchange_strong(t, t+1, std::memory_order_release))
			{
				return nullptr;
			}

			return job;
		}
		else
		{
			return nullptr;
		}
	}

private:
	Job* m_jobs[NUMBER_OF_JOBS];
	std::atomic_long m_bottom{ 0 };
	std::atomic_long m_top{ 0 };

};

struct VeritasEngine::JobManager::Impl
{
	Impl()
	: m_queueCount{ std::min(std::thread::hardware_concurrency(), MAX_NUMBER_OF_QUEUES) }
	{
		static_assert(std::atomic_int32_t::is_always_lock_free == true && "Platform is not lock free");
	}

	void Init()
	{
		m_queueIndex = 0;

		m_workerThreads.reserve(m_queueCount - 1);

		for (unsigned i = 1; i < m_queueCount; i++)
		{
			m_workerThreads.emplace_back(ThreadMain, this, i);
		}
	}

	~Impl()
	{
		g_runJobs = false;
		g_hasJobsConditionVariable.notify_all();

		for(auto& t : m_workerThreads)
		{
			if (t.joinable())
			{
				t.join();
			}
		}

		m_workerThreads.clear();
	}

	void Push(Job* job)
	{
		GetQueue().Push(job);
		++m_activeJobCount;
		g_hasJobsConditionVariable.notify_all();
	}

	Job* AllocateJob()
	{
		const auto index = m_allocatedJobs++;
		return &m_jobs[index & NUMBER_OF_JOBS_MASK];
	}

	WorkQueue& GetQueue()
	{
		return m_queues[m_queueIndex];
	}

	void ExecuteJob(Job* job)
	{
		(job->Callback)(job, job->Data);
		FinishJob(job);
	}

	Job* GetJob()
	{
		auto& queue = GetQueue();

		const auto job = queue.Pop();
		if (job == nullptr)
		{
			auto& otherQueue = m_queues[0];

			if (&queue == &otherQueue)
			{
				Yield();
				return nullptr;
			}

			Job* stolenJob = otherQueue.Steal();

			if (stolenJob)
			{
				return stolenJob;
			}

			auto& randomQueue = m_queues[rand() % m_queueCount];

			if (&queue == &randomQueue)
			{
				Yield();
				return nullptr;
			}

			stolenJob = randomQueue.Steal();

			if (stolenJob == nullptr)
			{
				Yield();
				return nullptr;
			}

			return stolenJob;
		}
		return job;
	}

private:
	void FinishJob(Job* job)
	{
		const auto jobCount = --job->UnfinishedJobs;

		if (jobCount == 0 && (job->Parent))
		{
			FinishJob(job->Parent);
		}

		--m_activeJobCount;
	}

	static void Yield()
	{
		YIELD_COMMAND
	}

	static void ThreadMain(Impl* impl, const unsigned int queueIndex)
	{
		m_queueIndex = queueIndex;

		std::unique_lock<std::mutex> lock{ m_threadMainMutex };

		while (g_runJobs)
		{
			g_hasJobsConditionVariable.wait(lock, [&] { return impl->m_activeJobCount > 0 || !g_runJobs; });

			// double check if we need to run jobs since we may be trying to shut down the engine
			if (g_runJobs)
			{
				const auto job = impl->GetJob();
				if (job != nullptr)
				{
					impl->ExecuteJob(job);
				}
			}
		}
	}

	static thread_local unsigned int m_queueIndex;
	static thread_local unsigned int m_allocatedJobs;
	static thread_local std::mutex m_threadMainMutex;
	static thread_local Job m_jobs[NUMBER_OF_JOBS];

	unsigned int m_queueCount;
	std::atomic_int32_t m_activeJobCount{ 0 };
	WorkQueue m_queues[MAX_NUMBER_OF_QUEUES];
	std::vector<std::thread> m_workerThreads{};
};

thread_local unsigned int VeritasEngine::JobManager::Impl::m_queueIndex;
thread_local unsigned int VeritasEngine::JobManager::Impl::m_allocatedJobs { 0 };
thread_local std::mutex VeritasEngine::JobManager::Impl::m_threadMainMutex{};
thread_local VeritasEngine::Job VeritasEngine::JobManager::Impl::m_jobs[NUMBER_OF_JOBS];

VeritasEngine::JobManager::JobManager()
	: m_impl{std::make_unique<Impl>() }
{

}

VeritasEngine::JobManager::JobManager(JobManager&& other) noexcept
	: m_impl{ std::move(other.m_impl) }
{

}

void VeritasEngine::JobManager::Init()
{
	m_impl->Init();
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJob(JobFunction&& function)
{
	return CreateJob(std::move(function), nullptr, 0);
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJob(JobFunction&& function, void* data, const size_t sizeOfData)
{
	assert(sizeOfData < sizeof(Job::Data));

	auto job = m_impl->AllocateJob();
	job->Callback = std::move(function);
	job->Parent = nullptr;
	job->UnfinishedJobs = 1;

	if (data)
	{
		std::memcpy(job->Data, data, sizeOfData);
	}

	return job;
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJobAsChild(Job* parent, JobFunction&& jobFunction)
{
	return CreateJobAsChild(parent, std::move(jobFunction), nullptr, 0);
}

VeritasEngine::Job* VeritasEngine::JobManager::CreateJobAsChild(Job* parent, JobFunction&& jobFunction, void* data, const size_t sizeOfData)
{
	++parent->UnfinishedJobs;

	auto job = m_impl->AllocateJob();
	job->Callback = std::move(jobFunction);
	job->Parent = parent;
	job->UnfinishedJobs = 1;

	if (data)
	{
		std::memcpy(job->Data, data, sizeOfData);
	}

	return job;
}

void VeritasEngine::JobManager::Run(Job* job)
{
	m_impl->Push(job);
}

void VeritasEngine::JobManager::Wait(Job* job)
{
	while(job->UnfinishedJobs > 0)
	{
		const auto nextJob = m_impl->GetJob();

		if(nextJob != nullptr)
		{
			m_impl->ExecuteJob(nextJob);
		}
	}
}

VeritasEngine::JobManager& VeritasEngine::JobManager::operator=(JobManager&& other) noexcept
{
	if(this != &other)
	{
		this->m_impl = std::move(other.m_impl);
	}

	return *this;
}
<|endoftext|>


<commit_before>#include "pidomus_lambdas.h"
#include "pidomus.h"
#include "pidomus_macros.h"

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::Lambdas ()
{}

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::
Lambdas (piDoMUS<dim,spacedim,LAC> &simulator_object)
  :
  simulator (&simulator_object)
{}

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::~Lambdas ()
{}

template <int dim, int spacedim, typename LAC>
void
Lambdas<dim,spacedim,LAC>::
initialize_simulator (piDoMUS<dim,spacedim,LAC> &simulator_object)
{
  simulator = &simulator_object;
}

template <int dim, int spacedim, typename LAC>
void
Lambdas<dim,spacedim,LAC>::
set_functions_to_default()
{
  create_new_vector = [this]() ->shared_ptr<typename LAC::VectorType>
  {
    return this->simulator->create_new_vector();
  };

  residual = [this](const double t,
                    const typename LAC::VectorType &y,
                    const typename LAC::VectorType &y_dot,
                    typename LAC::VectorType &residual) ->int
  {
    return this->simulator->residual(t,y,y_dot,residual);
  };

  setup_jacobian = [this](const double t,
                          const typename LAC::VectorType &y,
                          const typename LAC::VectorType &y_dot,
                          const double alpha) ->int
  {
    return this->simulator->setup_jacobian(t,y,y_dot,alpha);
  };

  solve_jacobian_system = [this](const typename LAC::VectorType &rhs,
                                 typename LAC::VectorType &dst) ->int
  {
    return this->simulator->solve_jacobian_system(rhs,dst);
  };

  output_step = [this](const double t,
                       const typename LAC::VectorType &y,
                       const typename LAC::VectorType &y_dot,
                       const unsigned int step_number)
  {
    this->simulator->output_step(t,y,y_dot,step_number);
  };

  solver_should_restart = [this](const double t,
                                 typename LAC::VectorType &y,
                                 typename LAC::VectorType &y_dot) ->bool
  {
    return this->simulator->solver_should_restart(t,y,y_dot);
  };

  differential_components = [this]() ->typename LAC::VectorType &
  {
    return this->simulator->differential_components();
  };

  get_local_tolerances = [this]() ->typename LAC::VectorType &
  {
    AssertThrow(false, ExcPureFunctionCalled("Please implement get_local_tolerances function."));
    static auto lt = this->create_new_vector();
    return *lt;
  };

  get_lumped_mass_matrix = [&]() ->typename LAC::VectorType &
  {
    static shared_ptr<typename LAC::VectorType> lm;
    lm = this->create_new_vector();
    this->simulator->get_lumped_mass_matrix(*lm);
    return *lm;
  };

  jacobian_vmult = [this](const typename LAC::VectorType &src,
                          typename LAC::VectorType &dst) ->int
  {
    return this->simulator->jacobian_vmult(src,dst);
  };

  vector_norm = [this](const typename LAC::VectorType &vector) ->double
  {
    return this->simulator->vector_norm(vector);
  };

}

#define INSTANTIATE(dim,spacedim,LAC) \
  template class Lambdas<dim,spacedim,LAC>;

PIDOMUS_INSTANTIATE(INSTANTIATE)
<commit_msg>fix adaptive refinement<commit_after>#include "pidomus_lambdas.h"
#include "pidomus.h"
#include "pidomus_macros.h"

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::Lambdas ()
{}

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::
Lambdas (piDoMUS<dim,spacedim,LAC> &simulator_object)
  :
  simulator (&simulator_object)
{}

template <int dim, int spacedim, typename LAC>
Lambdas<dim,spacedim,LAC>::~Lambdas ()
{}

template <int dim, int spacedim, typename LAC>
void
Lambdas<dim,spacedim,LAC>::
initialize_simulator (piDoMUS<dim,spacedim,LAC> &simulator_object)
{
  simulator = &simulator_object;
}

template <int dim, int spacedim, typename LAC>
void
Lambdas<dim,spacedim,LAC>::
set_functions_to_default()
{
  create_new_vector = [this]() ->shared_ptr<typename LAC::VectorType>
  {
    return this->simulator->create_new_vector();
  };

  residual = [this](const double t,
                    const typename LAC::VectorType &y,
                    const typename LAC::VectorType &y_dot,
                    typename LAC::VectorType &residual) ->int
  {
    int ret = this->simulator->residual(t,y,y_dot,residual);
    this->simulator->set_constrained_dofs_to_zero(residual);
    return ret;
  };

  setup_jacobian = [this](const double t,
                          const typename LAC::VectorType &y,
                          const typename LAC::VectorType &y_dot,
                          const double alpha) ->int
  {
    return this->simulator->setup_jacobian(t,y,y_dot,alpha);
  };

  solve_jacobian_system = [this](const typename LAC::VectorType &rhs,
                                 typename LAC::VectorType &dst) ->int
  {
    return this->simulator->solve_jacobian_system(rhs,dst);
  };

  output_step = [this](const double t,
                       const typename LAC::VectorType &y,
                       const typename LAC::VectorType &y_dot,
                       const unsigned int step_number)
  {
    this->simulator->output_step(t,y,y_dot,step_number);
  };

  solver_should_restart = [this](const double t,
                                 typename LAC::VectorType &y,
                                 typename LAC::VectorType &y_dot) ->bool
  {
    return this->simulator->solver_should_restart(t,y,y_dot);
  };

  differential_components = [this]() ->typename LAC::VectorType &
  {
    return this->simulator->differential_components();
  };

  get_local_tolerances = [this]() ->typename LAC::VectorType &
  {
    AssertThrow(false, ExcPureFunctionCalled("Please implement get_local_tolerances function."));
    static auto lt = this->create_new_vector();
    return *lt;
  };

  get_lumped_mass_matrix = [&]() ->typename LAC::VectorType &
  {
    static shared_ptr<typename LAC::VectorType> lm;
    lm = this->create_new_vector();
    this->simulator->get_lumped_mass_matrix(*lm);
    return *lm;
  };

  jacobian_vmult = [this](const typename LAC::VectorType &src,
                          typename LAC::VectorType &dst) ->int
  {
    return this->simulator->jacobian_vmult(src,dst);
  };

  vector_norm = [this](const typename LAC::VectorType &vector) ->double
  {
    return this->simulator->vector_norm(vector);
  };

}

#define INSTANTIATE(dim,spacedim,LAC) \
  template class Lambdas<dim,spacedim,LAC>;

PIDOMUS_INSTANTIATE(INSTANTIATE)
<|endoftext|>


<commit_before>#include "stdafx.h"

#include "LatLongElevation.h"
#include <curl/curl.h>
#include <cassert>
#include <sstream>

using std::ostringstream;

static const string MIKEDEM_BASE_URL("http://maverick.coas.oregonstate.edu:11300/terrainextraction.ashx?");

typedef struct {
	char* _data;
	size_t _size;
} CurlData;

size_t write_data(void *ptr, size_t size, size_t count, void *stream) {
	CurlData* curlData = (CurlData*)stream;
	char* buffer = new char[size*count];
	memcpy(buffer, ptr, size*count);
	size_t newSize = curlData->_size + size*count;
	char* newData = new char[newSize];
	if (curlData->_size != 0) {
		memcpy(newData, curlData->_data, curlData->_size);
	}
	memcpy(newData + curlData->_size, buffer, size*count);
	delete[] curlData->_data;
	curlData->_data = newData;
	curlData->_size = newSize;
	return size*count;
}

MikeDEM::MikeDEM(float lngMin, float lngMax, float latMin, float latMax,
	int numLngs, int numLats) : NUM_LNGS(numLngs), NUM_LATS(numLats),
	LNG_MIN(lngMin), LNG_MAX(lngMax), LAT_MIN(latMin), LAT_MAX(latMax)
{

	shared_ptr<CURL> curl(curl_easy_init(), [](CURL* c) {
		curl_easy_cleanup(c);
	});

	if (!curl) {
		throw CurlInitException("curl_easy_init failed");
	}

	CurlData curlData = {NULL, 0};

	auto queryString = createQueryString(MIKEDEM_BASE_URL);
	curl_easy_setopt(curl.get(), CURLOPT_URL, queryString.c_str());
	curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &curlData);
	curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, 1);

	CURLcode res = curl_easy_perform(curl.get());

	if (res != CURLE_OK) {
		throw CurlConnectionException(curl_easy_strerror(res));
	}

	initHeightWithXTR(curlData._data);
}

float MikeDEM::elevAt( float longtitude, float latitude ) {
	double latRange = LAT_MAX-LAT_MIN;
	double lngRange = LNG_MAX-LNG_MIN;
	int latI = (int)( ((latitude-LAT_MIN)/latRange)*((float)NUM_LATS-1.0)  );
	int lngI = (int)( ((longtitude-LNG_MIN)/lngRange)*((float)NUM_LNGS-1.0)  );
	return elevAtIndex(lngI, latI);
}

float MikeDEM::elevAtIndex(int lngI, int latI) {
	if (latI > NUM_LATS || lngI > NUM_LNGS || lngI < 0 || latI < 0 ) {
		throw out_of_range("invalid lat/long");
	}
	return elevationData->at(NUM_LNGS*latI + lngI);
}

string MikeDEM::createQueryString( const string& baseURL ) {
	ostringstream ss;
	ss << MIKEDEM_BASE_URL << "lat1=" << LAT_MIN << "&lat2=" << LAT_MAX <<
		"&lng1=" << LNG_MIN << "&lng2=" << LNG_MAX << "&numlngs=" << NUM_LNGS <<
		"&numlats=" << NUM_LATS;
	return string(ss.str());
}

void MikeDEM::initHeightWithXTR(char* data) {
	const char FORM_FEED =  0x0c;

	size_t iterator = 0;
	while (data[iterator++] != FORM_FEED) {

	}

// 	float minLng, maxLng, minLat, maxLat;
// 	int numLngs, numLats;
//
// 	memcpy(&minLng, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&maxLng, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&numLngs, data + iterator, sizeof(int));
// 	iterator = iterator + sizeof(int);
// 	memcpy(&minLat, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&maxLat, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&numLats, data + iterator, sizeof(int));
// 	iterator = iterator + sizeof(int);
//
// 	assert(numLngs == NUM_LNGS);
// 	assert(numLats == NUM_LATS);

	vector<float>* hVec = new vector<float>(NUM_LNGS * NUM_LATS, 0.0);

	for (int y = 0; y<NUM_LATS; y++) {
		memcpy( &((*hVec)[y*NUM_LNGS]), data + iterator, sizeof(float)*NUM_LNGS);
		iterator = iterator + sizeof(float)*NUM_LNGS;
	}

	elevationData.reset(hVec);
}
<commit_msg>improve performance with new realloc strategy<commit_after>#include "stdafx.h"

#include "LatLongElevation.h"
#include <curl/curl.h>
#include <cassert>
#include <sstream>

using std::ostringstream;

static const string MIKEDEM_BASE_URL("http://maverick.coas.oregonstate.edu:11300/terrainextraction.ashx?");

typedef struct {
	char* _data;
	size_t _size;
	size_t _capacity;
} CurlData;

size_t write_data(void *ptr, size_t size, size_t count, void *stream) {
	CurlData* curlData = (CurlData*)stream;

	size_t newSize = curlData->_size + size*count;
	if (newSize > curlData->_capacity) {
		size_t toBeAllocated = curlData->_capacity*2;;
		while (toBeAllocated < newSize) {
			toBeAllocated = toBeAllocated*2;
		}
		char* newData = new char[toBeAllocated];

		memcpy(newData, curlData->_data, curlData->_size);

		delete[] curlData->_data;
		curlData->_data = newData;
		curlData->_capacity = toBeAllocated;
	}

	memcpy(curlData->_data + curlData->_size, ptr, size*count);
	curlData->_size = newSize;
	return size*count;
}

MikeDEM::MikeDEM(float lngMin, float lngMax, float latMin, float latMax,
	int numLngs, int numLats) : NUM_LNGS(numLngs), NUM_LATS(numLats),
	LNG_MIN(lngMin), LNG_MAX(lngMax), LAT_MIN(latMin), LAT_MAX(latMax)
{

	shared_ptr<CURL> curl(curl_easy_init(), [](CURL* c) {
		curl_easy_cleanup(c);
	});

	if (!curl) {
		throw CurlInitException("curl_easy_init failed");
	}

	CurlData curlData = {NULL, 0};

	auto queryString = createQueryString(MIKEDEM_BASE_URL);
	curl_easy_setopt(curl.get(), CURLOPT_URL, queryString.c_str());
	curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L);
	curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &curlData);
	curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(curl.get(), CURLOPT_VERBOSE, 1);

	CURLcode res = curl_easy_perform(curl.get());

	if (res != CURLE_OK) {
		throw CurlConnectionException(curl_easy_strerror(res));
	}

	initHeightWithXTR(curlData._data);
}

float MikeDEM::elevAt( float longtitude, float latitude ) {
	double latRange = LAT_MAX-LAT_MIN;
	double lngRange = LNG_MAX-LNG_MIN;
	int latI = (int)( ((latitude-LAT_MIN)/latRange)*((float)NUM_LATS-1.0)  );
	int lngI = (int)( ((longtitude-LNG_MIN)/lngRange)*((float)NUM_LNGS-1.0)  );
	return elevAtIndex(lngI, latI);
}

float MikeDEM::elevAtIndex(int lngI, int latI) {
	if (latI > NUM_LATS || lngI > NUM_LNGS || lngI < 0 || latI < 0 ) {
		throw out_of_range("invalid lat/long");
	}
	return elevationData->at(NUM_LNGS*latI + lngI);
}

string MikeDEM::createQueryString( const string& baseURL ) {
	ostringstream ss;
	ss << MIKEDEM_BASE_URL << "lat1=" << LAT_MIN << "&lat2=" << LAT_MAX <<
		"&lng1=" << LNG_MIN << "&lng2=" << LNG_MAX << "&numlngs=" << NUM_LNGS <<
		"&numlats=" << NUM_LATS;
	return string(ss.str());
}

void MikeDEM::initHeightWithXTR(char* data) {
	const char FORM_FEED =  0x0c;

	size_t iterator = 0;
	while (data[iterator++] != FORM_FEED) {

	}

// 	float minLng, maxLng, minLat, maxLat;
// 	int numLngs, numLats;
//
// 	memcpy(&minLng, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&maxLng, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&numLngs, data + iterator, sizeof(int));
// 	iterator = iterator + sizeof(int);
// 	memcpy(&minLat, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&maxLat, data + iterator, sizeof(float));
// 	iterator = iterator + sizeof(float);
// 	memcpy(&numLats, data + iterator, sizeof(int));
// 	iterator = iterator + sizeof(int);
//
// 	assert(numLngs == NUM_LNGS);
// 	assert(numLats == NUM_LATS);

	vector<float>* hVec = new vector<float>(NUM_LNGS * NUM_LATS, 0.0);

	for (int y = 0; y<NUM_LATS; y++) {
		memcpy( &((*hVec)[y*NUM_LNGS]), data + iterator, sizeof(float)*NUM_LNGS);
		iterator = iterator + sizeof(float)*NUM_LNGS;
	}

	elevationData.reset(hVec);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: qualiname.cxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: np $ $Date: 2002-11-01 17:14:10 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <precomp.h>
#include <ary/qualiname.hxx>

// NOT FULLY DECLARED SERVICES

namespace ary
{

QualifiedName::QualifiedName( uintt i_nSize )
    :   aNamespace(),
        sLocalName(),
        bIsAbsolute(false),
        bIsFunction()
{
    if (i_nSize > 0)
        aNamespace.reserve(i_nSize);
}

QualifiedName::QualifiedName( const char *        i_sText,
                              const char *        i_sSeparator )
    :   aNamespace(),
        sLocalName(),
        bIsAbsolute(false),
        bIsFunction()
{
    AssignText(i_sText,i_sSeparator);
}

QualifiedName::~QualifiedName()
{
}

void
QualifiedName::AssignText(  const char *        i_sText,
                            const char *        i_sSeparator )
{
    csv_assert(NOT csv::no_str(i_sText) AND NOT csv::no_str(i_sSeparator));
    bIsAbsolute = false;
    bIsFunction = false;
    csv::erase_container( aNamespace );

    uintt nSepLen = strlen(i_sSeparator);
    const char * sNext = i_sText;

    const char * ps = strstr( i_sText, i_sSeparator );
    if (ps == i_sText)
    {
        bIsAbsolute = true;
        sNext = ps + nSepLen;
    }

    for ( ps = strstr(sNext, i_sSeparator);
          ps != 0;
          ps = strstr(sNext, i_sSeparator) )
    {
        String sPart(sNext, ps - sNext);
        aNamespace.push_back(sPart);
        sNext = ps + nSepLen;
    }

    uintt sNameLen = strlen(sNext);
    if ( sNameLen > 2 )
    {
        ps = sNext + sNameLen - 2;
        if (*ps == '(' AND *(ps+1) == ')')
        {
            sNameLen -= 2;
            bIsFunction = true;
        }
    }
    sLocalName = String(sNext,sNameLen);
}

}   // namespace ary
<commit_msg>INTEGRATION: CWS ooo19126 (1.1.132); FILE MERGED 2005/09/05 13:10:30 rt 1.1.132.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: qualiname.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 17:14:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <precomp.h>
#include <ary/qualiname.hxx>

// NOT FULLY DECLARED SERVICES

namespace ary
{

QualifiedName::QualifiedName( uintt i_nSize )
    :   aNamespace(),
        sLocalName(),
        bIsAbsolute(false),
        bIsFunction()
{
    if (i_nSize > 0)
        aNamespace.reserve(i_nSize);
}

QualifiedName::QualifiedName( const char *        i_sText,
                              const char *        i_sSeparator )
    :   aNamespace(),
        sLocalName(),
        bIsAbsolute(false),
        bIsFunction()
{
    AssignText(i_sText,i_sSeparator);
}

QualifiedName::~QualifiedName()
{
}

void
QualifiedName::AssignText(  const char *        i_sText,
                            const char *        i_sSeparator )
{
    csv_assert(NOT csv::no_str(i_sText) AND NOT csv::no_str(i_sSeparator));
    bIsAbsolute = false;
    bIsFunction = false;
    csv::erase_container( aNamespace );

    uintt nSepLen = strlen(i_sSeparator);
    const char * sNext = i_sText;

    const char * ps = strstr( i_sText, i_sSeparator );
    if (ps == i_sText)
    {
        bIsAbsolute = true;
        sNext = ps + nSepLen;
    }

    for ( ps = strstr(sNext, i_sSeparator);
          ps != 0;
          ps = strstr(sNext, i_sSeparator) )
    {
        String sPart(sNext, ps - sNext);
        aNamespace.push_back(sPart);
        sNext = ps + nSepLen;
    }

    uintt sNameLen = strlen(sNext);
    if ( sNameLen > 2 )
    {
        ps = sNext + sNameLen - 2;
        if (*ps == '(' AND *(ps+1) == ')')
        {
            sNameLen -= 2;
            bIsFunction = true;
        }
    }
    sLocalName = String(sNext,sNameLen);
}

}   // namespace ary
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _COMM_BAS_HXX
#define _COMM_BAS_HXX

#include <basic/sbxfac.hxx>
#include <basic/sbxvar.hxx>
#include <basic/sbxobj.hxx>

class CommunicationManagerClientViaSocket;
class CommunicationLink;

class CommunicationWrapper : public SbxObject   // Einer f�r Manager und Links
{
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( C50 ) || defined ( C52 )
public:
#endif
    typedef void( CommunicationWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, sal_Bool bWrite );
#if defined ( ICC )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        pMeth pFunc;            // Function Pointer
        short nArgs;            // Argumente und Flags
    };
    static Methods aManagerMethods[];   // Methodentabelle
    static Methods aLinkMethods[];      // Methodentabelle
    Methods *m_pMethods;    // Aktuelle Methodentabelle

    // Methoden
    //      Manager
    void MStartCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MStopAllCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MIsCommunicationRunning( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MGetMyName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MIsLinkValid( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MSetCommunicationEventHandler( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );

    //      Link
    void LStopCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetMyName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetHostName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LSend( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetString( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );

    // Interne Member und Methoden
    CommunicationManagerClientViaSocket *m_pManager;
    CommunicationLink *m_pLink;
    sal_Bool m_bIsManager;  // Ist es kein Manager, so ist es ein Link

    // Kram f�r Manager
    DECL_LINK( Open, CommunicationLink* );
    DECL_LINK( Close, CommunicationLink* );
    DECL_LINK( Data, CommunicationLink* );
    void Events( String aType, CommunicationLink* pLink );
    sal_Bool m_bCatchOpen;
    CommunicationLink *m_pNewLink;
    String m_aEventHandlerName;

    using SbxVariable::GetInfo;
    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    CommunicationWrapper( const String& );
    CommunicationWrapper( CommunicationLink *pThisLink );
    ~CommunicationWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );

    CommunicationLink* GetCommunicationLink() { return m_pLink; }
};

// Die dazugehoerige Factory:

class CommunicationFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Remove the C52 define.<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _COMM_BAS_HXX
#define _COMM_BAS_HXX

#include <basic/sbxfac.hxx>
#include <basic/sbxvar.hxx>
#include <basic/sbxobj.hxx>

class CommunicationManagerClientViaSocket;
class CommunicationLink;

class CommunicationWrapper : public SbxObject   // Einer f�r Manager und Links
{
    // Definition eines Tabelleneintrags. Dies wird hier gemacht,
    // da dadurch die Methoden und Properties als private deklariert
    // werden koennen.
#if defined ( ICC ) || defined ( C50 )
public:
#endif
    typedef void( CommunicationWrapper::*pMeth )
        ( SbxVariable* pThis, SbxArray* pArgs, sal_Bool bWrite );
#if defined ( ICC )
private:
#endif

    struct Methods {
        const char* pName;      // Name des Eintrags
        SbxDataType eType;      // Datentyp
        pMeth pFunc;            // Function Pointer
        short nArgs;            // Argumente und Flags
    };
    static Methods aManagerMethods[];   // Methodentabelle
    static Methods aLinkMethods[];      // Methodentabelle
    Methods *m_pMethods;    // Aktuelle Methodentabelle

    // Methoden
    //      Manager
    void MStartCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MStopAllCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MIsCommunicationRunning( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MGetMyName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MIsLinkValid( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void MSetCommunicationEventHandler( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );

    //      Link
    void LStopCommunication( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetMyName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetHostName( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LSend( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );
    void LGetString( SbxVariable* pVar, SbxArray* pPar, sal_Bool bWrite );

    // Interne Member und Methoden
    CommunicationManagerClientViaSocket *m_pManager;
    CommunicationLink *m_pLink;
    sal_Bool m_bIsManager;  // Ist es kein Manager, so ist es ein Link

    // Kram f�r Manager
    DECL_LINK( Open, CommunicationLink* );
    DECL_LINK( Close, CommunicationLink* );
    DECL_LINK( Data, CommunicationLink* );
    void Events( String aType, CommunicationLink* pLink );
    sal_Bool m_bCatchOpen;
    CommunicationLink *m_pNewLink;
    String m_aEventHandlerName;

    using SbxVariable::GetInfo;
    // Infoblock auffuellen
    SbxInfo* GetInfo( short nIdx );

    // Broadcaster Notification
    virtual void SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
                             const SfxHint& rHint, const TypeId& rHintType );
public:
    CommunicationWrapper( const String& );
    CommunicationWrapper( CommunicationLink *pThisLink );
    ~CommunicationWrapper();
    // Suchen eines Elements
    virtual SbxVariable* Find( const String&, SbxClassType );

    CommunicationLink* GetCommunicationLink() { return m_pLink; }
};

// Die dazugehoerige Factory:

class CommunicationFactory : public SbxFactory
{
public:
    virtual SbxObject* CreateObject( const String& );
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>